ashutosh1919 commited on
Commit
46568f0
1 Parent(s): a811e85

Adding hypergraph states

Browse files
mypy.ini CHANGED
@@ -4,6 +4,12 @@
4
  plugins = numpy.typing.mypy_plugin
5
  warn_return_any = True
6
  warn_unused_configs = True
 
 
 
 
 
 
7
 
8
  # Per-module options:
9
 
 
4
  plugins = numpy.typing.mypy_plugin
5
  warn_return_any = True
6
  warn_unused_configs = True
7
+ ignore_missing_imports = True
8
+ strict_optional = False
9
+ no_implicit_optional = True
10
+ warn_redundant_casts = True
11
+ warn_unused_ignores = True
12
+
13
 
14
  # Per-module options:
15
 
quantum_perceptron/tests/test_utils.py CHANGED
@@ -1,42 +1,47 @@
1
  import pytest
2
  import numpy as np
3
 
4
- from quantum_perceptron.utils.data_utils import (
5
  get_vector_from_int,
6
- get_num_bits,
7
- get_possible_state_strings
 
8
  )
9
 
10
 
11
- @pytest.mark.parametrize("data, expected_result", [
12
- (12, 4),
13
- (8, 4),
14
- (7, 3),
15
- (0, 1),
16
- (-5, False),
17
  ])
18
- def test_get_num_bits(data, expected_result):
19
  if isinstance(expected_result, bool) and not expected_result:
20
  with pytest.raises(ValueError):
21
- get_num_bits(data)
22
  else:
23
- assert expected_result == get_num_bits(data)
 
 
 
24
 
25
 
26
- @pytest.mark.parametrize("data, expected_result", [
27
- (12, np.array([-1, -1, 1, 1])),
28
- (1, np.array([1, 1, 1, -1])),
29
- (0, np.array([1, 1, 1, 1])),
30
- (-5, False)
 
31
  ])
32
- def test_get_vector_from_int(data, expected_result):
33
  if isinstance(expected_result, bool) and not expected_result:
34
  with pytest.raises(ValueError):
35
- get_vector_from_int(data)
36
  else:
37
  np.array_equal(
38
  expected_result,
39
- get_vector_from_int(data)
40
  )
41
 
42
 
@@ -56,3 +61,22 @@ def test_get_possible_state_strings(num_bits, expected_result):
56
  expected_result,
57
  get_possible_state_strings(num_bits)
58
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import pytest
2
  import numpy as np
3
 
4
+ from quantum_perceptron.utils import (
5
  get_vector_from_int,
6
+ get_bin_int,
7
+ get_possible_state_strings,
8
+ get_ones_counts_to_states
9
  )
10
 
11
 
12
+ @pytest.mark.parametrize("data, num_qubits, expected_result", [
13
+ (12, 4, '1100'),
14
+ (12, 5, '01100'),
15
+ (1, 1, '1'),
16
+ (2, None, '10'),
17
+ (-5, 2, False)
18
  ])
19
+ def test_get_bin_int(data, num_qubits, expected_result):
20
  if isinstance(expected_result, bool) and not expected_result:
21
  with pytest.raises(ValueError):
22
+ get_bin_int(data, num_qubits)
23
  else:
24
+ np.array_equal(
25
+ expected_result,
26
+ get_bin_int(data, num_qubits)
27
+ )
28
 
29
 
30
+ @pytest.mark.parametrize("data, num_qubits, expected_result", [
31
+ (12, 4, np.array([-1, -1, 1, 1])),
32
+ (12, 5, np.array([1, -1, -1, 1, 1])),
33
+ (1, 1, np.array([-1])),
34
+ (12, 3, False),
35
+ (-5, 2, False)
36
  ])
37
+ def test_get_vector_from_int(data, num_qubits, expected_result):
38
  if isinstance(expected_result, bool) and not expected_result:
39
  with pytest.raises(ValueError):
40
+ get_vector_from_int(data, num_qubits)
41
  else:
42
  np.array_equal(
43
  expected_result,
44
+ get_vector_from_int(data, num_qubits)
45
  )
46
 
47
 
 
61
  expected_result,
62
  get_possible_state_strings(num_bits)
63
  )
64
+
65
+
66
+ @pytest.mark.parametrize("states, expected_result", [
67
+ (np.array(['0', '1']), {0: [0], 1: [1]}),
68
+ (np.array(['00', '01', '10', '11']), {0: [0], 1: [1, 2], 2: [3]}),
69
+ (np.array(['000', '001', '010', '011', '100', '101', '110', '111']), {
70
+ 0: [0],
71
+ 1: [1, 2, 4],
72
+ 2: [3, 5, 6],
73
+ 3: [7]
74
+ }),
75
+ (np.array([]), False)
76
+ ])
77
+ def test_get_ones_counts_to_states(states, expected_result):
78
+ if isinstance(expected_result, bool) and not expected_result:
79
+ with pytest.raises(ValueError):
80
+ get_ones_counts_to_states(states)
81
+ else:
82
+ assert expected_result == get_ones_counts_to_states(states)
quantum_perceptron/utils/__init__.py CHANGED
@@ -0,0 +1 @@
 
 
1
+ from quantum_perceptron.utils.data_utils import *
quantum_perceptron/utils/data_utils.py CHANGED
@@ -1,4 +1,5 @@
1
  import numpy as np
 
2
 
3
 
4
  def assert_negative(data: int):
@@ -9,23 +10,25 @@ def assert_negative(data: int):
9
  raise ValueError("Currently we do not support negative data values.")
10
 
11
 
12
- def get_bin_int(data: int) -> str:
13
  """
14
  Get binary representation of integer.
15
  """
16
  assert_negative(data)
 
 
17
  return bin(data)[2:]
18
 
19
 
20
- def get_num_bits(data: int) -> int:
21
  """
22
- Get number of bits in an integer.
23
  """
24
- assert_negative(data)
25
- return len(get_bin_int(data))
26
 
27
 
28
- def get_vector_from_int(data: int) -> np.ndarray:
29
  """
30
  This method returns the vector where each element is (-1)^b_i where b_i is
31
  the bit value at index i.
@@ -33,13 +36,14 @@ def get_vector_from_int(data: int) -> np.ndarray:
33
  Args:
34
  data: `int` representing data value
35
  (correspponding toinput or weight vector)
 
36
 
37
  Returns: Vector in form of `np.ndarray`.
38
  """
39
  assert_negative(data)
 
40
 
41
- bin_data = get_bin_int(data)
42
- num_qubits = get_num_bits(data)
43
  data_vector = np.empty(num_qubits)
44
 
45
  for i, bit in enumerate(bin_data):
@@ -72,3 +76,27 @@ def get_possible_state_strings(num_bits: int) -> np.ndarray:
72
  states[i] = state_template.format(i)
73
 
74
  return states
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import numpy as np
2
+ from typing import Dict, List, Optional
3
 
4
 
5
  def assert_negative(data: int):
 
10
  raise ValueError("Currently we do not support negative data values.")
11
 
12
 
13
+ def get_bin_int(data: int, num_qubits: Optional[int] = None) -> str:
14
  """
15
  Get binary representation of integer.
16
  """
17
  assert_negative(data)
18
+ if num_qubits:
19
+ return bin(data)[2:].zfill(num_qubits)
20
  return bin(data)[2:]
21
 
22
 
23
+ def assert_bits(data: int, num_bits: int):
24
  """
25
+ General method to prevent invalid number of bits.
26
  """
27
+ if len(get_bin_int(data)) > num_bits:
28
+ raise ValueError("data has more bits than num_bits")
29
 
30
 
31
+ def get_vector_from_int(data: int, num_qubits: int) -> np.ndarray:
32
  """
33
  This method returns the vector where each element is (-1)^b_i where b_i is
34
  the bit value at index i.
 
36
  Args:
37
  data: `int` representing data value
38
  (correspponding toinput or weight vector)
39
+ num_qubits: `int` representing number of qubits.
40
 
41
  Returns: Vector in form of `np.ndarray`.
42
  """
43
  assert_negative(data)
44
+ assert_bits(data, num_qubits)
45
 
46
+ bin_data = get_bin_int(data, num_qubits)
 
47
  data_vector = np.empty(num_qubits)
48
 
49
  for i, bit in enumerate(bin_data):
 
76
  states[i] = state_template.format(i)
77
 
78
  return states
79
+
80
+
81
+ def get_ones_counts_to_states(states: np.ndarray) -> Dict[int, List[int]]:
82
+ """
83
+ Get the mapping from number of 1's to the states which has that many number
84
+ of 1 bits.
85
+
86
+ Args:
87
+ states: `np.ndarray` containing the bit strings of the states.
88
+
89
+ Returns: `dict` containing the mappings from count of 1's to the list
90
+ of states.
91
+ """
92
+ if len(states) == 0:
93
+ raise ValueError("The states array is empty")
94
+
95
+ ones_count: Dict[int, List[int]] = dict()
96
+ for i in range(len(states)):
97
+ ct = states[i].count('1')
98
+ if ct not in ones_count:
99
+ ones_count[ct] = []
100
+ ones_count[ct].append(i)
101
+
102
+ return ones_count
quantum_perceptron/utils/quantum_utils.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from typing import List, Dict
3
+ from qiskit import QuantumCircuit
4
+ from quantum_perceptron.utils.data_utils import (
5
+ get_possible_state_strings,
6
+ get_ones_counts_to_states
7
+ )
8
+
9
+
10
+ def append_hypergraph_state(
11
+ circuit: QuantumCircuit,
12
+ data_vector: np.ndarray,
13
+ states: np.ndarray,
14
+ ones_count: Dict[int, List[int]]) -> QuantumCircuit:
15
+ """
16
+ Append the computed hypergraph state to the circuit.
17
+
18
+ Args:
19
+ circuit: `QuantumCircuit` object corresponding to the perceptron.
20
+ data_vector: `np.ndarray` containing the data vector containing -1s & 1s.
21
+ states: `list` of `str` containing the bit strings for states.
22
+ ones_count: `dict` containing mapping of the count of ones with
23
+ index of states
24
+
25
+ Returns: `QuantumCircuit` object denoting the circuit containing
26
+ hypergraph states.
27
+ """
28
+ num_qubits = int(np.log2(len(data_vector)))
29
+ is_sign_inverted = [1] * len(data_vector)
30
+
31
+ # Flipping all signs if all zero state has coef -1.
32
+ if data_vector[0] == -1:
33
+ for i in range(len(data_vector)):
34
+ data_vector[i] *= -1
35
+
36
+ for ct in range(1, num_qubits + 1):
37
+ for i in ones_count.get(ct, []):
38
+ if data_vector[i] == is_sign_inverted[i]:
39
+ state = states[i]
40
+ ones_idx = [j for j, x in enumerate(state) if x == '1']
41
+ if ct == 1:
42
+ circuit.z(ones_idx[0])
43
+ elif ct == 2:
44
+ circuit.cz(ones_idx[0], ones_idx[1])
45
+ else:
46
+ circuit.mcrz(
47
+ -np.pi,
48
+ [circuit.qubits[j] for j in ones_idx[1:]],
49
+ circuit.qubits[ones_idx[0]]
50
+ )
51
+ for j, state in enumerate(states):
52
+ is_one = np.array([bit == '1' for bit in state])
53
+ if np.all(is_one[ones_idx]):
54
+ is_sign_inverted[j] *= -1
55
+ return circuit
56
+
57
+
58
+ def create_hypergraph_state(circuit: QuantumCircuit,
59
+ data_vector: np.ndarray) -> QuantumCircuit:
60
+ """
61
+ Creating hypergraph state for specific data vector corresponding to
62
+ the provided data (input or weight value).
63
+ It is as per https://arxiv.org/abs/1811.02266.
64
+
65
+ Args:
66
+ circuit: `QuantumCircuit` object corresponding to the perceptron.
67
+ data_vector: `np.ndarray` containing the data vector containing -1s & 1s.
68
+
69
+ Returns: `QuantumCircuit` object denoting the circuit containing
70
+ hypergraph states.
71
+ """
72
+ num_qubits = int(np.log2(len(data_vector)))
73
+ states = get_possible_state_strings(num_qubits)
74
+ ones_count = get_ones_counts_to_states(states)
75
+ return append_hypergraph_state(
76
+ circuit,
77
+ data_vector,
78
+ states,
79
+ ones_count
80
+ )