Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CosineWindow StatePrep #4683

Merged
merged 48 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
9c470df
cosine definition
KetpuntoG Oct 16, 2023
fd23ba9
Update cosine_window.py
KetpuntoG Oct 16, 2023
4327304
image
KetpuntoG Oct 16, 2023
53303b0
Update cosine_window.py
KetpuntoG Oct 16, 2023
3fdf9bc
Update cosine_window.py
KetpuntoG Oct 16, 2023
77d566a
adding tests
KetpuntoG Oct 17, 2023
d41709c
Update test_cosine_window.py
KetpuntoG Oct 17, 2023
ecd2fbf
Update cosine_window.py
KetpuntoG Oct 17, 2023
9140298
[ci skip]
KetpuntoG Oct 17, 2023
906b539
tests
KetpuntoG Oct 17, 2023
a7036a9
fixing tests
KetpuntoG Oct 17, 2023
5529669
typo test
KetpuntoG Oct 17, 2023
386112c
reshaping test
KetpuntoG Oct 17, 2023
3704848
thumbnail + codefactor
KetpuntoG Oct 17, 2023
dc001bd
codefactor
KetpuntoG Oct 17, 2023
c0516ca
not batch
KetpuntoG Oct 17, 2023
9d6c034
Update cosine_window.py
KetpuntoG Oct 17, 2023
f563b96
Update cosine_window.py
KetpuntoG Oct 17, 2023
26d6327
Update pennylane/templates/state_preparations/cosine_window.py
KetpuntoG Oct 18, 2023
c4c496f
Update tests/templates/test_state_preparations/test_cosine_window.py
KetpuntoG Oct 18, 2023
0bed715
not wire_order needed
KetpuntoG Oct 18, 2023
697b2c6
Update cosine_window.py
KetpuntoG Oct 18, 2023
cb6d72f
fixing codefactor
KetpuntoG Oct 18, 2023
e836d59
more codefactor complains
KetpuntoG Oct 18, 2023
a8b4f92
Update cosine_window.py
KetpuntoG Oct 18, 2023
29565aa
Update cosine_window.py
KetpuntoG Oct 18, 2023
11d19e9
test changing initilize_state.py
KetpuntoG Oct 18, 2023
b6b7c7a
[ci skip]
KetpuntoG Oct 18, 2023
80adfd7
wires_order again
KetpuntoG Oct 18, 2023
f2e73f8
Update cosine_window.py
KetpuntoG Oct 18, 2023
cc0307d
Update cosine_window.py
KetpuntoG Oct 19, 2023
549451d
visual example
KetpuntoG Oct 19, 2023
079af3b
Update pennylane/templates/state_preparations/cosine_window.py
KetpuntoG Oct 19, 2023
6a91c5b
Update test_cosine_window.py
KetpuntoG Oct 19, 2023
3e161cc
Merge branch 'cosine_window' of https://github.com/PennyLaneAI/pennyl…
KetpuntoG Oct 19, 2023
a8cc1f9
codefactor + test
KetpuntoG Oct 19, 2023
d8491a3
wires.Wires
KetpuntoG Oct 19, 2023
56b1a5a
label + image
KetpuntoG Oct 19, 2023
bdd6780
Update doc/releases/changelog-dev.md
KetpuntoG Oct 20, 2023
f49bc58
Update pennylane/templates/state_preparations/cosine_window.py
KetpuntoG Oct 20, 2023
38e2a97
Update pennylane/templates/state_preparations/cosine_window.py
KetpuntoG Oct 20, 2023
3860af2
last Soran suggestions
KetpuntoG Oct 20, 2023
0ade82b
Merge branch 'master' into cosine_window
KetpuntoG Oct 20, 2023
f99fc81
Update pennylane/templates/state_preparations/cosine_window.py
KetpuntoG Oct 20, 2023
d801f20
Update pennylane/templates/state_preparations/cosine_window.py
KetpuntoG Oct 20, 2023
b8c986d
Merge branch 'master' into cosine_window
KetpuntoG Oct 20, 2023
6581911
Merge branch 'master' into cosine_window
mudit2812 Oct 20, 2023
c5e368c
Merge branch 'master' into cosine_window
mudit2812 Oct 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
trbromley marked this conversation as resolved.
Show resolved Hide resolved
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions doc/introduction/templates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ state preparation is typically used as the first operation.
:description: :doc:`ArbitraryStatePreparation <../code/api/pennylane.ArbitraryStatePreparation>`
:figure: _static/templates/subroutines/arbitrarystateprep.png

.. gallery-item::
:description: :doc:`CosineWindow <../code/api/pennylane.CosineWindow>`
:figure: _static/templates/state_preparations/thumbnail_cosine_window.png

.. raw:: html

<div style='clear:both'></div>
Expand Down
21 changes: 21 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,26 @@
[(#4620)](https://github.com/PennyLaneAI/pennylane/pull/4620)
[(#4632)](https://github.com/PennyLaneAI/pennylane/pull/4632)

* `CosineWindow` has been added. Prepare the initial state following a cosine wave function.
[(#4683)](https://github.com/PennyLaneAI/pennylane/pull/4683)

trbromley marked this conversation as resolved.
Show resolved Hide resolved
```python
import pennylane as qml
import matplotlib.pyplot as plt

dev = qml.device('default.qubit', wires=4)

@qml.qnode(dev)
def example_circuit():
qml.CosineWindow(wires=range(4))
return qml.state()
output = example_circuit()

# Graph showing state amplitudes
plt.bar(range(len(output)), output)
plt.show()
```

<h3>Improvements 🛠</h3>

* `pennylane.devices.preprocess` now offers the transforms `decompose`, `validate_observables`, `validate_measurements`,
Expand Down Expand Up @@ -394,6 +414,7 @@

This release contains contributions from (in alphabetical order):

Guillermo Alonso,
Utkarsh Azad,
Stepan Fomichev,
Joana Fraxanet,
Expand Down
1 change: 1 addition & 0 deletions pennylane/templates/state_preparations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
from .basis import BasisStatePreparation
from .arbitrary_state_preparation import ArbitraryStatePreparation
from .basis_qutrit import QutritBasisStatePreparation
from .cosine_window import CosineWindow
134 changes: 134 additions & 0 deletions pennylane/templates/state_preparations/cosine_window.py
trbromley marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Copyright 2018-2021 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
r"""
Contains the CosineWindow template.
"""
import numpy as np
import pennylane as qml
from pennylane.operation import AnyWires, StatePrepBase
from pennylane.wires import Wires, WireError
from pennylane import math


class CosineWindow(StatePrepBase):
r"""CosineWindow(wires)
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
Prepare the initial state following a cosine wave function.
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

.. math::

|\psi\rangle = \sqrt{2^{1-m}} \sum_{k=0}^{2^m-1} \cos(\frac{\pi k}{2^m} - \frac{\pi}{2}) |k\rangle,

where :math:`m` is the number of wires.
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

.. figure:: ../../_static/templates/state_preparations/cosine_window.png
:align: center
:width: 65%
:target: javascript:void(0);

.. note::

The wave function is shifted by :math:`\frac{\pi}{2}` units so that the window is centered.
trbromley marked this conversation as resolved.
Show resolved Hide resolved


**Details:**

* Number of wires: Any (the operation can act on any number of wires)
* Number of parameters: 0
* Gradient recipe: None
soranjh marked this conversation as resolved.
Show resolved Hide resolved


Args:
wires (Sequence[int] or int): the wire(s) the operation acts on
id (str): custom label given to an operator instance,
can be useful for some applications where the instance has to be identified.
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

**Example**

KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
>>> dev = qml.device('default.qubit', wires=2)
>>> @qml.qnode(dev)
... def example_circuit():
... qml.CosineWindow(wires=range(2))
... return qml.probs()
>>> print(example_circuit())
[1.87469973e-33 2.50000000e-01 5.00000000e-01 2.50000000e-01]
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
"""
num_wires = AnyWires
num_params = 0
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
"""int: Number of trainable parameters that the operator depends on."""
soranjh marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, wires, id=None):
super().__init__(wires=wires, id=id)
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

@staticmethod
def compute_decomposition(
*args, wires, **kwargs
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
): # pylint: disable=arguments-differ,unused-argument
r"""Representation of the operator as a product of other operators (static method).
It is efficiently decomposed from one QFT over all qubits and one-qubit rotation gates.
soranjh marked this conversation as resolved.
Show resolved Hide resolved

Args:
wires (Iterable, Wires): the wire(s) the operation acts on

Returns:
list[Operator]: decomposition into lower level operations
"""

decomp_ops = []

decomp_ops.append(qml.Hadamard(wires=wires[-1]))
decomp_ops.append(qml.RZ(np.pi, wires=wires[-1]))
decomp_ops.append(qml.adjoint(qml.QFT)(wires=wires))

for ind, wire in enumerate(wires):
decomp_ops.append(qml.PhaseShift(np.pi * 2 ** (-ind - 1), wires=wire))

return decomp_ops

KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
def state_vector(self, wire_order=None):
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
num_op_wires = len(self.wires)
op_vector_shape = (2,) * num_op_wires
vector = np.array(
[
np.sqrt(2)
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
* np.cos(-np.pi / 2 + np.pi * x / 2 ** (num_op_wires))
/ np.sqrt(2**num_op_wires)
for x in range(2**num_op_wires)
]
)
op_vector = math.reshape(vector, op_vector_shape)

if wire_order is None or Wires(wire_order) == self.wires:
return op_vector

wire_order = Wires(wire_order)
if not wire_order.contains_wires(self.wires):
raise WireError(f"Custom wire_order must contain all {self.name} wires")

num_total_wires = len(wire_order)
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
indices = tuple(
[Ellipsis] + [slice(None)] * num_op_wires + [0] * (num_total_wires - num_op_wires)
)
ket_shape = [2] * num_total_wires

ket = np.zeros(ket_shape, dtype=np.complex128)
ket[indices] = op_vector
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

# unless wire_order is [*self.wires, *rest_of_wire_order], need to rearrange
if self.wires != wire_order[:num_op_wires]:
current_order = self.wires + list(Wires.unique_wires([wire_order, self.wires]))
desired_order = [current_order.index(w) for w in wire_order]

ket = ket.transpose(desired_order)

return math.convert_like(ket, op_vector)
107 changes: 107 additions & 0 deletions tests/templates/test_state_preparations/test_cosine_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Copyright 2018-2021 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Unit tests for the CosineWindow template.
"""
# pylint: disable=too-few-public-methods
import pytest
import numpy as np
import pennylane as qml
from pennylane.wires import WireError


class TestDecomposition:
soranjh marked this conversation as resolved.
Show resolved Hide resolved
"""Tests that the template defines the correct decomposition."""

def test_correct_gates_single_wire(self):
"""Test that the correct gates are applied."""

op = qml.CosineWindow(wires=[0])
queue = op.expand().operations
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

assert queue[0].name == "Hadamard"
assert queue[1].name == "RZ"
assert queue[2].name == "Adjoint(QFT)"
assert queue[3].name == "PhaseShift"

assert np.isclose(queue[3].data[0], np.pi / 2)

def test_correct_gates_many_wires(self):
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
"""Test that the correct gates are applied on on two wires."""
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

op = qml.CosineWindow(wires=[0, 1, 2, 3, 4])
queue = op.expand().operations
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

assert queue[0].name == "Hadamard"
assert queue[1].name == "RZ"
assert queue[2].name == "Adjoint(QFT)"

for ind, q in enumerate(queue[3:]):
assert q.name == "PhaseShift"
assert np.isclose(q.data[0], np.pi / 2 ** (ind + 1))

def test_custom_wire_labels(self):
"""Test that template can deal with non-numeric, nonconsecutive wire labels."""

dev = qml.device("default.qubit", wires=3)
dev2 = qml.device("default.qubit", wires=["z", "a", "k"])

@qml.qnode(dev)
def circuit():
qml.CosineWindow(wires=range(3))
return qml.expval(qml.Identity(0)), qml.state()

@qml.qnode(dev2)
def circuit2():
qml.CosineWindow(wires=["z", "a", "k"])
return qml.expval(qml.Identity("z")), qml.state()

res1, state1 = circuit()
res2, state2 = circuit2()

assert np.allclose(res1, res2)
assert np.allclose(state1, state2)


class TestInputs:
"""Test inputs and pre-processing."""
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

def test_id(self):
"""Tests that the id attribute can be set."""
template = qml.CosineWindow(wires=[0, 1, 2], id="a")
assert template.id == "a"


class TestStateVector:
"""Test the state_vector() method of various CosineWindow operations."""

def test_CosineWindow_state_vector(self):
"""Tests that the state vector is correct for a single wire."""
op = qml.CosineWindow(wires=[0])
res = op.state_vector()
expected = np.array([0.0, 1.0])
assert np.allclose(res, expected)

def test_CosineWindow_state_vector_bad_wire_order(self):
"""Tests that the provided wire_order must contain the wires in the operation."""
qsv_op = qml.CosineWindow(wires=[0, 1])
with pytest.raises(WireError, match="wire_order must contain all CosineWindow wires"):
qsv_op.state_vector(wire_order=[1, 2])

def test_CosineWindow_state_vector_wire_order(self):
"""Tests that the state vector works with a different order of wires."""
op = qml.CosineWindow(wires=[0, 1])
res = np.reshape(op.state_vector(wire_order=[1, 0]) ** 2, (-1,))
expected = np.array([0.0, 0.5, 0.25, 0.25])
assert np.allclose(res, expected)
Loading