def circuit_QAOA(theta, adjacency_matrix, N, P): """ This function constructs the parameterized QAOA circuit which is composed of P layers of two blocks: one block is based on the problem Hamiltonian H which encodes the classical problem, and the other is constructed from the driving Hamiltonian describing the rotation around Pauli X acting on each qubit. It outputs the final state of the QAOA circuit. Args: theta: parameters to be optimized in the QAOA circuit adjacency_matrix: the adjacency matrix of the graph encoding the classical problem N: number of qubits, or equivalently, the number of parameters in the original classical problem P: number of layers of two blocks in the QAOA circuit Returns: the QAOA circuit """ cir = UAnsatz(N) # prepare the input state in the uniform superposition of 2^N bit-strings in the computational basis cir.superposition_layer() # This loop defines the QAOA circuit with P layers of two blocks for layer in range(P): # The second and third loops construct the first block which involves two-qubit operation # e^{-i\gamma Z_iZ_j} acting on a pair of qubits or nodes i and j in the circuit in each layer. for row in range(N): for col in range(N): if adjacency_matrix[row, col] and row < col: cir.cnot([row, col]) cir.rz(theta[layer][0], col) cir.cnot([row, col]) # This loop constructs the second block only involving the single-qubit operation e^{-i\beta X}. for i in range(N): cir.rx(theta[layer][1], i) return cir
def circuit_QAOA(E, V, n, p, gamma, beta): """ This function constructs the parameterized QAOA circuit which is composed of P layers of two blocks: one block is based on the problem Hamiltonian H which encodes the classical problem, and the other is constructed from the driving Hamiltonian describing the rotation around Pauli X acting on each qubit. It outputs the final state of the QAOA circuit. Args: E: edges of the graph V: vertices of the graph n: number of qubits in th QAOA circuit p: number of layers of two blocks in the QAOA circuit gamma: parameter to be optimized in the QAOA circuit, parameter for the first block beta: parameter to be optimized in the QAOA circui, parameter for the second block Returns: the QAOA circuit """ cir = UAnsatz(n) cir.superposition_layer() for layer in range(p): for (u, v) in E: cir.cnot([u, v]) cir.rz(gamma[layer], v) cir.cnot([u, v]) for v in V: cir.rx(beta[layer], v) return cir
def circuit_maxcut(E, V, p, gamma, beta): r"""构建用于最大割问题的 QAOA 参数化电路。 Args: E: 图的边 V: 图的顶点 p: QAOA 电路的层数 gamma: 与最大割问题哈密顿量相关的电路参数 beta: 与混合哈密顿量相关的电路参数 Returns: UAnsatz: 构建好的 QAOA 电路 """ # Number of qubits needed n = len(V) cir = UAnsatz(n) cir.superposition_layer() for layer in range(p): for (u, v) in E: cir.cnot([u, v]) cir.rz(gamma[layer], v) cir.cnot([u, v]) for i in V: cir.rx(beta[layer], i) return cir
def circuit_extend_QAOA(theta, input_state, adjacency_matrix, N, P): """ This is an extended version of the QAOA circuit, and the main difference is U_theta[layer]([1]-[3]) constructed from the driving Hamiltonian describing the rotation around an arbitrary direction on each qubit. Args: theta: parameters to be optimized in the QAOA circuit input_state: input state of the QAOA circuit which usually is the uniform superposition of 2^N bit-strings in the computational basis adjacency_matrix: the adjacency matrix of the problem graph encoding the original problem N: number of qubits, or equivalently, the number of parameters in the original classical problem P: number of layers of two blocks in the QAOA circuit Returns: final state of the QAOA circuit: cir.state Note: If this U_extend_theta function is used to construct QAOA circuit, then we need to change the parameter layer in the Net function defined below from the Net(shape=[D, 2]) for U_theta function to Net(shape=[D, 4]) because the number of parameters doubles in each layer in this QAOA circuit. """ cir = UAnsatz(N, input_state=input_state) # The first loop defines the QAOA circuit with P layers of two blocks for layer in range(P): # The second and third loops aim to construct the first block U_theta[layer][0] which involves # two-qubit operation e^{-i\beta Z_iZ_j} acting on a pair of qubits or nodes i and j in the circuit. for row in range(N): for col in range(N): if abs(adjacency_matrix[row, col]) and row < col: cir.cnot([row + 1, col + 1]) cir.rz( theta=theta[layer][0] * adjacency_matrix[row, col], which_qubit=col + 1, ) cir.cnot([row + 1, col + 1]) # This loops constructs the second block U_theta[layer][1]-[3] composed of three single-qubit operation # e^{-i\beta[1] Z}e^{-i\beta[2] X}e^{-i\beta[3] X} sequentially acting on single qubits. for i in range(1, N + 1): cir.rz(theta=theta[layer][1], which_qubit=i) cir.rx(theta=theta[layer][2], which_qubit=i) cir.rz(theta=theta[layer][3], which_qubit=i) return cir.state
def circuit_QAOA(theta, input_state, adjacency_matrix, N, P): """ This function constructs the parameterized QAOA circuit which is composed of P layers of two blocks: one block is U_theta[layer][0] based on the problem Hamiltonian H which encodes the classical problem, and the other is U_theta[layer][1] constructed from the driving Hamiltonian describing the rotation around Pauli X acting on each qubit. It finally outputs the final state of the QAOA circuit. Args: theta: parameters to be optimized in the QAOA circuit input_state: initial state of the QAOA circuit which usually is the uniform superposition of 2^N bit-strings in the computational basis $|0\rangle, |1\rangle$ adjacency_matrix: the adjacency matrix of the graph encoding the classical problem N: number of qubits, or equivalently, the number of nodes in the given graph P: number of layers of two blocks in the QAOA circuit Returns: the final state of the QAOA circuit: cir.state """ cir = UAnsatz(N, input_state=input_state) # The first loop defines the QAOA circuit with P layers of two blocks for layer in range(P): # The second and third loops aim to construct the first block U_theta[layer][0] which involves # two-qubit operation e^{-i\beta Z_iZ_j} acting on a pair of qubits or nodes i and j in the circuit. for row in range(N): for col in range(N): if abs(adjacency_matrix[row, col]) and row < col: cir.cnot([row + 1, col + 1]) cir.rz( theta=theta[layer][0] * adjacency_matrix[row, col], which_qubit=col + 1, ) cir.cnot([row + 1, col + 1]) # This loops constructs the second block U_theta only involving the single-qubit operation e^{-i\beta X}. for i in range(1, N + 1): cir.rx(theta=theta[layer][1], which_qubit=i) return cir.state
def U_theta(theta, input_state, N, D): # definition of U_theta """ :param theta: :param input_state: :return: """ cir = UAnsatz(N, input_state=input_state) for i in range(N): cir.rx(theta=theta[0][0][i], which_qubit=i + 1) cir.ry(theta=theta[0][1][i], which_qubit=i + 1) cir.rx(theta=theta[0][2][i], which_qubit=i + 1) for repeat in range(D): for i in range(1, N): cir.cnot(control=[i, i + 1]) for i in range(N): cir.ry(theta=theta[repeat][0][i], which_qubit=i + 1) # cir.ry(theta=theta[repeat][1][i], which_qubit=i + 1) # cir.ry(theta=theta[repeat][2][i], which_qubit=i + 1) return cir.state