QPanda3  0.1.0
Supported by OriginQ
Loading...
Searching...
No Matches
Changelog of QPanda3 v0.1.0

QGate

Prelude

In classical computing, the most fundamental unit is the bit, and the most basic control mode is the logic gate. We can achieve our circuit control objectives through the combination of logic gates. Similarly, the way to manipulate quantum bits is through quantum logic gates. QPanda3 offers a more concise and lightweight approach to constructing and using quantum logic gates.

Changes

  • Optimize space occupancy

    In pyqpanda, quantum logic gates store their own matrix form, which consumes a large amount of memory space for generating ultra large quantum circuits. pyqpanda3, the matrix of quantum circuits is obtained at runtime, effectively reducing memory space occupation

from pyqpanda3.core import *
h_gate= H(1)
# Retrieve matrix at runtime
matrix = h_gate.matrix()
Definition core.py:1

New Features

  • Simplify the construction and initialization process.

    In most scenarios, we only need to know the logic gate type and operation bit index to construct quantum logic gates, while in pyqpanda, we need to apply for bits in advance.

from pyqpanda import *
qvm = CPUQVM()
qvm.init_qvm()
qvm.set_configure(29, 29)
qubits = qvm.qAlloc_many(4)
cbits = qvm.cAlloc_many(4)
h_gate= H(qubits[0])
cnot_gate= CNOT(qubits[0], qubits[1])

In pyqpanda3, The process has been simplified.

from pyqpanda3.core import *
circuit = QCircuit(2)
circuit << H(0)
circuit << CNOT(0, 1)
circuit << RX(0, 3.9)
circuit << RX(0, 1.2)
circuit << RX(0, 5.6)
circuit << CP(0, 1, 4.9)
  • Storage and space optimization

    Compared with pyqpanda, pyqpanda3 optimizes the information storage of quantum logic gates, reduces memory usage, and can effectively reduce more than 70% of space for the construction of large quantum circuits

  • More diverse and concise development interfaces
    • Obtain quantum logic gate information and parameters
from pyqpanda3.core import *
h_gate= H(1)
# get quantum gate gate_type
gate_type = h_gate.gate_type()
# get quantum gate qubits
qubits = h_gate.qubits()
# get quantum gate parameters
parameters = h_gate.parameters()
# get quantum gate control_qubits
control_qubits = h_gate.control_qubits()
# get quantum gate qubits num
qubits_num = h_gate.qubits_num()
# get quantum gate matrix
matrix = h_gate.qubits()
# dagger
h_dag_gate = h_gate.dagger()
  • Simplified unnecessary quantum logic gate types.

pyqpanda has many quantum logic gates that are prone to misleading repetition. In the previous version, we supported the following types of logic gates

class GateType:
GATE_NOP
GATE_UNDEFINED
P0_GATE
P1_GATE
PAULI_X_GATE
PAULI_Y_GATE
PAULI_Z_GATE
X_HALF_PI
Y_HALF_PI
Z_HALF_PI
HADAMARD_GATE
T_GATE
S_GATE
P_GATE
CP_GATE
RX_GATE
RY_GATE
RZ_GATE
RXX_GATE
RYY_GATE
RZZ_GATE
RZX_GATE
U1_GATE
U2_GATE
U3_GATE
U4_GATE
CU_GATE
CNOT_GATE
CZ_GATE
MS_GATE
CPHASE_GATE
ISWAP_THETA_GATE
ISWAP_GATE
SQISWAP_GATE
SWAP_GATE
TWO_QUBIT_GATE
P00_GATE
P11_GATE
TOFFOLI_GATE
ORACLE_GATE
I_GATE
BARRIER_GATE
RPHI_GATE

pyqpanda3 has completed simplification and optimization

class GateType:
BARRIER
CNOT
CP
CU
CZ
GATE_NOP
GATE_UNDEFINED
H
I
ISWAP
MS
ORACLE
P
P0
P00
P1
P11
RPHI
RX
RXX
RY
RYY
RZ
RZX
RZZ
S
SQISWAP
SWAP
SX
T
TOFFOLI
U1
U2
U3
U4
X
X1
Y
Y1
Z
Z1

Circuit & QProg

Prelude

Quantum circuit and program is an important model in the field of quantum computing, used to describe and study the operation process of quantum algorithms and quantum computers. It is a graphical representation method used to demonstrate the operations and interactions between qubits, similar to circuit diagrams in classical computing.

Changes

  • The conversion between quantum programs and originir is more convenient and user-friendly`

    In pyqpanda, quantum programs and originir conversions are performed through independent external interfaces

from pyqpanda import *
if __name__ == "__main__":
machine = CPUQVM()
machine.init_qvm()
qlist = machine.qAlloc_many(4)
clist = machine.cAlloc_many(4)
prog = QProg()
prog_cir = QCircuit()
prog_cir << Y(qlist[2]) << H(qlist[2]) << CNOT(qlist[0],qlist[1])
prog << H(qlist[2]) << Measure(qlist[1],clist[1])
print(convert_qprog_to_originir(prog,machine))

In pyqpanda3, it is directly implemented through the member functions of quantum programs

from pyqpanda3 import *
from pyqpanda3.core import *
from pyqpanda3.compiler import *
if __name__ == "__main__":
originir_str = """
QINIT 3
CREG 2
H q[2]
H q[0]
H q[1]
CONTROL q[1]
RX q[2],(-3.141593)
ENDCONTROL
CONTROL q[0]
RX q[2],(-3.141593)
RX q[2],(-3.141593)
ENDCONTROL
DAGGER
H q[1]
// CR q[0],q[1],(1.570796)
H q[0]
ENDDAGGER
MEASURE q[0],c[0]
MEASURE q[1],c[1]
"""
prog = QProg(originir_str)

Example Usage:

# Import the QCircuit class
from pyqpanda3.core import *
# Create a quantum circuit with 2 qubits
circuit = QCircuit(2)
# Append gates to the circuit
circuit << H(0) # Apply Hadamard gate on qubit 0
circuit << CNOT(0,1) # Apply CNOT gate with control 0 and target 1
# Print circuit properties
print("Circuit Size:", circuit.size())
print("Qubits:", circuit.qubits())
print("Operations:", circuit.count_ops(False))
print("Circuit Depth:", circuit.depth(False))
from pyqpanda3.core import *
prog = QProg()
prog.append(H(0))
for i in range(1, 5):
prog.append(CNOT(i - 1, i))
for i in range(5):
prog.append(QMeasure(i, i))
print(draw_qprog(prog))
qvm = CPUQVM()
qvm.run(prog, 1024)
print(qvm.result().get_measure_probs())

New Features

  • Bottom level data structure optimization

In pyqpanda, we use linked lists to store internal quantum operation nodes. In PyQPanda3, we optimized this method by using sequential containers

Characteristics/Scenarios Quantum Program Sequential Container(std::vector) Quantum program linked list(std::list, std::forward_list)
Memory Layout Continuous memory allocation improves cache hit rate and access efficiency. Distributed memory allocation leads to low cache hit rates and slow access speeds.
Random access efficiency Support random access of O (1), such as QCircuit[i] Random access is not supported and needs to be traversed from scratch, with an access complexity of O (n).
Traverse performance Supports efficient traversal, with continuous memory allocation resulting in high traversal efficiency and a complexity of O (n). The traversal efficiency is low, memory allocation is decentralized, and pointer operations increase additional overhead.
Memory usage Additional space management capacity is required (such as during dynamic expansion), but the overall memory overhead is relatively small. Each node requires additional storage of pointers, resulting in high memory overhead.
Stability (pointer or reference) The insertion or deletion of elements may cause pointers or references to become invalid (such as ` std::) Vector will reallocate memory. Element insertion/deletion does not invalidate pointers or references to other elements.

Overall, quantum programs require traversal and space allocation, so using sequential containers can improve overall system efficiency

  • Enriched other member function interfaces
from pyqpanda3.core import *
from pyqpanda3.compiler import *
circuit = QCircuit(3)
circuit << H(0)
circuit << RY(1, 0.3)
circuit << RY(2, 2.7)
circuit << RX(0, 1.5)
circuit << CNOT(0, 1)
circuit << CNOT(1, 2)
prog = QProg()
# append nodes
prog.append(circuit)
# get size
size = prog.size()
# get depth
depth = prog.depth()
# get layers_of_operation
layers_of_operation = prog.layers_of_operation()
# get originir
originir = prog.originir()

Simulator

Prelude

Simulators are used to simulate the evolution process of quantum computing circuits, including quantum systems in perfect states and simulations with noise. In the latest QPanda3 version, there are currently six types of virtual machines supported, including full amplitude simulators, single amplitude simulators, density matrix simulators, Clifford circuit simulators, and simulations with noise. Compared to QPanda2, we have removed multiple redundant interfaces and used them in a more unified manner

New Features

  • Initialization process simplified.

    In the quantum simulator code of QPanda2, the application and release of qubits, the construction of quantum circuits, and the binding of the virtual machine are integrated together. For example:

from pyqpanda import *
qvm = CPUQVM()
qvm.init_qvm()
qvm.set_configure(29, 29)
qubits = qvm.qAlloc_many(4)
cbits = qvm.cAlloc_many(4)
prog = QProg()
prog << H(qubits[0]) << CNOT(qubits[0], qubits[1]) << Measure(qubits[0], cbits[0])

In pyqpanda3, complete decoupling has been achieved, and the explicit init configuration has been removed.

  • Removal of Global Virtual Machine Functions and Usage:
init(QMachineType.CPU)
auto qvm = init_quantum_machine(QMachineType.CPU)
qvm = CPUQVM()
  • Optimization of Noise Model Configuration and Usage.

The noise model is used to simulate the noise impact of real environments in quantum circuit computing tasks,In QPanda2, setting noise parameters required a complex noise model, and the noise model and noise errors are not decoupled.

from pyqpanda import *
noise = Noise()
noise.add_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.PAULI_X_GATE, 0.1)
qv0 = [q[0], q[1]]
noise.add_noise_model(NoiseModel.DEPHASING_KRAUS_OPERATOR, GateType.HADAMARD_GATE, 0.1, qv0)
qves = [[q[0], q[1]], [q[1], q[2]]]
noise.add_noise_model(NoiseModel.DAMPING_KRAUS_OPERATOR, GateType.CNOT_GATE, 0.1, qves)
f0 = 0.9
f1 = 0.85
noise.set_readout_error([[f0, 1 - f0], [1 - f1, f1]])
noise.set_rotation_error(0.05)

In pyqpanda3, noise errors and noise models are decoupledfugaile,Covering six commonly used noise models

pauli_error = pauli_x_error(0.6)
model = NoiseModel()
model.add_all_qubit_quantum_error(pauli_error,GateType.RX)
model.add_all_qubit_quantum_error(depolarizing_error(0.9),GateType.RX)
model.add_all_qubit_quantum_error(phase_damping_error(0.9),GateType.RX)
  • The interface for running simulator and obtaining results has been simplified. Refer to the code below for details.

    in qpanda3, first import modules

from pyqpanda3.Core import *
  • (1) Full Amplitue :The full amplitude and noise simulations in QPanda3 are merged into one simulator, which is run using a unified run function method, with the noise model as an optional parameter
from pyqpanda3.Core import *
circuit = QCircuit(3)
circuit << H(0)
circuit << RY(1, 0.3)
circuit << RY(2, 2.7)
circuit << RX(0, 1.5)
circuit << CNOT(0, 1)
circuit << CNOT(1, 2)
prog = QProg()
prog.append(circuit)
prog.append(QMeasure(0, 0))
prog.append(QMeasure(1, 1))
prog.append(QMeasure(2, 2))
model = NoiseModel()
model.add_all_qubit_quantum_error(pauli_x_error(0.5),GateType.RX)
machine = CPUQVM()
machine.run(prog, 1000, model)
measure_result = machine.result().get_counts()
print(measure_result)
  • Partial Amplitude
circuit = QCircuit(3)
circuit << H(0)
circuit << RY(1, 0.3)
circuit << RY(2, 2.7)
circuit << RX(0, 1.5)
circuit << CNOT(0, 1)
circuit << CNOT(1, 2)
prog = QProg()
prog.append(circuit)
machine = PartialAmplitudeQVM()
machine.run(prog)
measure_result = machine.get_state_vector(["0","1","2"])
print(measure_result)
  • DensityMatrixSimulator
circuit = QCircuit(2)
circuit << H(0)
circuit << CNOT(0, 1)
circuit << RX(0, 3.9)
circuit << RX(0, 1.2)
circuit << RX(0, 5.6)
circuit << CP(0, 1, 4.9)
prog = QProg()
prog.append(circuit)
machine = DensityMatrixSimulator()
machine.run(prog)
density_matrix = machine.density_matrix()
print(density_matrix)
pauli_error = pauli_x_error(0.6)
model = NoiseModel()
model.add_all_qubit_quantum_error(pauli_error,GateType.RX)
model.add_all_qubit_quantum_error(depolarizing_error(0.9),GateType.RX)
model.add_all_qubit_quantum_error(phase_damping_error(0.9),GateType.RX)
machine.run(prog, model)
density_matrix = machine.density_matrix()
print(density_matrix)
  • Stabilizer is used to simulate Clifford circuits, which only contain H, X, Y, Z, CNOT, S, CNOT, CZ quantum circuits. The maximum simulation can exceed 5000 quantum bits
prog = QProg()
prog.append(random_qcircuit([0,1,2,3,4,5 ], 20, ["H","X","Y","Z","S","CZ","CNOT","SWAP"]))
prog.append(QMeasure(0,0))
prog.append(QMeasure(1,1))
prog.append(QMeasure(2,2))
machine = Stabilizer()
machine.run(prog,1000)
measure_result = machine.result().get_counts()
print(measure_result)

Intermediate Compiler

Prelude

QPanda3 has optimized the implementation of quantum program translation. It has replaced the cross-language syntax parser Antlr4, used in QPanda2, with a line-by-line scanning method for quantum program translation, resulting in a fivefold improvement in overall execution efficiency.

Furthermore, QPanda3 supports the parsing of comments in quantum programs.

New Features

The intermediate compiler module provides an interface that supports converting an instruction set string in the OriginIR format into a quantum program (QProg).

prog = convert_originir_string_to_qprog(originir_str)

The intermediate compiler module provides an interface that supports converting a text file containing OriginIR instruction set string into a quantum program (QProg).

prog = convert_originir_file_to_qprog(originir_file_path)

The intermediate compiler module provides an interface that supports converting an instruction set string in OpenQASM format into a quantum program (QProg).

prog = convert_qasm_string_to_qprog(qasm_str)

The intermediate compiler module provides an interface that supports converting a text file containing OpenQASM instruction set string into a quantum program (QProg).

prog = convert_qasm_file_to_qprog(qasm_file_path)

The intermediate compiler module provides an interface that supports converting a quantum program (QProg) into an instruction set string in the OriginIR format.

convert_str = convert_qprog_to_originir(prog)

As can be seen, in the QPanda3 translation QProg interface definition, the parameter list eliminates the QuantumMachine type parameter used for conversion in the old version, and instead only uses the instruction set string or quantum program file path string as parameters to be converted. Additionally, the return value is no longer a list containing the QProg object, quantum bits, and classical bits, but is now solely the QProg object.

Hamiltonian

Prelude

As of the latest version, QPanda3 supports the use of qpanda2-style and qiskit-style parameter forms or PauliOperator objects to directly construct objects of the Hamiltonian class. Objects of the Hamiltonian class support addition, subtraction, scalar multiplication, multiplication, and tensor products, as well as mixed operations. They also support displaying the main information of the object by omitting the "I" or omitting the string of qubit indexes.

Changes

When constructing the Hamiltonian, it is no longer necessary to first construct the Pauli operator and then construct the Hamiltonian

H2 = Hamiltonian({"Z0 I1": 1})
Ham = Hamiltonian([("XXZ", [0, 1, 4], 1 + 2j), ("ZZ", [1, 2], -1 + 1j)] )

New Features

The Hamiltonian supports the direct construction of the Hamiltonian using the parameters of the constructed PauliOperator

H2 = Hamiltonian({"Z0 I1": 1})
Ham = Hamiltonian([("XXZ", [0, 1, 4], 1 + 2j), ("ZZ", [1, 2], -1 + 1j)] )

The Hamiltonian supports mixed operations of addition, subtraction, scalar multiplication, multiplication, and tensor product

H1 = Hamiltonian({"X0 Y1":1})
H2 = Hamiltonian({"X0 Y1": 2})
H3 = H1+H2
H1 = Hamiltonian({"X0 Y1":1})
H2 = Hamiltonian({"X0 Y1": 2})
H3 = H1-H2
H1 = Hamiltonian({"X0 Y1":1})
H2 = Hamiltonian({"X0 Y1": 2})
H3 = H1*H2
H1 = Hamiltonian({"X0 Y1":1})
H2 = Hamiltonian({"X0 Y1": 2})
H3 = H1+H2
H1 = Hamiltonian({"X0 Y1":1})
H3 = (3.3+1.j) * H1
H4 = H1*(4.4+1.j)
H1 = Hamiltonian({"X0 Y1":1})
H2 = Hamiltonian({"X0 Y1": 2})
H3 = H1.tensor(H2)

The Hamiltonian supports printing the corresponding string in the omitting "I" mode

Ham = Hamiltonian({"X0 Z1":2,"X1 Y2":3})
print("without I:\n",Ham)

Output

without I:
{ qbit_total = 3, pauli_with_coef_s = { 'X0 Z1 ':2 + 0j, 'X1 Y2 ':3 + 0j, } }

The Hamiltonian supports printing the corresponding string by omitting qbit index

Ha = Hamiltonian({"X0 Z1": 2, "X1 Y2": 3})
print("without I:\n", Ha)
print("with I:\n", Ha.str_with_I(True))

Output

without I:
{ qbit_total = 3, pauli_with_coef_s = { 'X0 Z1 ':2 + 0j, 'X1 Y2 ':3 + 0j, } }
with I:
{ qbit_totql = 3, paulis = [ 'IZX', 'YXI', ], coefs = [ 2 + 0j, 3 + 0j, ] }

Operator

Prelude

As of the latest version, QPanda3 supports the direct construction of PauliOperator objects using qpanda2-style and qiskit-style parameter forms. Objects of the PauliOperator class support addition, subtraction, scalar multiplication, multiplication, and tensor products, as well as mixed operations. They also support displaying the main information of the object by omitting the "I" or omitting the string of qubit indexes.

Changes

Use the PauliOperator class to provide unified simulation of the first mock examination for basic Pauli operators and Pauli operator combinations

op = PauliOperator("X")
op = PauliOperator("Y")
op = PauliOperator("Z")
op = PauliOperator("I")
H1 = PauliOperator({"X0 Y1":1})

New Features

PauliOperator support qsikit-style construction methods

# op means that "X0 X1 Z4" is applied to the quantum system with the coefficient 1+2.j, and "Z1 Z2" is applied to the quantum system with the coefficient -1+1.j
from pyqpanda3.hamiltonian import PauliOperator
op = PauliOperator([("XXZ", [0, 1, 4], 1 + 2j), ("ZZ", [1, 2], -1 + 1j)] )
Definition hamiltonian.py:1

PauliOperator support tensor product operations

H1 = PauliOperator({"X0 Y1":1})
H2 = PauliOperator({"X0 Y1":1})
H3 = H1.tensor(H2)

PauliOperator support scalar multiplication

H1 = PauliOperator({"X0 Y1":1})
H3 = (3.3+1.j) * H1

PauliOperator supports mixed operations of addition, subtraction, scalar multiplication, multiplication, and tensor product

PauliOperator supports printing the corresponding string by omitting "I"

PauliOperator supports printing corresponding strings by omitting qbit indexes

Ha = PauliOperator({"X0 Z1": 2, "X1 Y2": 3})
print("without I:\n", Ha)
print("with I:\n", Ha.str_with_I(True))

Output

without I:
{ qbit_total = 3, pauli_with_coef_s = { 'X0 Z1 ':2 + 0j, 'X1 Y2 ':3 + 0j, } }
with I:
{ qbit_totql = 3, paulis = [ 'IZX', 'YXI', ], coefs = [ 2 + 0j, 3 + 0j, ] }

Profiling Module

Prelude

The profiling module is designed to intuitively present information about quantum programs. It analyzes quantum programs using two methods and displays the results through visualizations for users.

Changes

  • None

New Features

  • draw_circuit_profile: This function analyzes quantum programs, outputting the execution time of the quantum program and its subroutine, as well as the calling relationships between various quantum gates. Its inputs include the quantum circuit, names of quantum gates, and their execution times on hardware, with the output being a flowchart of the calling relationships between the quantum gates.
  • draw_circuit_features: This function visualizes the features of a quantum circuit by generating a radar chart. It computes several metrics related to the circuit's structure and behavior, including connectivity, liveness, parallelism, entanglement, and critical depth, The meaning of specific features can be found in reference [1].

references

  1. Tomesh T, Gokhale P, Omole V, et al. Supermarq: A scalable quantum benchmark suite[C]//2022 IEEE International Symposium on High-Performance Computer Architecture (HPCA). IEEE, 2022: 587-603.

QCloudService

Prelude

In complex quantum circuit simulations, it is necessary to rely on high-performance computer clusters or real quantum computers to replace local computing with cloud computing, which to some extent reduces users' computing costs and provides a better computing experience. The Origin Quantum Cloud Platform submits tasks to quantum computers or computing clusters deployed remotely through the Origin South Service, and queries the processing results,

New Features

  • Origin Quantum Cloud Service Initialization process simplified.

    In the quantum cloud service code of QPanda2, the application and release of qubits, the construction of quantum circuits, and the binding of the virtual machine are integrated together.

For example, This is the usage method of pyqpanda, and the process is quite complicated

from pyqpanda import *
PI=3.14159
qm = QCloud()
qm.set_configure(72,72);
qm.init_qvm("302e020100301006072a86006052b8104001c041730502010424100b6d33ad8772eb9708494453a3c8a/16327",True)
q = qm.qAlloc_many(6)
c = qm.cAlloc_many(6)
prog = QProg()
prog << hadamard_circuit(q)\
<< RX(q[1], PI / 4)\
<< RX(q[2], PI / 4)\
<< RX(q[1], PI / 4)\
<< CZ(q[0], q[1])\
<< CZ(q[1], q[2])\
<< Measure(q[0], c[0])\
<< Measure(q[1], c[1])

In pyqpanda3, complete decoupling has been achieved, and the explicit init configuration has been removed.

from pyqpanda3.qcloud import *
prog = QProg()
prog << H(0)
prog << X(0)
prog << Y(0)
prog.append(QMeasure(0,0))
service = pq.QCloudService(api_key, test_url)
Definition qcloud.py:1
  • Unified Computing Interface

In QPanda2, different computing interfaces are independent.

result0 = QCM.full_amplitude_measure(measure_prog, 100)
print(result0)
result1 = QCM.full_amplitude_pmeasure(pmeasure_prog, [0, 1, 2])
print(result1)
result2 = QCM.partial_amplitude_pmeasure(pmeasure_prog, ["0", "1", "2"])
print(result2)
batch_prog = [prog for _ in range (6)]
real_chip_measure_batch_result = machine.batch_real_chip_measure(batch_prog, 1000, real_chip_type.origin_72)

In QPanda3, a unified approach is implemented using overloaded run functions.

At present, we support submission and query methods for cluster tasks such as full amplitude simulation, single amplitude simulation, partial amplitude simulation, and noisy simulation, as well as single and batch task submission and query for real quantum computing chip devices.

from pyqpanda3.qcloud import *
service = pq.QCloudService(api_key, test_url)
backend = service.backend("origin_wukong")
options = pq.QCloudOptions()
job = backend.run(prog, 1000, options)
result = job.result()
  • Optimized Synchronous and Asynchronous Processes

In QPanda2, synchronous and asynchronous methods are provided separately. QPanda3 simplifies this process.

Synchronous Process, job.result() will continuously loop through the task results until the task calculation is completed or there is an error

job = backend.run(prog, 1000)
result= job.result()
probs = result.get_probs()

Asynchronous method as above, Job.status() will query the current task status and return the query result

while True:
status = job.status()
if status == JobStatus.FINISHED:
break
sleep(5)
  • Added support for querying individual tasks, including the ability to query any historical task ID.
job = QCloudJob("A45DE13AA1920B115220C19BC0C0F4A5")
probs = job.result().get_probs()

QuantumInformation

Prelude

As of the latest version, QPanda3 supports the use of StateVector and DensityMatrix to represent two basic quantum state representations, namely state vector and density matrix. It supports the use of five forms of describing quantum channels, including Kraus, Choi, Chi, SuperOp, and PTM, as well as the conversion between these five representations. In addition, it also provides information analysis tools such as Hellinger distance, Hellinger fidelity, and KL divergence, as well as a dedicated class for obtaining the unitary matrix of the quantum circuit QCircuit, and a Matrix class that can obtain the transpose matrix, adjoint matrix, and L2 norm.

Changes

Compared to qpanda2, this module is a brand new module

New Features

Abstract and simulate quantum states, including state vectors and density matrices, and support the application of quantum circuits for evolution operations on quantum systems represented by state vectors and density matrices

# Construct a DensityMatrix object
dm = DensityMatrix(data)
# Construct a StateVector object
stv = StateVector([1+1.j,2+2.j,3+3.j,4+4.j,5+5.j,6+6.j,7+7.j,8+8.j])

The abstraction and simulation of the representation methods Kraus, Choi, PTM, SuperOp, and Chi in quantum channel 5 support the pairwise conversion between these representation methods, and support the use of these quantum channels for evolving quantum states

#Prepare a one-dimensional array consisting of a two-dimensional matrix
K0 = np.array([[0, 1], [1+0.j, 0]])
K1 = np.array([[1, 0], [0+0.j, -1]])
K2 = np.array([[0+0.j, -1.j], [1.j, 0]])
Ks1 = [K0, K1, K2]
# Constructing a Kraus object
Kra2 = Kraus(Ks1)
# Constructing a Choi object from a Kraus object
choi = Choi(Kra3)
# Constructing a Chi object from a Kraus object
chi = Chi(Kra3)
# Constructing a SuperOp object from a Kraus object
sop = SuperOp(Kra3)
# Constructing a PTM object from a Kraus object
ptm = PTM(Kra3)

Information analysis tools, including the calculation of Hellinger distance, Hellinger fidelity, and KL divergence between discrete probability distributions, including KL divergence between discrete probability distributions and KL divergence between continuous probability distributions

# Calculate the Hellinger distance for p distribution and q distribution
hd = hellinger_distance(p_prob,q_prob)
# Calculate the Hellinger fidelity for p distribution and q distribution
hd = hellinger_fidelity(p_prob,q_prob)
# Calculate KL divergence for p distribution's probability values and q distribution's probability values
kld = KL_divergence(p_prob_val,q_prob_val)

Others, including a matrix class and a class for obtaining the unitary matrix of the quantum circuit QCircuit object

data = np.array(data, dtype=complex)
# Constructing a Matrix object
m = Matrix(data)
# Obtain the unitary matrix of QCircuit
matrix = Unitary(cir)

Transpiler Module

Prelude

This module provides functionalities for compiling quantum circuits, enhancing optimization and mapping to specific hardware topologies.

Changes

  • None

New Features

  • A new Transpiler class has been added, which compiles circuits using the transpile() interface. This interface has four parameters: QProg, chip_topology_edges, init_mapping, and optimization_level. The QProg parameter is the quantum circuit to be compiled, chip_topology_edges is the target topology for compilation, init_mapping is the mapping of virtual qubits to physical qubits, and optimization_level can be set to 0, 1 or 2:
    • 0: No optimization is performed.
    • 1: Basic optimizations are applied, including simple two-qubit gate cancellation and single-qubit gate merging.
    • 2: Advanced optimizations are performed, including matrix optimization, two-qubit gate cancellation, and single-qubit gate merging.
  • The current compiled basic gate set is [X1, RZ, CZ]
  • In the future, InitPass, LayoutPass, RoutingPass, OptimizationPass, and TranslationPass will be gradually opened up, allowing users to freely combine these passes to customize the transpiler process.

Example Usage:

import pyqpanda3.core as pq
from pyqpanda3.transpilation import Transpiler
prog_1 = pq.QProg()
prog_1 << H(0) << RX(0, 1.25) << CNOT(0, 1) << U1(1, 0.0001) << CNOT(0, 1) << CNOT(1, 2)
for i in range(3):
prog_1.append(QMeasure(i, i))
print('prog: \n', draw_qprog(prog_1))
# Create topology structure
topo = generate_topology(20, "square")
transpiler = Transpiler()
prog_level_0 = transpiler.transpile(prog_1, topo, {}, 0)
prog_level_1 = transpiler.transpile(prog_1, topo, {}, 1)
prog_level_2 = transpiler.transpile(prog_1, topo, {}, 2)
print('Transpiler level 0: \n', draw_qprog(prog_level_0))
print('Transpiler level 1: \n', draw_qprog(prog_level_1))
print('Transpiler level 2: \n', draw_qprog(prog_level_2))
Definition transpilation.py:1

Variational Quantum Circuit

Prelude

As of the latest version, QPanda3 uses VQCircuit to support variational quantum circuits. Provide placeholder support for setting variable parameters for logic gates in Ansatz using multidimensional arrays, support for generating QCircuit in batches based on multidimensional arrays, and support for calculating the expected values of Hamiltonians/Pauli operators for the generated QCircuit. In addition, VQCircuit also supports enabling the layer mechanism to better generate QCircuits composed of multiple quantum circuits with the same structure connected in series.

Changes

The name of Class 1 was changed from VQC to VQCircuit to avoid conflicts with the abbreviation of the variational quantum circuit classifier

vqc = VQCircuit()

When constructing Ansatz, the method of adding non-parametric gates and parameter-fixed gates has changed. QPanda3 uses the same functions as QCircuit and QProg to add corresponding quantum logic gates

vqc << H(0)<<X(0)<<CP(1,2,3.14)
cir = QCircuit()
cir << Y(0)<<U2(1,4.14,5.14)
vqc << cir

When constructing Ansztz, the method of adding parameters that require updating quantum logic gates has been changed. QPanda3 uses the functions with same names as those which are for generate QCircuit or QProg. These functions can specify which gate parameters of a certain type with parameters need to be updated.

#<1> qbit 0, <2> the element with index 0, 0 in the array with shape (3, 2) is used as the parameter of the gate, and the parameter with index 0, 0 is assigned the name "theta"
vqc << RX(0,vqc.Param([0,0],"theta"))
# The element corresponding to the name "theta" in qbit 2 is used as the parameter of the gate, which corresponds to the element with index 0,0 in the array with shape (3,2)
vqc << RX(2,vqc.Param("theta"))
#<1> qbit 1, <2> the element with index 1,0 in the array with shape (3,2) is used as the parameter of the gate
vqc << RX(1,vqc.Param([1,0]))

The methods for generating specific QCircuit objects vary. The VQCircuit object generates corresponding QCircuit objects in batches by passing in a multidimensional array.

After generating a QCircuit object, the return form of the result is different. QPanda3 uses the VQCResult object to manage the generated QCircuit

# Prepare test parameters
# Prepare fixed shape array
data = np.zeros((2,3,2,3,2))
# Prepare test data
for i0 in range(2):
for i1 in range(3):
for i2 in range(2):
for i3 in range(3):
for i4 in range(2):
data[i0][i1][i2][i3][i4] = (i0+1)*10000+(i1+1)*1000+(i2+1)*100+(i3+1)*10+(i4+1)
# Print test data
print("data.shape",data.shape)
print("data")
print(data)
# Disable layer mechanism
vqc.disable_layer()
# Apply the parameter data to generate multiple QCircuits in batch and store them in cirs
# Here, 2*3*2 QCircuits are generated, totaling 12 QCircuits. Each QCircuit is updated by VQC based on the last two dimensions of data, which is an array with a shape of (3,2)
res = vqc(data)

New Features

Provides a configurable layer mechanism suitable for constructing quantum circuits formed by concatenating quantum circuits with the same structure but possibly different gate parameters

# Prepare test parameters
# Prepare fixed shape array
data = np.zeros((2,3,2,3,2))
# Prepare test data
for i0 in range(2):
for i1 in range(3):
for i2 in range(2):
for i3 in range(3):
for i4 in range(2):
data[i0][i1][i2][i3][i4] = (i0+1)*10000+(i1+1)*1000+(i2+1)*100+(i3+1)*10+(i4+1)
# Print test data
print("data.shape",data.shape)
print("data")
print(data)
# Disable layer mechanism
vqc.disable_layer()
# Apply the parameter data to generate multiple QCircuits in batch and store them in cirs
# Here, 2*3*2 QCircuits are generated, totaling 12 QCircuits. Each QCircuit is updated by VQC based on the last two dimensions of data, which is an array with a shape of (3,2)
res = vqc(data)
# Prepare test parameters
# Prepare fixed shape array
data = np.zeros((2,3,2,3,2))
# Prepare test data
for i0 in range(2):
for i1 in range(3):
for i2 in range(2):
for i3 in range(3):
for i4 in range(2):
data[i0][i1][i2][i3][i4] = (i0+1)*10000+(i1+1)*1000+(i2+1)*100+(i3+1)*10+(i4+1)
# Print test data
print("data.shape",data.shape)
print("data")
print(data)
# Enable layer mechanism
vqc.enable_layer()
# Apply the parameter data to generate multiple QCircuits in batches and store them in cirs
# Here, 2*3 QCircuits consisting of two layers of sub-circuits are generated, for a total of 6 QCircuits,
# Each QCircuit is generated by VQC by updating parameters based on the last 3-dimensional data, specifically an array with a shape of (2, 3, 2).
# Each QCircuit is composed of two layers of sub-circuits connected in series, and each sub-circuit layer is obtained by setting specific parameters for the Ansatz based on the last two-dimensional data, which is an array with a shape of (3, 2).
res = vqc(data)

Support the construction of Ansatz with variable parameters or fixed parameters

Support for displaying detailed information of internal Ansatz

vqc.display_ansatz()

Support the use of multidimensional arrays to update gate parameters and generate quantum circuits in bulk

# Prepare test parameters
# Prepare fixed shape array
data = np.zeros((2,3,2,3,2))
# Prepare test data
for i0 in range(2):
for i1 in range(3):
for i2 in range(2):
for i3 in range(3):
for i4 in range(2):
data[i0][i1][i2][i3][i4] = (i0+1)*10000+(i1+1)*1000+(i2+1)*100+(i3+1)*10+(i4+1)
# Print test data
print("data.shape",data.shape)
print("data")
print(data)
# Disable layer mechanism
vqc.disable_layer()
# Apply the parameter data to generate multiple QCircuits in batch and store them in cirs
# Here, 2*3*2 QCircuits are generated, totaling 12 QCircuits. Each QCircuit is updated by VQC based on the last two dimensions of data, which is an array with a shape of (3,2)
res = vqc(data)

Provide post-processing of the results of generating circuits in batches, including the calculation of the expected value of the results of quantum program execution in quantum systems with Pauli operators or Hamiltonian actions

# Here, 2*3*2 QCircuits are generated, totaling 12 QCircuits. Each QCircuit is updated by VQC based on the last two dimensions of data, which is an array with a shape of (3,2)
res = vqc(data)
# Obtaining Results Using Multidimensional Indexing
for i0 in range(2):
for i1 in range(3):
for i2 in range(2):
cir = res.at([i0,i1,i2]) #at method, the input parameter is a list of multi-dimensional subscript indexes
# Constructing the Hamiltonian
Ha = Hamiltonian(pauli_with_coef_s = { 'X0 Z1 ':2 + 0j, 'X1 Y2 ':3 + 0j, })
# Calculate the Hamiltonian expectation of all QCircuits in res in batch
# The parameter exp_type specifies the method for solving the Hamiltonian. Currently, only theoretical value calculations are supported, corresponding to the enumeration values of ExpectationType.THEORETICAL
expectations = res.expval_hamiltonian(hamiltonian=Ha,exp_type=ExpectationType.
THEORETICAL)#res is the same as the previous example
# Constructing the PauliOperator
op = PauliOperator(pauli_with_coef_s = { 'X0 Z1 ':2 + 0j, 'X1 Y2 ':3 + 0j, })
# Calculate the PauliOperator expectation of all QCircuits in res in batch
# The parameter exp_type specifies the method for solving the PauliOperator. Currently, only theoretical value calculations are supported, corresponding to the enumeration values of ExpectationType.THEORETICAL
expectations = res.expval_pauli_operator(pauli_operator=op,exp_type=ExpectationType.
THEORETICAL)#res is the same as the previous example