[PYTHON] Qiskit: Implementation of Quantum Hypergraph States

Introduction

When performing quantum calculations, you may want to get the initial state to the desired shape. Especially, it seems to be necessary for quantum neural networks.

what if

\frac{|000>+|001>-|010>+|011>-|100>-|101>+|110>+|111>}{2 \sqrt{2}}

Wouldn't it be convenient if you could quickly find the combination of gates to make? The idea to achieve this is Quantum Hypergraph State.

See Quantum Hypergraph states for more information.

Quantum Hypergraph states

I would like to briefly explain Quantum Hypergraph states.

\frac{i_0|000>+i_1|001>+i_2|010>+i_3|011>+i_4|100>+i_5|101>+i_6|110>+i_7|111>}{2 \sqrt{2}}  \\
i_k = -1 \ or \ 1
  1. When $ | 0 ... 1 ... 0> $ with a coefficient of $ -1 $ exists, Z gate is applied to the qubit with $ 1 $.
  2. Update the coefficients.
  3. When $ | 0 ... 1 ... 1 ... 0> $ with a coefficient of $ -1 $ exists, CZ gate is applied to the qubit with $ 1 $.
  4. Update the coefficients.
  5. When $ | 0 ... 1 ... 1 ... 1 ... 0> $ with a coefficient of $ -1 $ exists, CCZ gate is applied to the qubit with $ 1 $.

For 3qubit, this makes all coefficients 1.

Example

\frac{|000>+|001>-|010>+|011>-|100>-|101>+|110>+|111>}{2 \sqrt{2}}
  1. |010>When|100>Coefficient of-1なので、第二qubitWhen第三qubitにZ gateを作用させます。その結果、
\frac{|000>+|001>+|010>-|011>+|100>+|101>+|110>+|111>}{2 \sqrt{2}}
  1. Since the coefficient of $ | 011> $ is $ -1 $, let the CZ gate work on the first qubit and the second qubit. as a result,
\frac{|000>+|001>+|010>+|011>+|100>+|101>+|110>-|111>}{2 \sqrt{2}}
  1. Since the coefficient of $ | 111> is $ -1 $, let CCZ gate work on the 1st qubit, 2nd qubit and 3rd qubit. as a result,
\frac{|000>+|001>+|010>+|011>+|100>+|101>+|110>+|111>}{2 \sqrt{2}}

This is the end of circuit construction.

qhgs.png

Code

The Code is as follows. To be honest, I'm not good at Python, so there may be some waste. I would appreciate it if you could tell me if there is an efficient way to write. By the way, this time it is up to 3qubit, but I think that you can increase it as much as you like.

python


# matplotlib inline
# coding: utf-8

import numpy as np
from math import log2
from copy import deepcopy
from qiskit import QuantumCircuit, QuantumRegister
from qiskit.quantum_info.operators import Operator
import matplotlib.pyplot as plt


def count_ones_by_bin(num):
    bin_num = bin(num)[2:]
    count = 0
    for i in bin_num:
        count += int(i)
    return count


class QuantumHypergraphState:

    def __init__(self, numqubits, states, qubit_index=None):
        ''' make Quantum HyperGraph State in circuit
        :param circuit:
        :param numqubits: maximum 3
        :param states:
        '''
        self.numqubits = numqubits
        self.states = deepcopy(states)
        if qubit_index is None:
            self.index = [i for i in range(numqubits)]
        else:
            self.index = qubit_index

    def bin_length(self, num):
        bin_num = bin(num)[2:]
        dif_len = self.numqubits - len(bin_num)
        for i in range(dif_len):
            bin_num = '0' + bin_num
        return bin_num

    def get_z_tgt(self, num):
        bin_num = self.bin_length(num)[::-1]
        z_tgt = []
        for i in range(len(bin_num)):
            if int(bin_num[i]) == 1:
                z_tgt.append(i)
        return z_tgt

    def tgt_0(self, num, tgt):
        """
        e.g. tgt = [0]
             num = 011

        """
        bin_num = self.bin_length(num)[::-1]  # 011
        count = 0
        for i in range(len(bin_num)):
            if i in tgt:
                count += int(bin_num[i])
        if count == len(tgt):
            return True
        else:
            return False

    def renew_states(self, tgt):
        for st in range(len(self.states)):
            if self.tgt_0(st, tgt):
                self.states[st] *= -1

    def get_tgt_list(self, idx_list):
        tgt_list = []
        for i in range(len(idx_list)):
            tgt_list.append(self.index[idx_list[i]])
        return tgt_list

    def construct_circuit(self, circuit, inverse=False):
        ccz = Operator([[1, 0, 0, 0, 0, 0, 0, 0],
                        [0, 1, 0, 0, 0, 0, 0, 0],
                        [0, 0, 1, 0, 0, 0, 0, 0],
                        [0, 0, 0, 1, 0, 0, 0, 0],
                        [0, 0, 0, 0, 1, 0, 0, 0],
                        [0, 0, 0, 0, 0, 1, 0, 0],
                        [0, 0, 0, 0, 0, 0, 1, 0],
                        [0, 0, 0, 0, 0, 0, 0, -1]])
        if inverse:
            gate_list = []
        else:
            circuit.h(self.index)
        for num in range(1, self.numqubits + 1):
            #Loop for states
            if num == 1:
                for st in range(len(self.states)):
                    if count_ones_by_bin(st) == num:
                        if self.states[st] == -1:
                            idx = int(log2(st))
                            tgt = self.index[idx]
                            if inverse:
                                gate_list.append(['z', [tgt]])
                            else:
                                circuit.z(tgt)
                            self.renew_states([idx])
            elif num == 2:
                for st in range(len(self.states)):
                    if count_ones_by_bin(st) == num:
                        if self.states[st] == -1:
                            idx_list = self.get_z_tgt(st)
                            tgt_list = self.get_tgt_list(idx_list)
                            if inverse:
                                gate_list.append(['cz', tgt_list])
                            else:
                                circuit.cz(tgt_list[0], tgt_list[1])
                            self.renew_states(idx_list)
            else:
                for st in range(len(self.states)):
                    if count_ones_by_bin(st) == num:
                        if self.states[st] == -1:
                            idx_list = self.get_z_tgt(st)
                            tgt_list = self.get_tgt_list(idx_list)
                            if inverse:
                                gate_list.append(['ccz', tgt_list])
                            else:
                                circuit.unitary(ccz, self.index, label='ccz')
                            self.renew_states(idx_list)

        if inverse:
            gate_list = gate_list[::-1]
            for gate in gate_list:
                if gate[0] == 'ccz':
                    circuit.unitary(ccz, self.index, label='ccz')
                if gate[0] == 'cz':
                    circuit.cz(gate[1][0], gate[1][1])
                if gate[0] == 'z':
                    circuit.z(gate[1][0])
            # circuit.h(self.index)
            circuit.x(self.index)
            return circuit
        else:
            return circuit

    def draw(self):
        print(self.qc.draw(output='mpl'))

that's all. Thank you very much.

Postscript

I was spitting out some errors so I updated it: 2020/04/12

Recommended Posts

Qiskit: Implementation of Quantum Hypergraph States
Qiskit: Implementation of quantum Boltzmann machine
Qiskit: Implementation of Quantum Circuit Learning (QCL)
Quantum computer implementation of quantum walk 2
Quantum computer implementation of quantum walk 3
Quantum computer implementation of quantum walk 1
Quantum computer implementation of 3-state quantum walk
Qiskit: Implementation of QAOA without Qiskit Aqua
Qiskit: Realizing artificial neurons with quantum circuits (implementation)
Quantum teleportation with Qiskit!
Implementation of Fibonacci sequence
Qiskit: Quantum Fourier Transform
Implementation of TF-IDF using gensim
Implementation of MathJax on Sphinx
Explanation and implementation of SocialFoceModel
Implementation of game theory-Prisoner's dilemma-
Implementation of independent component analysis
Python implementation of particle filters
Implementation of quicksort in Python
Deep reinforcement learning 2 Implementation of reinforcement learning
Implementation of Scale-space for SIFT