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

Majorana pool #114

Merged
merged 6 commits into from
Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
6 changes: 4 additions & 2 deletions tangelo/algorithms/variational/adapt_vqe_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ADAPTSolver:
pool (func): Function that returns a list of FermionOperator. Each
element represents excitation/operator that has an effect of the
total energy.
pool_args (tuple) : The arguments for the pool function given as a
pool_args (tuple or dict) : The arguments for the pool function given as a
Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. I think you can just say "The arguments for the pool function" as the type is already clear in the docs.

  2. It is not obvious why you're choosing to extend the functionality here. What was the rationale behind supporting dictionaries? Ideally I'd pick one or the other, and stay pythonic: one way to do things (and less code to maintain). If you have an opinion about what we should keep, that would be great.

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 changed the type required to dictionary. I added the functionality because the get_majorana_uccgsd_pool function requires either a SecondQuantizedMolecule or n_sos. If left as a tuple, it would require the user to supply (None, number_of_spin_orbitals) to use the latter choice. The dictionary would be {"n_sos": number_of_spin_orbitals}.

tuple.
qubit_mapping (str): One of the supported qubit mapping identifiers.
qubit_hamiltonian (QubitOperator-like): Self-explanatory.
Expand Down Expand Up @@ -174,7 +174,9 @@ def build(self):
else:
raise KeyError('pool_args must be defined if using own pool function')
# Check if pool function returns a QubitOperator or FermionOperator and populate variables
pool_list = self.pool(*self.pool_args)
if not isinstance(self.pool_args, (dict, tuple)):
raise ValueError("pool_args must be a tuple or a dictionary")
pool_list = self.pool(*self.pool_args) if isinstance(self.pool_args, tuple) else self.pool(**self.pool_args)
if isinstance(pool_list[0], QubitOperator):
self.pool_type = 'qubit'
self.pool_operators = pool_list
Expand Down
18 changes: 17 additions & 1 deletion tangelo/algorithms/variational/tests/test_adapt_vqe_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import unittest

from tangelo.algorithms.variational import ADAPTSolver
from tangelo.molecule_library import mol_H2_sto3g
from tangelo.molecule_library import mol_H2_sto3g, xyz_H4
from tangelo.toolboxes.ansatz_generator._unitary_majorana_cc import majorana_uccgsd_list
from tangelo.toolboxes.molecular_computation.molecule import SecondQuantizedMolecule


class ADAPTSolverTest(unittest.TestCase):
Expand Down Expand Up @@ -54,6 +56,20 @@ def test_single_cycle_adapt(self):
"vqe_variational_parameters": 1}
self.assertEqual(adapt_solver.get_resources(), resources)

def test_multiple_cycle_adapt_majorana_pool(self):
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
"""Solve H4 with one frozen orbtial with ADAPTSolver using 4 cycles and a operators chosen
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
from a Majorana UCCGSD pool
"""

mol = SecondQuantizedMolecule(xyz_H4, 0, 0, "sto-3g", frozen_orbitals=[0])
opt_dict = {"molecule": mol, "max_cycles": 4, "verbose": False, "pool": majorana_uccgsd_list,
"pool_args": {"n_sos": mol.n_active_sos}}
adapt_solver = ADAPTSolver(opt_dict)
adapt_solver.build()
adapt_solver.simulate()

self.assertAlmostEqual(adapt_solver.optimal_energy, -1.8945, places=3)


if __name__ == "__main__":
unittest.main()
97 changes: 97 additions & 0 deletions tangelo/toolboxes/ansatz_generator/_unitary_majorana_cc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Copyright 2021 Good Chemistry Company.
#
# 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.

"""Utililty functions to generate pool of FermionOperators obtained from individual MajoranaOperators in
unitary coupled cluster expansions."""

from openfermion.transforms.opconversions.conversions import get_fermion_operator
from openfermion import MajoranaOperator
from numpy import integer

from tangelo.toolboxes.molecular_computation.molecule import SecondQuantizedMolecule


def majorana_uccsd_list(molecule: SecondQuantizedMolecule = None, n_electrons: int = None, n_sos: int = None):
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
"""Construct a list of FermionOperator corresponding to the individual Majorana modes in the UCCSD ansatz

Args:
molecule (SecondQuantizedMolecule): The molecule to generate the Majorana pool from: Default None
n_electrons (int): The number of active electrons: Default None
n_sos (int): The number of active spin orbitals: Default None

Returns:
list: The list of FermionOperator for each Majorana operator in a UCCD pool"""

if molecule is not None:
n_active_electrons = molecule.n_active_electrons
n_active_sos = molecule.n_active_sos
elif isinstance(n_electrons, (int, integer)) and isinstance(n_sos, (int, integer)):
n_active_electrons = n_electrons
n_active_sos = n_sos
else:
raise ValueError("SecondQuantized mol or ints n_electrons/n_sos must be provided")

def majorana_uccsd_generator():
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
for i in range(n_active_electrons):
for k in range(n_active_electrons, n_active_sos):
yield (2*i, 2*k)
yield (2*i+1, 2*k+1)
for j in range(i+1, n_active_electrons):
for l in range(k+1, n_active_sos):
yield (2*i, 2*j+1, 2*k+1, 2*l+1)
yield (2*i+1, 2*j, 2*k+1, 2*l+1)
yield (2*i+1, 2*j+1, 2*k, 2*l+1)
yield (2*i+1, 2*j+1, 2*k+1, 2*l)
yield (2*i+1, 2*j, 2*k, 2*l)
yield (2*i, 2*j+1, 2*k, 2*l)
yield (2*i, 2*j, 2*k+1, 2*l)
yield (2*i, 2*j, 2*k, 2*l+1)
pool_list = [get_fermion_operator(MajoranaOperator(term)) for term in majorana_uccsd_generator()]
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
return pool_list


def majorana_uccgsd_list(molecule: SecondQuantizedMolecule = None, n_sos: int = None):
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
"""Construct a list of FermionOperator corresponding to the individual Majorana modes in the UCCGSD ansatz

Args:
molecule (SecondQuantizedMolecule): The molecule to generate the Majorana pool from: Default None
n_sos (int): The number of active spin orbitals: Default None

Returns:
list: The list of FermionOperator for each Majorana operator in a UCCD pool"""
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved

if molecule is not None:
n_active_sos = molecule.n_active_sos
elif isinstance(n_sos, (int, integer)):
n_active_sos = n_sos
else:
raise ValueError("SecondQuantized mol or int n_sos must be provided")

def majorana_uccgsd_generator():
for i in range(n_active_sos):
for j in range(i+1, n_active_sos):
yield (2*i, 2*j)
yield (2*i+1, 2*j+1)
for k in range(j+1, n_active_sos):
for l in range(k+1, n_active_sos):
yield (2*i, 2*j+1, 2*k+1, 2*l+1)
yield (2*i+1, 2*j, 2*k+1, 2*l+1)
yield (2*i+1, 2*j+1, 2*k, 2*l+1)
yield (2*i+1, 2*j+1, 2*k+1, 2*l)
yield (2*i+1, 2*j, 2*k, 2*l)
yield (2*i, 2*j+1, 2*k, 2*l)
yield (2*i, 2*j, 2*k+1, 2*l)
yield (2*i, 2*j, 2*k, 2*l+1)
pool_list = [get_fermion_operator(MajoranaOperator(term)) for term in majorana_uccgsd_generator()]
JamesB-1qbit marked this conversation as resolved.
Show resolved Hide resolved
return pool_list