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
For 3qubit, this makes all coefficients 1.
\frac{|000>+|001>-|010>+|011>-|100>-|101>+|110>+|111>}{2 \sqrt{2}}
\frac{|000>+|001>+|010>-|011>+|100>+|101>+|110>+|111>}{2 \sqrt{2}}
\frac{|000>+|001>+|010>+|011>+|100>+|101>+|110>-|111>}{2 \sqrt{2}}
\frac{|000>+|001>+|010>+|011>+|100>+|101>+|110>+|111>}{2 \sqrt{2}}
This is the end of circuit construction.

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.
I was spitting out some errors so I updated it: 2020/04/12
Recommended Posts