File size: 2,974 Bytes
46568f0
 
 
 
 
 
 
 
 
 
 
 
 
91d3e9c
 
46568f0
 
 
 
 
 
 
 
 
91d3e9c
46568f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91d3e9c
 
46568f0
 
 
 
 
 
 
 
91d3e9c
46568f0
 
 
 
 
 
 
 
 
 
91d3e9c
 
46568f0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import numpy as np
from typing import List, Dict
from qiskit import QuantumCircuit
from quantum_perceptron.utils.data_utils import (
    get_possible_state_strings,
    get_ones_counts_to_states
)


def append_hypergraph_state(
        circuit: QuantumCircuit,
        data_vector: np.ndarray,
        states: np.ndarray,
        ones_count: Dict[int, List[int]],
        num_qubits: int) -> QuantumCircuit:
    """
    Append the computed hypergraph state to the circuit.

    Args:
      circuit: `QuantumCircuit` object corresponding to the perceptron.
      data_vector: `np.ndarray` containing the data vector containing -1s & 1s.
      states: `list` of `str` containing the bit strings for states.
      ones_count: `dict` containing mapping of the count of ones with
        index of states
      num_qubits: `int` denoting total number of qubits in the circuit.

    Returns: `QuantumCircuit` object denoting the circuit containing
      hypergraph states.
    """
    is_sign_inverted = [1] * len(data_vector)

    # Flipping all signs if all zero state has coef -1.
    if data_vector[0] == -1:
        for i in range(len(data_vector)):
            data_vector[i] *= -1

    for ct in range(1, num_qubits + 1):
        for i in ones_count.get(ct, []):
            if data_vector[i] == is_sign_inverted[i]:
                state = states[i]
                ones_idx = [j for j, x in enumerate(state) if x == '1']
                if ct == 1:
                    circuit.z(ones_idx[0])
                elif ct == 2:
                    circuit.cz(ones_idx[0], ones_idx[1])
                else:
                    circuit.mcrz(
                        -np.pi,
                        [circuit.qubits[j] for j in ones_idx[1:]],
                        circuit.qubits[ones_idx[0]]
                    )
                for j, state in enumerate(states):
                    is_one = np.array([bit == '1' for bit in state])
                    if np.all(is_one[ones_idx]):
                        is_sign_inverted[j] *= -1
    return circuit


def create_hypergraph_state(circuit: QuantumCircuit,
                            data_vector: np.ndarray,
                            num_qubits: int) -> QuantumCircuit:
    """
    Creating hypergraph state for specific data vector corresponding to
    the provided data (input or weight value).
    It is as per https://arxiv.org/abs/1811.02266.

    Args:
      circuit: `QuantumCircuit` object corresponding to the perceptron.
      data_vector: `np.ndarray` containing the data vector containing -1s & 1s.
      num_qubits: `int` denoting total number of qubits in the circuit.

    Returns: `QuantumCircuit` object denoting the circuit containing
      hypergraph states.
    """
    states = get_possible_state_strings(num_qubits)
    ones_count = get_ones_counts_to_states(states)
    return append_hypergraph_state(
        circuit,
        data_vector,
        states,
        ones_count,
        num_qubits
    )