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

Add GateFabric Template #1687

Merged
merged 36 commits into from
Oct 1, 2021

Conversation

obliviateandsurrender
Copy link
Contributor

Context:
This is the second part of the PRs aimed at adding the GateFabric template, which is based on the local, expressive, and quantum number preserving ansatz presented in arXiv:2104.05695.

Description of the Change:
Function GateFabric provides the implementation for the quantum number preserving gate fabric.
Relevant UnitTests and init definitions for GateFabric operation.

Benefits:
This will expand the current set of Pennylane's templates with a new local and expressive VQE circuit fabric.

Possible Drawbacks:
No specific drawbacks.

Related GitHub Issues:
No related issues.

@@ -1127,3 +1127,69 @@ def basic_entangler_layers_uniform(n_layers, n_wires, low=0, high=2 * pi, seed=N
params = np.random.uniform(low=low, high=high, size=(n_layers, n_wires))

return params


def gate_fabric_uniform(n_layers, n_wires, low=0, high=2 * pi, seed=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh @obliviateandsurrender we haven't done a very good job of documenting it, but the init module is deprecated! Instead of adding new functions here, the preferred approach is to have a shape method on the template itself:

>>> shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=3, n_wires=2)
>>> np.random.random(shape)
array([[[0.48715978, 0.24741362, 0.19435542],
        [0.54890558, 0.58210102, 0.98678809]],

       [[0.43263127, 0.09268041, 0.4359657 ],
        [0.34308469, 0.79198242, 0.81406353]],

       [[0.80658304, 0.45946463, 0.66767815],
        [0.75200523, 0.46483252, 0.02140596]]])

This has the advantage that we don't need to wrap NumPy's random module, worry about seeds, etc.

Also tagging @antalszava and @mariaschuld here for visibility; we should decide if we remove/fully deprecate this module.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @josh146! I am sorry I did not know about init module's depreciation. Anyhow, I already had included the shape method in GateFabric template. I have now removed the previously added functions from the init.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries at all, the PennyLane documentation was not clear as to the status of the init module 🙂 This is something we should address

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe for now we can just add a note in the docstring and/or remove it from the documentation and all tutorials? So it would still work, but people won't find it or add to it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Let's also add it to one of our upcoming deprecation cycles @antalszava, so that we don't forget about it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started a PR here...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to summarize, would the following sound good?

  • v0.19.0 (next release):
    • The init module is still available, but not advertised in the docs and a deprecation warning has been added as per Deprecate init module #1689
    • Demos don't use the init module anymore
  • v0.20.0: the init module is completely removed from PennyLane

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good to me :+1;

"""
num_params = 1
num_wires = AnyWires
par_domain = "A"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@obliviateandsurrender is there a known gradient recipe for this gate? If not, best to have grad_method=None

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added the grad_method=None. I am assuming that by gate you meant the overall unitary block made by the template and not the gates (OrbitalRotation and DoubleExcitation) it is composed of because for them four-term parameter-shift rule exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, would you have an idea about why in Tests/core-tests(3.8, tf, torch, jax), the tests TestPassthruIntegration::test_prob_differentiability and TestPassthruIntegration::test_backprop_gradient are failing? I am unable to replicate the error in my local machine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added the grad_method=None. I am assuming that by gate you meant the overall unitary block made by the template and not the gates (OrbitalRotation and DoubleExcitation) it is composed of because for them four-term parameter-shift rule exists.

Yep, exactly 👍

I am unable to replicate the error in my local machine.

Oh this is very interesting, the same thing was happening to me in my PR yesterday: #1685. It must be related either to:

  • A new release of JAX?
  • A change in master that has affected the test suite

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to have been a new release of JAX made on the 24th of September: https://pypi.org/project/jax/#history

Perhaps this is the cause

Copy link
Contributor

@antalszava antalszava Sep 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can confirm that this is it after checking locally. 🙂 Let me open a PR.

@codecov
Copy link

codecov bot commented Sep 27, 2021

Codecov Report

Merging #1687 (fa9e701) into master (dc98462) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #1687   +/-   ##
=======================================
  Coverage   99.21%   99.21%           
=======================================
  Files         202      203    +1     
  Lines       15253    15300   +47     
=======================================
+ Hits        15133    15180   +47     
  Misses        120      120           
Impacted Files Coverage Δ
pennylane/templates/layers/__init__.py 100.00% <100.00%> (ø)
pennylane/templates/layers/gate_fabric.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dc98462...fa9e701. Read the comment docs.

ansatz = partial(GateFabric, init_state=ref_state, include_pi=True)

# Define the cost function
cost_fn = qml.ExpvalCost(ansatz, h, dev)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might consider having an example that works with expval(H).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have changed the example now with one with expval(H).

assert res_wires == exp_wires

@pytest.mark.parametrize(
("init_state", "exp_state"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How the exp_state is computed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I compute them manually with the first matrix multiplication of the gates and then cross-check them with a manually decomposed version of GateFabric.

],
)
def test_decomposition_q(self, init_state, exp_state, tol):
"""Test the decomposition of the Q_{theta, phi}` exchange gate by asserting the prepared
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be changed to :math:Q_{theta, phi}. Is it just a general decomposition test? (what is Q exchange gate?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, fixed it. This is just to test correctness of Q gate (removed the word exchange) which makes up the GateFabric template.

print(init_state, exp_state)

@qml.qnode(dev)
def circuit(weight):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any test for n_layer > 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added two new tests for n_layers > 1.

Copy link
Contributor

@ixfoduap ixfoduap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code and tests look amazing! Great job!

I left several comments on the docstrings and I would like to consider improving the header image.

# See the License for the specific language governing permissions and
# limitations under the License.
r"""
Contains the quantum number preserving GateFabric template.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Contains the quantum number preserving GateFabric template.
Contains the quantum-number-preserving GateFabric template.

Comment on lines 24 to 25
r"""Implements a local, expressive, and quantum-number-preserving ansatz using VQE circuit fabrics
proposed by Anselmetti *et al.* in `arXiv:2104.05692 <https://arxiv.org/abs/2104.05695>`_.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
r"""Implements a local, expressive, and quantum-number-preserving ansatz using VQE circuit fabrics
proposed by Anselmetti *et al.* in `arXiv:2104.05692 <https://arxiv.org/abs/2104.05695>`_.
r"""Implements a local, expressive, and quantum-number-preserving ansatz
proposed by Anselmetti *et al.* in `arXiv:2104.05692 <https://arxiv.org/abs/2104.05695>`_.

Comment on lines 27 to 28
This template prepares the :math:`N` qubits trial state by applying :math:`D` layers of gate fabric block
:math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` to the Hartree-Fock state in the Jordan-Wigner basis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This template prepares the :math:`N` qubits trial state by applying :math:`D` layers of gate fabric block
:math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` to the Hartree-Fock state in the Jordan-Wigner basis
This template prepares the :math:`N`-qubit trial state by applying :math:`D` layers of gate-fabric blocks
:math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` to the Hartree-Fock state in the Jordan-Wigner basis

\vert \Psi(\vec{\theta},\vec{\phi})\rangle =
\hat{U}_{GF}^{(D)}(\vec{\theta}_{D},\vec{\phi}_{D}) \ldots
\hat{U}_{GF}^{(2)}(\vec{\theta}_{2},\vec{\phi}_{2})
\hat{U}_{GF}^{(1)}(\vec{\theta}_{1},\vec{\phi}_{1}) \vert HF \rangle
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
\hat{U}_{GF}^{(1)}(\vec{\theta}_{1},\vec{\phi}_{1}) \vert HF \rangle
\hat{U}_{GF}^{(1)}(\vec{\theta}_{1},\vec{\phi}_{1}) \vert HF \rangle,

\hat{U}_{GF}^{(2)}(\vec{\theta}_{2},\vec{\phi}_{2})
\hat{U}_{GF}^{(1)}(\vec{\theta}_{1},\vec{\phi}_{1}) \vert HF \rangle

where each of the gate fabric block :math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` comprises of 2-parameter 4-qubit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
where each of the gate fabric block :math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` comprises of 2-parameter 4-qubit
where each of the gate fabric blocks :math:`\hat{U}_{GF}(\vec{\theta},\vec{\phi})` is comprised of two-parameter four-qubit

.. UsageDetails::

#. The number of wires :math:`N` has to be equal to the number of
spin orbitals included in the active space, and should be even.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
spin orbitals included in the active space, and should be even.
spin-orbitals included in the active space, and should be even.

weights = np.random.random(size=shape)

>>> weights.shape
(2, 1, 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent usage details! Great job!


def __init__(self, weights, wires, init_state, include_pi=False, do_queue=True, id=None):

if len(wires) < 4:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great check!

)
if len(wires) % 2:
raise ValueError(
f"This template requires even number of qubits; got {len(wires)} wires"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
f"This template requires even number of qubits; got {len(wires)} wires"
f"This template requires an even number of qubits; got {len(wires)} wires"

par_domain = "A"
grad_method = None

def __init__(self, weights, wires, init_state, include_pi=False, do_queue=True, id=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the include_pi approach 👍

@obliviateandsurrender
Copy link
Contributor Author

@ixfoduap I have incorporated all the requested changes in the docstrings, header, and have included a VQE usage example in the changelog. Let me know if the header image needs to be more colorful.

Copy link
Contributor

@ixfoduap ixfoduap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

Just wondering if the entry in the changelog may be a bit too long


```python
coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614])
H, qubits = qml.qchem.molecular_hamiltonian(symbols = ["H", "H"], coordinates)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
H, qubits = qml.qchem.molecular_hamiltonian(symbols = ["H", "H"], coordinates)
H, qubits = qml.qchem.molecular_hamiltonian(["H", "H"], coordinates)

I think this should work, but good to double-check

Final value of the ground-state energy = -1.13618883 Ha

Optimal value of the circuit parameters = [[[ 0.58835515 0.40801101]]
[[ 0.83842218 -0.24228264]]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great entry to the changelog, but I wonder if it is too long for our usual standards. Any thoughts @josh146 @antalszava?

If we agree it's too long, you can just end it on line 234 where the circuit is defined

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, agree it is a great changelog entry, but potentially too much information. I suggest truncating at line 234. You can then have something such as

For more details, see the [GateFabric documentation](url).

You could even take the training example here, and add it to the GateFabric docstring under .. UsageDetails::!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have truncated the changelog entry as requested and have shifted the VQE usage example to .. UsageDetails::.

@ixfoduap ixfoduap merged commit 6ffdba4 into PennyLaneAI:master Oct 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants