Skip to content

Commit

Permalink
Merge pull request #18 from raunakkumarsingh/Sphinx-documentation
Browse files Browse the repository at this point in the history
Update comments to Sphinx documentation format close #10
  • Loading branch information
Zhaoyilunnn authored Aug 5, 2024
2 parents 6675a98 + 58df6d2 commit fb360e6
Show file tree
Hide file tree
Showing 15 changed files with 542 additions and 74 deletions.
164 changes: 123 additions & 41 deletions qdao/circuit.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
"""
This module provides methods to partition original circuit
into sub-circuits.
Quantum Circuit Module
===================================
This module provides methods to partition original circuit into sub-circuits.
Classes:
QdaoCircuit: A wrapper for quantum circuits with associated real qubits.
BasePartitioner: Abstract base class for circuit partitioning.
BaselinePartitioner: Implements a naive circuit partitioning approach.
StaticPartitioner: Partitioner that traverses operations in their original order.
DependencyMatrix: Assists the UniQ partitioning algorithm.
UniQPartitioner: Partitioner using the UniQ algorithm.
PartitionerProvider: Provides partitioner instances based on configuration.
CircuitHelperProvider: Provides circuit helper instances based on backend.
"""

import logging
Expand All @@ -11,25 +24,42 @@


class QdaoCircuit:
"""
A class to represent a quantum circuit along with its real qubits.
Attributes:
circ (Any): The underlying quantum circuit object.
real_qubits (List[int]): List of real qubits associated with the circuit.
"""
def __init__(self, circ: Any, real_qubits: List[int]) -> None:
self._circ = circ
self._real_qubits = real_qubits

@property
def circ(self) -> Any:
"""Gets the underlying quantum circuit."""
return self._circ

@circ.setter
def circ(self, circ: Any):
"""Sets the underlying quantum circuit."""
self._circ = circ

@property
def real_qubits(self) -> List[int]:
"""Gets the list of real qubits."""
return self._real_qubits


class BasePartitioner:
"""Base class of circuit partition"""
"""
Base class for circuit partitioning.
Attributes:
np (int): Number of primary qubits.
nl (int): Number of local qubits.
backend (str): The backend used for the partitioning process.
"""

def __init__(self, np=4, nl=2, backend="qiskit") -> None:
self._np = np
Expand All @@ -38,30 +68,52 @@ def __init__(self, np=4, nl=2, backend="qiskit") -> None:

@property
def np(self):
"""Gets the number of primary qubits."""
return self._np

@np.setter
def np(self, n):
"""Sets the number of primary qubits."""
self._np = n

@property
def nl(self):
"""Sets the number of local qubits."""
return self._nl

@nl.setter
def nl(self, n):
"""Sets the number of local qubits."""
self._nl = n

def run(self, circuit: Any) -> List[QdaoCircuit]:
"""
Partitions the given circuit into sub-circuits.
Args:
circuit (Any): The quantum circuit to be partitioned.
Returns:
List[QdaoCircuit]: A list of partitioned sub-circuits.
"""
sub_circs = []

return sub_circs


class BaselinePartitioner(BasePartitioner):
"""This mimic the naive implementation"""
"""A naive implementation of circuit partitioning."""

def run(self, circuit: Any) -> List[QdaoCircuit]:
"""
Runs the baseline partitioning algorithm on the given circuit.
Args:
circuit (Any): The quantum circuit to be partitioned.
Returns:
List[QdaoCircuit]: A list of partitioned sub-circuits.
"""
# Set cicuit of circuit helper
self._circ_helper.circ = circuit

Expand All @@ -77,9 +129,18 @@ def run(self, circuit: Any) -> List[QdaoCircuit]:


class StaticPartitioner(BasePartitioner):
"""Static partitioner which traverse the operations in original order"""
"""Static Partitioner that traverses operations in the original order."""

def run(self, circuit: Any) -> List[QdaoCircuit]:
"""
Runs the static partitioning algorithm on the given circuit.
Args:
circuit (Any): The quantum circuit to be partitioned.
Returns:
List[QdaoCircuit]: A list of partitioned sub-circuits.
"""
# Set cicuit of circuit helper
self._circ_helper.circ = circuit

Expand Down Expand Up @@ -116,50 +177,51 @@ def run(self, circuit: Any) -> List[QdaoCircuit]:
class DependencyMatrix:
"""To assist the Uniq partitioning algorithm
A two-dimensional matrix is ​used to obtain the dependency between quantum
gates using a dynamic programming method, and based on this dependence,
a sub-circuit containing the most quantum gates that meets the requirements
is generated.We define op[i][j] as putting all operators that include qubit
j in the first i quantum gate and their dependencies into the same group.
Attributes:
gate_num: An integer holding the number of quantum gates contained in the quantum
circuit
qubit_num: An integer holding the number of qubits acted upon by the quantum circuit
result_bit: the set of all operators
result_op: the set of target a-bits
A two-dimensional matrix is used to analyze the dependencies between quantum
gates using a dynamic programming method. Based on these dependencies, a sub-circuit
containing the maximum number of quantum gates that meet the specified requirements is generated.
We define `op[i][j]` as the process of grouping all operators that involve qubit `j`
are dependent on the first `i` quantum gates.
Attributes:
gate_num (int): Number of quantum gates in the circuit.
qubit_num (int): Number of qubits in the circuit.
result_bit (list): A 2D list storing qubit dependencies.
result_op (list): A 2D list storing operator dependencies.
"""

def __init__(
self,
qubit_num: int,
gate_num: int,
) -> None:
"""Dependency matrix class constructor
"""Dependency matrix class constructorInitializes the dependency matrix.
Instantiate a dependency matrix class based on the given number of qubits and
quantum gates
Arg:
a:An integer representing the number of qubits
b:An integer representing the number of quantum gates
Args:
qubit_num (int): Number of qubits in the circuit.
gate_num (int): Number of quantum gates in the circuit.
"""
self.gate_num = gate_num
self.qubit_num = qubit_num

def preprocessing_single_quantum_circuits(self, gate_index: int, gate_target: any):
"""Process a single quantum gate, adding it to the dependency matrix
"""
Process a single quantum gate, adding it to the dependency matrix.
Fill in the row of dependency matrix corresponding to the quantum gate.
For the qubit that the quantum gate acts on, combine the quantum gate sets
of all target bits in the previous row and add them to the current quantum
gate and put them into the dependency matrix. And record the qubits these q
uantum gates act on.
Fill in the row of the dependency matrix corresponding to the quantum gate.
For the qubit that the quantum gate acts on, combine the quantum gate sets
of all target bits in the previous row, add them to the current quantum gate,
and put them into the dependency matrix. Record the qubits that these quantum
gates act on.
Arg:
gate_index: An integer representing the index of the quantum gate being processed
gate_target: An integer or list representing the qubits that the quantum gate acts on
"""
Args:
gate_index (int): An integer representing the index of the quantum gate being processed.
gate_target (int or list): An integer or list representing the qubits that the quantum gate acts on.
"""
if isinstance(gate_target, int):
gate_target = [gate_target]
for j in range(self.qubit_num):
Expand All @@ -178,13 +240,12 @@ def preprocessing_single_quantum_circuits(self, gate_index: int, gate_target: an
)

def preprocessing_quantum_circuits(self, ops: list):
"""Process all quantum gates, adding it to the dependency matrix
"""Processes all quantum gates and adds them to the dependency matrix.
Given a set of quantum gates, use the preprocessing_single_quantum_circuits function
to put them all into the dependency matrix
Arg:
ops:A list that stores the quantum gate sequence
Args:
ops (list): A list of quantum gate operations.
"""
self.result_bit = [
[[] for _ in range(self.qubit_num)] for _ in range(self.gate_num + 1)
Expand All @@ -206,12 +267,12 @@ def select_subcircuit(self, active_qubit_num: int) -> (List[int], int):
Returns a list containing the numbers of all quantum gates and the number
of qubits these quantum gates act on.
Arg:
active_qubit_num: An integer representing the required number of active qubits
Args:
active_qubit_num (int): The number of active qubits in the sub-circuit.
Return:
list[int]:
int:
Returns:
List[int]: A list of gate indices forming the sub-circuit.
int: The number of qubits in the sub-circuit.
"""
qubit_num_subcircuit = 0
gate_num_subcircuit = 0
Expand All @@ -229,13 +290,22 @@ def select_subcircuit(self, active_qubit_num: int) -> (List[int], int):


class UniQPartitioner(BasePartitioner):
"""Partitioner in UniQ
"""Partitioner using the UniQ algorithm.
References:
[1] https://ieeexplore.ieee.org/abstract/document/10045784/
"""

def run(self, circuit: Any) -> List[QdaoCircuit]:
"""
Runs the UniQ partitioning algorithm on the given circuit.
Args:
circuit (Any): The quantum circuit to be partitioned.
Returns:
List[QdaoCircuit]: A list of partitioned sub-circuits.
"""
self._circ_helper.circ = circuit
ops = []
ops += self._circ_helper.instructions
Expand Down Expand Up @@ -278,6 +348,9 @@ def run(self, circuit: Any) -> List[QdaoCircuit]:


class PartitionerProvider:
"""
Provides partitioner instances based on configuration.
"""
@classmethod
def get_partitioner(
cls,
Expand All @@ -290,4 +363,13 @@ def get_partitioner(
class CircuitHelperProvider:
@classmethod
def get_helper(cls, backend_name: str, **props):
"""
Returns a circuit helper instance based on the specified backend.
Args:
backend (str): The backend to use (e.g., 'qiskit', 'quafu').
Returns:
Any: An instance of a circuit helper.
"""
return INITIALIZERS[backend_name](**props)
41 changes: 39 additions & 2 deletions qdao/converters.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
"""Converters that convert np.array to statevector objects of other frameworks"""
"""
Converters that convert np.array to statevector objects of other frameworks.
Classes:
BaseConverter: Abstract base class for statevector converters.
QiskitConverter: Converts np.ndarray to Qiskit Statevector.
"""

import numpy as np
from qiskit.quantum_info.states import Statevector


class BaseConverter:
"""
Base class for statevector converters.
"""

def __init__(self) -> None:
"""
Initializes the BaseConverter.
"""
pass

def convert(self):
"""
Abstract method to convert statevectors.
This method should be implemented by subclasses.
"""
pass


class QiskitConverter(BaseConverter):
"""
Converts np.ndarray to Qiskit Statevector.
Attributes:
sv (np.ndarray): The numpy array representing the statevector.
"""

def __init__(self, sv: np.ndarray) -> None:
"""
Initializes the QiskitConverter with a statevector.
Args:
sv (np.ndarray): The numpy array representing the statevector.
"""
super().__init__()
self._sv = sv

def convert(self):
def convert(self) -> Statevector:
"""
Converts the numpy array to a Qiskit Statevector.
Returns:
Statevector: The Qiskit Statevector object.
"""
return Statevector(self._sv)
Loading

0 comments on commit fb360e6

Please sign in to comment.