Skip to content

Commit

Permalink
binary encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
renatomello committed Dec 23, 2024
1 parent 60341f6 commit 13c155e
Showing 1 changed file with 72 additions and 16 deletions.
88 changes: 72 additions & 16 deletions src/qibo/models/encodings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
def comp_basis_encoder(
basis_element: Union[int, str, list, tuple], nqubits: Optional[int] = None, **kwargs
):
"""Creates circuit that performs encoding of bitstrings into computational basis states.
"""Create circuit that performs encoding of bitstrings into computational basis states.
Args:
basis_element (int or str or list or tuple): bitstring to be encoded.
Expand All @@ -31,7 +31,7 @@ def comp_basis_encoder(
For details, see the documentation of :class:`qibo.models.circuit.Circuit`.
Returns:
:class:`qibo.models.circuit.Circuit`: circuit encoding computational basis element.
:class:`qibo.models.circuit.Circuit`: Circuit encoding computational basis element.
"""
if not isinstance(basis_element, (int, str, list, tuple)):
raise_error(
Expand Down Expand Up @@ -74,7 +74,7 @@ def comp_basis_encoder(


def phase_encoder(data, rotation: str = "RY", **kwargs):
"""Creates circuit that performs the phase encoding of ``data``.
"""Create circuit that performs the phase encoding of ``data``.
Args:
data (ndarray or list): :math:`1`-dimensional array of phases to be loaded.
Expand All @@ -86,7 +86,7 @@ def phase_encoder(data, rotation: str = "RY", **kwargs):
For details, see the documentation of :class:`qibo.models.circuit.Circuit`.
Returns:
:class:`qibo.models.circuit.Circuit`: circuit that loads ``data`` in phase encoding.
:class:`qibo.models.circuit.Circuit`: Circuit that loads ``data`` in phase encoding.
"""
if isinstance(data, list):
data = np.array(data)
Expand Down Expand Up @@ -116,8 +116,64 @@ def phase_encoder(data, rotation: str = "RY", **kwargs):
return circuit


def binary_encoder(data, **kwargs):
"""Create circuit that encodes ``data`` in all amplitudes of the computational basis.
Args:
data (ndarray or list): :math:`1`-dimensional array or length :math:`2^{n}`
to be loaded in the amplitudes of a :math:`n`-qubit quantum state.
Returns:
:class:`qibo.models.circuit.Circuit`: Circuit that loads ``data`` in binay encoding.
"""
if isinstance(data, list):
data = np.array(data)

nqubits = float(np.log2(len(data)))
if not nqubits.is_integer():
raise_error(ValueError, "`data` size must be a power of 2.")

nqubits = int(nqubits)
dims = 2**nqubits

base_strings = [f"{elem:0{nqubits}b}" for elem in range(dims)]
base_strings = np.reshape(base_strings, (-1, 2))
strings = [base_strings]
for _ in range(nqubits - 1):
new_row = [row[0] for row in base_strings]
base_strings = np.reshape(new_row, (-1, 2))
strings.append(base_strings)
strings = strings[::-1]

targets_and_controls = []
for pairs in strings:
for pair in pairs:
targets, controls, anticontrols = [], [], []
for k, (bit_0, bit_1) in enumerate(zip(pair[0], pair[1])):
if bit_0 == "0" and bit_1 == "0":
anticontrols.append(k)
elif bit_0 == "1" and bit_1 == "1":
controls.append(k)
elif bit_0 == "0" and bit_1 == "1":
targets.append(k)
targets_and_controls.append([targets, controls, anticontrols])

circuit = Circuit(nqubits, **kwargs)
for targets, controls, anticontrols in targets_and_controls:
gate_list = []
if len(anticontrols) > 0:
gate_list.append(gates.X(qubit) for qubit in anticontrols)
gate_list.append(gates.RY(targets[0], 0.0).controlled_by(*(controls + anticontrols)))
if len(anticontrols) > 0:
gate_list.append(gates.X(qubit) for qubit in anticontrols)
circuit.add(gate_list)

return circuit



def unary_encoder(data, architecture: str = "tree", **kwargs):
"""Creates circuit that performs the (deterministic) unary encoding of ``data``.
"""Create circuit that performs the (deterministic) unary encoding of ``data``.
Args:
data (ndarray): :math:`1`-dimensional array of data to be loaded.
Expand All @@ -129,7 +185,7 @@ def unary_encoder(data, architecture: str = "tree", **kwargs):
For details, see the documentation of :class:`qibo.models.circuit.Circuit`.
Returns:
:class:`qibo.models.circuit.Circuit`: circuit that loads ``data`` in unary representation.
:class:`qibo.models.circuit.Circuit`: Circuit that loads ``data`` in unary representation.
"""
if isinstance(data, list):
data = np.array(data)
Expand Down Expand Up @@ -173,7 +229,7 @@ def unary_encoder(data, architecture: str = "tree", **kwargs):
def unary_encoder_random_gaussian(
nqubits: int, architecture: str = "tree", seed=None, **kwargs
):
"""Creates a circuit that performs the unary encoding of a random Gaussian state.
"""Create a circuit that performs the unary encoding of a random Gaussian state.
At depth :math:`h` of the tree architecture, the angles :math:`\\theta_{k} \\in [0, 2\\pi]` of the the
gates :math:`RBS(\\theta_{k})` are sampled from the following probability density function:
Expand All @@ -197,7 +253,7 @@ def unary_encoder_random_gaussian(
For details, see the documentation of :class:`qibo.models.circuit.Circuit`.
Returns:
:class:`qibo.models.circuit.Circuit`: circuit that loads a random Gaussian array in unary representation.
:class:`qibo.models.circuit.Circuit`: Circuit that loads a random Gaussian array in unary representation.
References:
1. A. Bouland, A. Dandapani, and A. Prakash, *A quantum spectral method for simulating
Expand Down Expand Up @@ -271,7 +327,7 @@ def entangling_layer(
closed_boundary: bool = False,
**kwargs,
):
"""Creates a layer of two-qubit, entangling gates.
"""Create a layer of two-qubit, entangling gates.
If the chosen gate is a parametrized gate, all phases are set to :math:`0.0`.
Expand Down Expand Up @@ -377,7 +433,7 @@ def entangling_layer(


def ghz_state(nqubits: int, **kwargs):
"""Generates an :math:`n`-qubit Greenberger-Horne-Zeilinger (GHZ) state that takes the form
"""Generate an :math:`n`-qubit Greenberger-Horne-Zeilinger (GHZ) state that takes the form
.. math::
\\ket{\\text{GHZ}} = \\frac{\\ket{0}^{\\otimes n} + \\ket{1}^{\\otimes n}}{\\sqrt{2}}
Expand Down Expand Up @@ -406,7 +462,7 @@ def ghz_state(nqubits: int, **kwargs):


def _generate_rbs_pairs(nqubits: int, architecture: str, **kwargs):
"""Generating list of indexes representing the RBS connections
"""Generate list of indexes representing the RBS connections.
Creates circuit with all RBS initialised with 0.0 phase.
Expand All @@ -420,8 +476,8 @@ def _generate_rbs_pairs(nqubits: int, architecture: str, **kwargs):
For details, see the documentation of :class:`qibo.models.circuit.Circuit`.
Returns:
(:class:`qibo.models.circuit.Circuit`, list): circuit composed of :class:`qibo.gates.gates.RBS`
and list of indexes of target qubits per depth.
(:class:`qibo.models.circuit.Circuit`, list): Circuit composed of :class:`qibo.gates.gates.RBS`
and list of indexes of target qubits per depth.
"""

if architecture == "diagonal":
Expand Down Expand Up @@ -451,7 +507,7 @@ def _generate_rbs_pairs(nqubits: int, architecture: str, **kwargs):


def _generate_rbs_angles(data, nqubits: int, architecture: str):
"""Generating list of angles for RBS gates based on ``architecture``.
"""Generate list of angles for RBS gates based on ``architecture``.
Args:
data (ndarray, optional): :math:`1`-dimensional array of data to be loaded.
Expand All @@ -462,7 +518,7 @@ def _generate_rbs_angles(data, nqubits: int, architecture: str):
Defaults to ``tree``.
Returns:
list: list of phases for RBS gates.
list: List of phases for RBS gates.
"""
if architecture == "diagonal":
engine = _check_engine(data)
Expand Down Expand Up @@ -494,7 +550,7 @@ def _generate_rbs_angles(data, nqubits: int, architecture: str):


def _parametrized_two_qubit_gate(gate, q0, q1, params=None):
"""Returns two-qubit gate initialized with or without phases."""
"""Return two-qubit gate initialized with or without phases."""
if params is not None:
return gate(q0, q1, *params)

Expand Down

0 comments on commit 13c155e

Please sign in to comment.