{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Frequently Used Functions in Paddle Quantum\n",
"\n",
" Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Overview"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this file, we list some frequently used functions in Paddle Quantum.\n",
"\n",
"You can see other functions in [API](https://qml.baidu.com/api/introduction.html)\n",
"\n",
"Here we will also use preparing a pure state as an example to see how to use Paddle Quantum to realize quantum neural network algorithms."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Import Mudules "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# 1.1 Import numpy and paddle\n",
"import numpy as np\n",
"import paddle\n",
"\n",
"# 1.2 Create quantum circuit\n",
"from paddle_quantum.circuit import UAnsatz \n",
"\n",
"# 1.3 Create quantum state - in np.ndarray form\n",
"from paddle_quantum.state import vec, vec_random # As vector\n",
"from paddle_quantum.state import density_op, density_op_random, completely_mixed_computational # As matrix\n",
"\n",
"# 1.4 Create Matrix - in np.ndarray form\n",
"from scipy.stats import unitary_group # Random U matrix\n",
"from paddle_quantum.utils import pauli_str_to_matrix # Pauli matrices for n qubits\n",
"\n",
"# 1.5 Matrix calculation with paddle.Tensor\n",
"from paddle import matmul, trace # Calculate the inner product and trace\n",
"from paddle_quantum.utils import dagger # Get dagger of a paddle.Tensor (note: for numpy.ndarray, you can use “.conj().T” to do dagger)\n",
"\n",
"# 1.6 Plot figure\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Often Used Parameters"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# 2.1 Parameters for quantum circuit\n",
"\n",
"N = 3 # Qubits number in Quantum circuit\n",
"DEPTH = 2 # Depth of the quantum circuit (Layers number)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# 2.2 Parameters in the iteration \n",
"\n",
"ITR = 200 # Iteration number \n",
"LR = 0.2 # Learning rate \n",
"SEED = 1 # Random seed \n",
"paddle.seed(SEED) # seed for paddle\n",
"np.random.seed(SEED) # seed for numpy"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Numpy Matrix"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# 3.1 Random unitary gate\n",
"V = unitary_group.rvs(2) # Random 2*2 V"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# 3.2 Diagonal matrix\n",
"D = np.diag([0.2, 0.8])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# 3.3 Transpose complex conjugate\n",
"V_dagger = V.conj().T"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# 3.4 Matrix multiplication: @\n",
"H = (V @ D @ V_dagger)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(0.9999999999999998-8.239936510889834e-18j)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 3.5 Trace\n",
"H.trace()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0.2, 0.8])"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 3.6 Eigenvalues\n",
"np.linalg.eigh(H)[0]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# 3.7 Tensor product: A \\otimes B\n",
"A = np.eye(2)\n",
"B = H\n",
"T = np.kron(A, B)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Note: in Paddle Quantum, you can use string to create matrix for Pauli matices with $n$ qubit."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# An example: 0.4*I⊗Z+0.4*Z⊗I+0.2*X⊗X\n",
"# In the string form: 0.4*kron(I, Z) + 0.4*kron(Z, I) + 0.2*kron(X, X)\n",
"H_info = [[0.4, 'z0'], [0.4, 'z1'], [0.2, 'x0,x1']]\n",
"H_matrix = pauli_str_to_matrix(H_info, 3) # pauli matices with 3 qubits"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Quantum States"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# 4.1 Get pure states (a row vector in np.ndarray form)\n",
"\n",
"initial_state_pure1 = vec(0, N) # Get |00…0>, 2**N dimension row vector\n",
"initial_state_pure2 = vec_random(N) # Get random pure state, row vector"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"# 4.2 Get mixed states (in np.ndarray form)\n",
"\n",
"initial_state_mixed1 = density_op(N) # Get |00…0><00…0|\n",
"# Get a random density matrix, can decide real or complex and its rank (rank = 1 means pure) \n",
"initial_state_mixed2 = density_op_random(N, real_or_complex=2, rank=4)\n",
"initial_state_mixed3 = completely_mixed_computational(N) # Get a maximally mixed state "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Quantum Circuit"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# 5.1 Create an N qubits quantum circuit\n",
"cir = UAnsatz(N)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"# 5.2 Add gates to the circuit - see Section 7\n",
"# An example: add a CNOT gate to the first two qubits:\n",
"cir.cnot([0, 1])"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# 5.3 The output state of the circuit\n",
"# The output state of the circuit as a vector in paddle.Tensor form.\n",
"# Note: the shape of the output here is not a vector. It can be changed to a column vector \n",
" # via function \"paddle.reshape(final_state, [2**N, 1]) —— it will be made better in the next version\n",
"\n",
"# Initial state is |00...0>\n",
"final_state = cir.run_state_vector()\n",
"# Initial state is not |00...0>\n",
"initial_state_pure = paddle.to_tensor(initial_state_pure2)\n",
"final_state_pure = cir.run_state_vector(initial_state_pure)\n",
"# Change to np.array form\n",
"final_state_pure_np = cir.run_state_vector().reshape([2**N, 1]).numpy()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"# Initial state is |00…0><00…0|\n",
"cir.run_density_matrix()\n",
"# Initial state is not |00...0><00...0|\n",
"initial_state_mixed = paddle.to_tensor(initial_state_mixed2)\n",
"final_state_mixed = cir.run_density_matrix(initial_state_mixed)\n",
"# Change to np.ndarray form\n",
"final_state_mixed_np = cir.run_density_matrix().numpy()"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 0., 0., 0., 0., 0., 0., 0.],\n",
" [0., 1., 0., 0., 0., 0., 0., 0.],\n",
" [0., 0., 1., 0., 0., 0., 0., 0.],\n",
" [0., 0., 0., 1., 0., 0., 0., 0.],\n",
" [0., 0., 0., 0., 0., 0., 1., 0.],\n",
" [0., 0., 0., 0., 0., 0., 0., 1.],\n",
" [0., 0., 0., 0., 1., 0., 0., 0.],\n",
" [0., 0., 0., 0., 0., 1., 0., 0.]])"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 5.4 The unitary matrix of the circuit (in paddle.Tensor form)\n",
"cir.U\n",
"# Change to np.ndarray form\n",
"cir.U.numpy()\n",
"# Only keep the real part:\n",
"cir.U.real()\n",
"cir.U.numpy().real"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--*--\n",
" | \n",
"--x--\n",
" \n",
"-----\n",
" \n"
]
}
],
"source": [
"# 5.5 Print the circuit\n",
"print(cir)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"