Demo Play

This section outlines the procedure for executing the Block-Encoding method using PItBE. It is recommended to read through this before using this module.

Computation Conditions

  • Target matrix to reproduce on the quantum circuit Hamiltonian of the transverse-field Ising model for a 6-particle system:​

\[\hat{H} = 0.5\sum_i^{6}\hat{Z}_i\hat{Z}_{i+1} + 0.8\sum_i^{6}\hat{X}_i\]
  • Quantum state to which the matrix is applied The system where all spins are aligned in the \(+z\) -direction:

    \[|\psi\rangle = |000000\rangle\]

Execution

Preparation for Execution

First, construct the unitary matrix that determines the quantum state of the ancillary qubits.
Ideally, this would be represented as a product of Pauli rotation gates; however, there is currently no proposed method to create a product of Pauli rotation gates that generates an arbitrary quantum state.
Therefore, in this work, we use a unitary gate that acts on the ancillary qubits initially in the all-zero state and transforms them into an arbitrary quantum state.
[1]:
import math
import numpy as np
import pitbe

# The coefficients and Pauli matrix production
# in the linear combination representation of the matrix to be Block-Encoded
coefficients = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8]
paulies = ['Z0Z1', 'Z1Z2', 'Z2Z3', 'Z3Z4', 'Z4Z5', 'Z5Z0',
           'X0', 'X1', 'X2', 'X3', 'X4', 'X5']

# Normalize coefficients
norm_cf = np.sum(np.abs(coefficients))
alphas = (np.sqrt(np.abs(coefficients)) / np.sqrt(np.sum(np.abs(coefficients))))
if math.floor(np.log2(len(alphas))) != np.log2(len(alphas)):
        zero_list = np.zeros(2**(math.floor(np.log2(len(alphas))) + 1) - len(alphas))
        alphas = np.append(alphas, zero_list)

# Creating a matrix for adjusting coefficient signs
opposite_list = np.ones(len(alphas))
for j in range(len(coefficients)):
    if (coefficients[j] < 0):
        opposite_list[j] = -1

# Creating a matrix for adjusting ancilla qubits
cf = pitbe.coeff_make(alphas)
mat_for_anci = pitbe.mat_maker(alphas, cf)

Construct Quantum Circuit

Next, construct the quantum circuit that performs the BE method. For details on the circuit structure and flow, please refer to the page explaining the BE method. In this example, we use Qulacs as the quantum simulator.

[2]:
from qulacs import QuantumState, QuantumCircuit
from qulacs.state import inner_product
from qulacs.gate import X, Y, Z, DenseMatrix, H, CNOT, to_matrix_gate, CZ, RY, RZ, merge
from qulacs.observable import create_observable_from_openfermion_text
from qulacs.quantum_operator import create_quantum_operator_from_openfermion_file
from qulacs.quantum_operator import create_quantum_operator_from_openfermion_text
from qulacsvis import circuit_drawer

# Detect the number of main qubits and ancilla qubits
main = pitbe.total_search(paulies)
anci = int(np.log2(len(alphas)))

# Prepare the control qubit information
cont_list = []
for j in range(len(paulies)):
    cont_list.append(pitbe.cont_order(j, anci))

# Create quantum circuit and quantum state
total = anci + main
state = QuantumState(total)
state.set_zero_state()
circ = QuantumCircuit(total)

# Convert matrices into quantum gates
gate = DenseMatrix([j for j in range(anci)], mat_for_anci)
opp_gate = DenseMatrix([j for j in range(anci)], np.diag(opposite_list))
gate_dag = gate.get_inverse()

# Create quantum circuit
circ.add_gate(gate)
circ.add_gate(opp_gate)
for j in range(len(cont_list)):
    pitbe.circ_make(paulies[j], cont_list[j], circ, total, anci)
circ.add_gate(gate_dag)

Execution of the Quantum Circuit and Analysis of the Results

Finally, execute the quantum circuit and analyze the results.
Specifically, extract the outcomes where all ancillary qubits are measured as 0, adjust the corresponding coefficients, and output the processed result.
As noted on the page explaining the BE method, the output of this process provides information about the quantum state after applying the reconstructed matrix—not its eigenvalues directly.
[3]:
# Run the quantum circuit
circ.update_quantum_state(state)

# Calculate probability to get the result of Block-Encoding
obser_order = []
for j in range(anci):
    obser_order.append(0)
for j in range(main):
    obser_order.append(2)
prob = state.get_marginal_probability(obser_order)

# Analyze the result of Block-Encoding
res_state = state.get_vector()
desire_state = []
for i in range(2**anci):
    desire_state.append(res_state[2**anci*i]*norm_cf)
print(desire_state)
[np.complex128(2.9999999999999996+0j), np.complex128(0.7999999999999998+0j), np.complex128(0.7999999999999998+0j), np.complex128(0j), np.complex128(0.7999999999999998+0j), np.complex128(0j), np.complex128(0j), np.complex128(0j), np.complex128(0.7999999999999998+0j), np.complex128(0j), np.complex128(0j), np.complex128(0j), np.complex128(0j), np.complex128(0j), np.complex128(0j), np.complex128(0j)]
This result matches the outcome of directly applying the Hamiltonian \(\hat{H}\) to the quantum state \(|\psi\rangle\), \(\hat{H}|\psi\rangle\).
The above describes the complete workflow for executing the BE method using the PItBE module.