Skip to content

Commit a395e3b

Browse files
kottmanjdavibinco
andauthored
Merge pull request #340 from tequilahub/kottmanj-update-1.9.5
* fixing syntax issue in post_init of dataclass (#327) * phoenics support dropped * more convenient randomization initialization for OO, avoiding numpy warnings * Update qasm.py (#334) Fixes issue #332 * added methods to create annihilation, creation, sz, sp, sm and s2 operators in qubit representation (#336) * Update qasm.py (#335) * Update ci_chemistry_psi4.yml (psi4 --> conda-forge channel) * orbital names are better tracked through transformations (#338) * keep basis info when re-initializing with mol.from_tequila * orbital-optimization gives back molecule in the original basis * more basis info (#339) --------- Co-authored-by: davibinco <[email protected]>
2 parents a547f3c + 5f6a43f commit a395e3b

File tree

9 files changed

+165
-48
lines changed

9 files changed

+165
-48
lines changed

Diff for: .github/workflows/ci_chemistry_psi4.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
runs-on: ubuntu-latest
1717
strategy:
1818
matrix:
19-
python-version: [3.8]
19+
python-version: [3.9]
2020

2121
steps:
2222
- uses: actions/checkout@v2
@@ -50,7 +50,7 @@ jobs:
5050
source $HOME/.bashrc
5151
source $CONDABASE/bin/activate
5252
conda activate test_psi4
53-
conda install psi4 python=3.8 -c psi4
53+
conda install psi4 python=3.9 -c conda-forge
5454
python -m pip install --upgrade pip
5555
python -m pip install -r requirements.txt
5656
python -m pip install -e .

Diff for: README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Tequila can execute the underlying quantum expectation values on state of the ar
1414
- [talks and slides](https://kottmanj.github.io/talks_and_material/)
1515

1616
# Installation
17-
Recommended Python version is 3.8-3.9.
17+
Recommended Python version is 3.9 - 3.10.
1818
Tequila supports linux, osx and windows. However, not all optional dependencies are supported on windows.
1919

2020
## Install from PyPi
@@ -275,7 +275,7 @@ Currently supported
275275
### [Psi4](https://github.com/psi4/psi4).
276276
In a conda environment this can be installed with
277277
```bash
278-
conda install psi4 -c psi4
278+
conda install psi4 -c conda-forge
279279
```
280280
Here is a small [tutorial](https://nbviewer.org/github/tequilahub/tequila-tutorials/blob/main/chemistry/ChemistryModule.ipynb) that illustrates the usage.
281281

Diff for: src/tequila/circuit/qasm.py

+25-11
Original file line numberDiff line numberDiff line change
@@ -313,19 +313,33 @@ def parse_command(command: str, custom_gates_map: Dict[str, QCircuit], qregister
313313
return apply_custom_gate(custom_circuit=custom_circuit, qregisters_values=qregisters_values)
314314

315315
if name in ("x", "y", "z", "h", "cx", "cy", "cz", "ch"):
316-
return QCircuit.wrap_gate(gates.impl.QGateImpl(name=(name[1] if name[0] == 'c' else name).upper(),
317-
control=get_qregister(args[0], qregisters) if name[0] == 'c' else None,
318-
target=get_qregister(args[1 if name[0] == 'c' else 0], qregisters)))
316+
target = get_qregister(args[0], qregisters)
317+
control = None
318+
if name[0].lower() == 'c':
319+
control = get_qregister(args[0], qregisters)
320+
target = get_qregister(args[1], qregisters)
321+
name = name[1]
322+
G = getattr(gates, name.upper())
323+
return G(control=control, target=target)
324+
319325
if name in ("ccx", "ccy", "ccz"):
320-
return QCircuit.wrap_gate(gates.impl.QGateImpl(name=name.upper()[2],
321-
control=[get_qregister(args[0], qregisters), get_qregister(args[1], qregisters)],
322-
target=get_qregister(args[2], qregisters)))
326+
G = getattr(gates, name[2].upper())
327+
control = [get_qregister(args[0], qregisters), get_qregister(args[1], qregisters)]
328+
target = get_qregister(args[2], qregisters)
329+
return G(control=control, target=target)
330+
323331
if name.startswith("rx(") or name.startswith("ry(") or name.startswith("rz(") or \
324332
name.startswith("crx(") or name.startswith("cry(") or name.startswith("crz("):
325-
return QCircuit.wrap_gate(gates.impl.RotationGateImpl(axis=name[2 if name[0] == 'c' else 1],
326-
angle=get_angle(name)[0],
327-
control=get_qregister(args[0], qregisters) if name[0] == 'c' else None,
328-
target=get_qregister(args[1 if name[0] == 'c' else 0], qregisters)))
333+
angle = get_angle(name)[0]
334+
i = name.find('(')
335+
name = name[0:i]
336+
name = name.upper()
337+
name = [x for x in name]
338+
name[-1] = name[-1].lower()
339+
name = "".join(name)
340+
G = getattr(gates, name)
341+
return G(angle=angle,control=get_qregister(args[0], qregisters) if name[0] == 'C' else None,target=get_qregister(args[1 if name[0] == 'C' else 0], qregisters))
342+
329343
if name.startswith("U("):
330344
angles = get_angle(name)
331345
return gates.U(theta=angles[0], phi=angles[1], lambd=angles[2],
@@ -362,7 +376,7 @@ def parse_command(command: str, custom_gates_map: Dict[str, QCircuit], qregister
362376
control=get_qregister(args[0], qregisters),
363377
target=get_qregister(args[1], qregisters))
364378
if name in ("s", "t", "sdg", "tdg"):
365-
g = gates.Phase(pi / (2 if name.startswith("s") else 4),
379+
g = gates.Phase(angle=pi / (2 if name.startswith("s") else 4),
366380
control=None,
367381
target=get_qregister(args[0], qregisters))
368382
if name.find("dg") != -1:

Diff for: src/tequila/quantumchemistry/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ def Molecule(geometry: str = None,
9595
if backend is None:
9696
if basis_set is None or basis_set.lower() in ["madness", "mra", "pno"]:
9797
backend = "madness"
98+
basis_set = "mra"
99+
parameters.basis_set = basis_set
98100
if orbital_type is not None and orbital_type.lower() not in ["pno", "mra-pno"]:
99101
warnings.warn("only PNOs supported as orbital_type without basis set. Setting to pno - You gave={}".format(orbital_type), TequilaWarning)
100102
orbital_type = "pno"

Diff for: src/tequila/quantumchemistry/chemistry_tools.py

+24-13
Original file line numberDiff line numberDiff line change
@@ -804,20 +804,18 @@ class IntegralManager:
804804
_one_body_integrals: numpy.ndarray = None
805805
_two_body_integrals: NBodyTensor = None
806806
_constant_term: float = None
807-
_basis_type: str = "unknown"
808807
_basis_name: str = "unknown"
809808
_orbital_type: str = "unknown" # e.g. "HF", "PNO", "native"
810809
_orbital_coefficients: numpy.ndarray = None
811810
_active_space: ActiveSpaceData = None
812811
_orbitals: typing.List[OrbitalData] = None
813812

814-
def __init__(self, one_body_integrals, two_body_integrals, basis_type="custom",
813+
def __init__(self, one_body_integrals, two_body_integrals,
815814
basis_name="unknown", orbital_type="unknown",
816815
constant_term=0.0, orbital_coefficients=None, active_space=None, overlap_integrals=None, orbitals=None, *args, **kwargs):
817816
self._one_body_integrals = one_body_integrals
818817
self._two_body_integrals = two_body_integrals
819818
self._constant_term = constant_term
820-
self._basis_type = basis_type
821819
self._basis_name = basis_name
822820
self._orbital_type = orbital_type
823821

@@ -956,9 +954,16 @@ def transform_to_native_orbitals(self):
956954
"""
957955
c = self.get_orthonormalized_orbital_coefficients()
958956
self.orbital_coefficients=c
959-
self._orbital_type="orthonormalized-{}-basis".format(self._orbital_type)
957+
self._orbital_type="orthonormalized-{}-basis".format(self._basis_name)
960958

961-
def transform_orbitals(self, U):
959+
def is_unitary(self, U):
960+
if len(U.shape) != 2: return False
961+
if U.shape[0] != U.shape[1]: return False
962+
test = (U.conj().T).dot(U) - numpy.eye(U.shape[0])
963+
if not numpy.isclose(numpy.linalg.norm(test), 0.0): return False
964+
return True
965+
966+
def transform_orbitals(self, U, name=None):
962967
"""
963968
Transform orbitals
964969
Parameters
@@ -969,10 +974,12 @@ def transform_orbitals(self, U):
969974
-------
970975
updates the structure with new orbitals: c = cU
971976
"""
972-
c = self.orbital_coefficients
973-
c = numpy.einsum("ix, xj -> ij", c, U, optimize="greedy")
974-
self.orbital_coefficients = c
975-
self._orbital_type += "-transformed"
977+
assert self.is_unitary(U)
978+
self.orbital_coefficients = numpy.einsum("ix, xj -> ij", self.orbital_coefficients, U, optimize="greedy")
979+
if name is None:
980+
self._orbital_type += "-transformed"
981+
else:
982+
self._orbital_type = name
976983

977984
def get_integrals(self, orbital_coefficients=None, ordering="openfermion", ignore_active_space=False, *args, **kwargs):
978985
"""
@@ -1001,7 +1008,9 @@ def get_integrals(self, orbital_coefficients=None, ordering="openfermion", ignor
10011008
active_integrals = get_active_space_integrals(one_body_integrals=h, two_body_integrals=g,
10021009
occupied_indices=self._active_space.frozen_reference_orbitals,
10031010
active_indices=self._active_space.active_orbitals)
1011+
10041012
c = active_integrals[0] + c
1013+
10051014
h = active_integrals[1]
10061015
g = NBodyTensor(elems=active_integrals[2], ordering="openfermion")
10071016
g.reorder(to=ordering)
@@ -1069,14 +1078,16 @@ def __str__(self):
10691078
result += str(x) + "\n"
10701079
return result
10711080

1072-
def print_basis_info(self, *args, **kwargs) -> None:
1073-
print("{:15} : {}".format("basis_type", self._basis_type), *args, **kwargs)
1081+
def print_basis_info(self, print_coefficients=True, *args, **kwargs) -> None:
10741082
print("{:15} : {}".format("basis_name", self._basis_name), *args, **kwargs)
10751083
print("{:15} : {}".format("orbital_type", self._orbital_type), *args, **kwargs)
1076-
print("{:15} : {}".format("orthogonal", self.basis_is_orthogonal()), *args, **kwargs)
1077-
print("{:15} : {}".format("functions", self.one_body_integrals.shape[0]), *args, **kwargs)
1084+
print("{:15} : {}".format("orthogonal basis", self.basis_is_orthogonal()), *args, **kwargs)
1085+
print("{:15} : {}".format("basis functions", self.one_body_integrals.shape[0]), *args, **kwargs)
1086+
print("{:15} : {}".format("active orbitals", [o.idx_total for o in self.active_orbitals]), *args, **kwargs)
10781087
print("{:15} : {}".format("reference", [x.idx_total for x in self.reference_orbitals]), *args, **kwargs)
10791088

1089+
if not print_coefficients: return
1090+
10801091
print("Current Orbitals", *args, **kwargs)
10811092
for i,x in enumerate(self.orbitals):
10821093
print(x, *args, **kwargs)

Diff for: src/tequila/quantumchemistry/orbital_optimizer.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def __call__(self, local_data, *args, **kwargs):
3737
self.iterations += 1
3838

3939
def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=None, silent=False,
40-
vqe_solver_arguments=None, initial_guess=None, return_mcscf=False, use_hcb=False, molecule_factory=None, molecule_arguments=None, *args, **kwargs):
40+
vqe_solver_arguments=None, initial_guess=None, return_mcscf=False, use_hcb=False, molecule_factory=None, molecule_arguments=None, restrict_to_active_space=True, *args, **kwargs):
4141
"""
4242
4343
Parameters
@@ -78,7 +78,12 @@ def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=N
7878
if pyscf_arguments is None:
7979
pyscf_arguments = {"max_cycle_macro": 10, "max_cycle_micro": 3}
8080
no = molecule.n_orbitals
81-
pyscf_molecule = QuantumChemistryPySCF.from_tequila(molecule=molecule, transformation=molecule.transformation)
81+
82+
if not isinstance(molecule, QuantumChemistryPySCF):
83+
pyscf_molecule = QuantumChemistryPySCF.from_tequila(molecule=molecule, transformation=molecule.transformation)
84+
else:
85+
pyscf_molecule = molecule
86+
8287
mf = pyscf_molecule._get_hf()
8388
result=OptimizeOrbitalsResult()
8489
mc = mcscf.CASSCF(mf, pyscf_molecule.n_orbitals, pyscf_molecule.n_electrons)
@@ -140,10 +145,11 @@ def optimize_orbitals(molecule, circuit=None, vqe_solver=None, pyscf_arguments=N
140145
mc.kernel()
141146
# make new molecule
142147

143-
transformed_molecule = pyscf_molecule.transform_orbitals(orbital_coefficients=mc.mo_coeff)
148+
mo_coeff = mc.mo_coeff
149+
transformed_molecule = pyscf_molecule.transform_orbitals(orbital_coefficients=mo_coeff, name="optimized")
144150
result.molecule=transformed_molecule
145151
result.old_molecule=molecule
146-
result.mo_coeff=mc.mo_coeff
152+
result.mo_coeff=mo_coeff
147153
result.energy=mc.e_tot
148154

149155
if return_mcscf:

Diff for: src/tequila/quantumchemistry/pyscf_interface.py

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def __init__(self, parameters: ParametersQC,
7575
kwargs["two_body_integrals"] = g_ao
7676
kwargs["one_body_integrals"] = h_ao
7777
kwargs["orbital_coefficients"] = mo_coeff
78+
kwargs["orbital_type"] = "hf"
7879

7980
if "nuclear_repulsion" not in kwargs:
8081
kwargs["nuclear_repulsion"] = mol.energy_nuc()

0 commit comments

Comments
 (0)