From fb4fc42efdd582a003a11e90d5153180b6d639e6 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 16 Oct 2020 16:34:18 +0200 Subject: [PATCH 01/22] make chemistry initial states circuits --- .../chemistry/components/initial_states/hf.py | 112 ++++++++++++++++++ .../components/initial_states/vscf.py | 83 +++---------- 2 files changed, 131 insertions(+), 64 deletions(-) create mode 100644 qiskit/chemistry/components/initial_states/hf.py diff --git a/qiskit/chemistry/components/initial_states/hf.py b/qiskit/chemistry/components/initial_states/hf.py new file mode 100644 index 0000000000..5b7dd1e4f7 --- /dev/null +++ b/qiskit/chemistry/components/initial_states/hf.py @@ -0,0 +1,112 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Hartree-Fock initial state.""" + +from typing import Optional, Union, List, Tuple +import warnings +import logging +import numpy as np +from qiskit import QuantumRegister, QuantumCircuit +from qiskit.aqua.utils.validation import validate_min, validate_in_set + +logger = logging.getLogger(__name__) + + +class HartreeFock(QuantumCircuit): + """A Hartree-Fock initial state.""" + + def __init__(self, + num_orbitals: int, + num_particles: Union[Tuple[int, int], int], + qubit_mapping: str = 'parity', + two_qubit_reduction: bool = True, + sq_list: Optional[List[int]] = None) -> None: + """ + Args: + num_orbitals: number of spin orbitals, has a min. value of 1. + num_particles: number of particles, if it is a list, the first number + is alpha and the second number if beta. + qubit_mapping: mapping type for qubit operator + two_qubit_reduction: flag indicating whether or not two qubit is reduced + sq_list: position of the single-qubit operators that + anticommute with the cliffords + """ + # validate the input + validate_min('num_orbitals', num_orbitals, 1) + validate_in_set('qubit_mapping', qubit_mapping, + {'jordan_wigner', 'parity', 'bravyi_kitaev'}) + + if qubit_mapping != 'parity' and two_qubit_reduction: + warnings.warn('two_qubit_reduction only works with parity qubit mapping ' + 'but you have %s. We switch two_qubit_reduction ' + 'to False.', qubit_mapping) + two_qubit_reduction = False + + # get the bitstring encoding the Hartree Fock state + bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, + two_qubit_reduction, sq_list) + + # construct the circuit + qr = QuantumRegister(len(bitstr), 'q') + super().__init__(qr, name='HF') + + # add gates in the right positions + for i, bit in enumerate(reversed(bitstr)): + if bit: + self.x(i) + + +def _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction=True, + sq_list=None): + if isinstance(num_particles, tuple): + num_alpha, num_beta = num_particles + else: + logger.info('We assume that the number of alphas and betas are the same.') + num_alpha = num_beta = num_particles // 2 + + num_particles = num_alpha + num_beta + + if num_particles > num_orbitals: + raise ValueError('# of particles must be less than or equal to # of orbitals.') + + half_orbitals = num_orbitals // 2 + bitstr = np.zeros(num_orbitals, np.bool) + bitstr[-num_alpha:] = True + bitstr[-(half_orbitals + num_beta):-half_orbitals] = True + + if qubit_mapping == 'parity': + new_bitstr = bitstr.copy() + + t_r = np.triu(np.ones((num_orbitals, num_orbitals))) + new_bitstr = t_r.dot(new_bitstr.astype(np.int)) % 2 # pylint: disable=no-member + + bitstr = np.append(new_bitstr[1:half_orbitals], new_bitstr[half_orbitals + 1:]) \ + if two_qubit_reduction else new_bitstr + + elif qubit_mapping == 'bravyi_kitaev': + binary_superset_size = int(np.ceil(np.log2(num_orbitals))) + beta = 1 + basis = np.asarray([[1, 0], [0, 1]]) + for _ in range(binary_superset_size): + beta = np.kron(basis, beta) + beta[0, :] = 1 + start_idx = beta.shape[0] - num_orbitals + beta = beta[start_idx:, start_idx:] + new_bitstr = beta.dot(bitstr.astype(int)) % 2 + bitstr = new_bitstr.astype(np.bool) + + if sq_list is not None: + sq_list = (len(bitstr) - 1) - np.asarray(sq_list) + bitstr = np.delete(bitstr, sq_list) + + return bitstr.astype(np.bool) diff --git a/qiskit/chemistry/components/initial_states/vscf.py b/qiskit/chemistry/components/initial_states/vscf.py index 6bc50f2a88..f614f52c90 100644 --- a/qiskit/chemistry/components/initial_states/vscf.py +++ b/qiskit/chemistry/components/initial_states/vscf.py @@ -10,21 +10,14 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -""" Initial state for vibrational modes. """ +"""Initial state for vibrational modes.""" -import logging from typing import List - import numpy as np - from qiskit import QuantumRegister, QuantumCircuit -from qiskit.aqua.components.initial_states import InitialState - -logger = logging.getLogger(__name__) - -class VSCF(InitialState): +class VSCF(QuantumCircuit): r""" Initial state for vibrational modes. Creates an occupation number vector as defined in @@ -39,64 +32,26 @@ def __init__(self, basis: List[int]) -> None: with 4 modals per mode basis = [4,4,4] """ super().__init__() - self._basis = basis - self._num_qubits = sum(basis) - - self._bitstr = self._build_bitstr() - - def _build_bitstr(self) -> np.ndarray: - bitstr = np.zeros(self._num_qubits, np.bool) - count = 0 - for i in range(len(self._basis)): - bitstr[self._num_qubits-count-1] = True - count += self._basis[i] + # get the bitstring encoding initial state + bitstr = _build_bitstr(basis) - return bitstr + # construct the circuit + qr = QuantumRegister(len(bitstr), 'q') + super().__init__(qr, name='VSCF') - def construct_circuit(self, mode: str = 'circuit', register: QuantumRegister = None) \ - -> QuantumCircuit: - """ - Construct the circuit of desired initial state. - - Args: - mode: `vector` or `circuit`. The `vector` mode produces the vector. - While the `circuit` constructs the quantum circuit corresponding that vector. - register (QuantumRegister): register for circuit construction. + # add gates in the right positions + for i, bit in enumerate(reversed(bitstr)): + if bit: + self.x(i) - Returns: - QuantumCircuit or numpy.ndarray: statevector. - Raises: - ValueError: when mode is not 'vector' or 'circuit'. - """ - if self._bitstr is None: - self._build_bitstr() - if mode == 'vector': - state = 1.0 - one = np.asarray([0.0, 1.0]) - zero = np.asarray([1.0, 0.0]) - for k in self._bitstr[::-1]: - state = np.kron(one if k else zero, state) - return state - elif mode == 'circuit': - if register is None: - register = QuantumRegister(self._num_qubits, name='q') - quantum_circuit = QuantumCircuit(register) - for qubit_idx, bit in enumerate(self._bitstr[::-1]): - if bit: - quantum_circuit.x(register[qubit_idx]) - return quantum_circuit - else: - raise ValueError('Mode should be either "vector" or "circuit"') - - @property - def bitstr(self) -> np.ndarray: - """Getter of the bit string represented the statevector. +def _build_bitstr(basis): + num_qubits = sum(basis) + bitstr = np.zeros(num_qubits, np.bool) + count = 0 + for modal in basis: + bitstr[num_qubits - count - 1] = True + count += modal - Returns: - numpy.ndarray containing the bitstring representation - """ - if self._bitstr is None: - self._build_bitstr() - return self._bitstr + return bitstr From 26299e71996b1a55c4e79e76c48fcd48f8197b2c Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 16 Oct 2020 17:52:19 +0200 Subject: [PATCH 02/22] put VSCF circuit in new file --- .../components/initial_states/vscf.py | 83 ++++++++++++++----- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/qiskit/chemistry/components/initial_states/vscf.py b/qiskit/chemistry/components/initial_states/vscf.py index f614f52c90..6bc50f2a88 100644 --- a/qiskit/chemistry/components/initial_states/vscf.py +++ b/qiskit/chemistry/components/initial_states/vscf.py @@ -10,14 +10,21 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Initial state for vibrational modes.""" +""" Initial state for vibrational modes. """ +import logging from typing import List + import numpy as np + from qiskit import QuantumRegister, QuantumCircuit +from qiskit.aqua.components.initial_states import InitialState + +logger = logging.getLogger(__name__) -class VSCF(QuantumCircuit): + +class VSCF(InitialState): r""" Initial state for vibrational modes. Creates an occupation number vector as defined in @@ -32,26 +39,64 @@ def __init__(self, basis: List[int]) -> None: with 4 modals per mode basis = [4,4,4] """ super().__init__() + self._basis = basis + self._num_qubits = sum(basis) + + self._bitstr = self._build_bitstr() + + def _build_bitstr(self) -> np.ndarray: - # get the bitstring encoding initial state - bitstr = _build_bitstr(basis) + bitstr = np.zeros(self._num_qubits, np.bool) + count = 0 + for i in range(len(self._basis)): + bitstr[self._num_qubits-count-1] = True + count += self._basis[i] - # construct the circuit - qr = QuantumRegister(len(bitstr), 'q') - super().__init__(qr, name='VSCF') + return bitstr - # add gates in the right positions - for i, bit in enumerate(reversed(bitstr)): - if bit: - self.x(i) + def construct_circuit(self, mode: str = 'circuit', register: QuantumRegister = None) \ + -> QuantumCircuit: + """ + Construct the circuit of desired initial state. + + Args: + mode: `vector` or `circuit`. The `vector` mode produces the vector. + While the `circuit` constructs the quantum circuit corresponding that vector. + register (QuantumRegister): register for circuit construction. + Returns: + QuantumCircuit or numpy.ndarray: statevector. -def _build_bitstr(basis): - num_qubits = sum(basis) - bitstr = np.zeros(num_qubits, np.bool) - count = 0 - for modal in basis: - bitstr[num_qubits - count - 1] = True - count += modal + Raises: + ValueError: when mode is not 'vector' or 'circuit'. + """ + if self._bitstr is None: + self._build_bitstr() + if mode == 'vector': + state = 1.0 + one = np.asarray([0.0, 1.0]) + zero = np.asarray([1.0, 0.0]) + for k in self._bitstr[::-1]: + state = np.kron(one if k else zero, state) + return state + elif mode == 'circuit': + if register is None: + register = QuantumRegister(self._num_qubits, name='q') + quantum_circuit = QuantumCircuit(register) + for qubit_idx, bit in enumerate(self._bitstr[::-1]): + if bit: + quantum_circuit.x(register[qubit_idx]) + return quantum_circuit + else: + raise ValueError('Mode should be either "vector" or "circuit"') + + @property + def bitstr(self) -> np.ndarray: + """Getter of the bit string represented the statevector. - return bitstr + Returns: + numpy.ndarray containing the bitstring representation + """ + if self._bitstr is None: + self._build_bitstr() + return self._bitstr From 1ba963d8c60d4c98da670c6846add8083014362d Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 16 Oct 2020 17:52:24 +0200 Subject: [PATCH 03/22] update several tests --- .../algorithms/minimum_eigen_solvers/iqpe.py | 7 ++- .../algorithms/minimum_eigen_solvers/qpe.py | 2 +- .../aqua/circuits/phase_estimation_circuit.py | 10 ++-- .../components/initial_states/vscf_circuit.py | 57 +++++++++++++++++++ .../components/variational_forms/uccsd.py | 13 ++--- test/chemistry/test_end2end_with_qpe.py | 3 +- .../test_initial_state_hartree_fock.py | 42 ++++++++++++++ test/chemistry/test_initial_state_vscf.py | 31 ++++++++-- test/chemistry/test_uccsd_hartree_fock.py | 2 +- test/chemistry/test_vqe_uccsd_adapt.py | 3 +- 10 files changed, 149 insertions(+), 21 deletions(-) create mode 100644 qiskit/chemistry/components/initial_states/vscf_circuit.py diff --git a/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py b/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py index fe8c887121..05c3cf384d 100644 --- a/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py +++ b/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py @@ -57,7 +57,7 @@ class IQPE(QuantumAlgorithm, MinimumEigensolver): def __init__(self, operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None, - state_in: Optional[InitialState] = None, + state_in: Optional[Union[QuantumCircuit, InitialState]] = None, num_time_slices: int = 1, num_iterations: int = 1, expansion_mode: str = 'suzuki', @@ -192,7 +192,10 @@ def construct_circuit(self, self._ancillary_register = a self._state_register = q qc = QuantumCircuit(q) - qc += self._state_in.construct_circuit('circuit', q) + if isinstance(self._state_in, InitialState): + qc += self._state_in.construct_circuit('circuit', q) + else: + qc.append(self._state_in.to_gate(), q) # hadamard on a[0] qc.add_register(a) qc.h(a[0]) diff --git a/qiskit/aqua/algorithms/minimum_eigen_solvers/qpe.py b/qiskit/aqua/algorithms/minimum_eigen_solvers/qpe.py index 028df795a3..9efa20f1b6 100644 --- a/qiskit/aqua/algorithms/minimum_eigen_solvers/qpe.py +++ b/qiskit/aqua/algorithms/minimum_eigen_solvers/qpe.py @@ -56,7 +56,7 @@ class QPE(QuantumAlgorithm, MinimumEigensolver): def __init__(self, operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None, - state_in: Optional[InitialState] = None, + state_in: Optional[Union[InitialState, QuantumCircuit]] = None, iqft: Optional[QuantumCircuit] = None, num_time_slices: int = 1, num_ancillae: int = 1, diff --git a/qiskit/aqua/circuits/phase_estimation_circuit.py b/qiskit/aqua/circuits/phase_estimation_circuit.py index ffdcfd8381..048e97a812 100644 --- a/qiskit/aqua/circuits/phase_estimation_circuit.py +++ b/qiskit/aqua/circuits/phase_estimation_circuit.py @@ -12,7 +12,7 @@ """Quantum Phase Estimation Circuit.""" -from typing import Optional, List +from typing import Optional, List, Union import numpy as np from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister @@ -33,7 +33,7 @@ class PhaseEstimationCircuit: def __init__( self, operator: Optional[WeightedPauliOperator] = None, - state_in: Optional[InitialState] = None, + state_in: Optional[Union[QuantumCircuit, InitialState]] = None, iqft: Optional[QuantumCircuit] = None, num_time_slices: int = 1, num_ancillae: int = 1, @@ -48,7 +48,7 @@ def __init__( """ Args: operator: the hamiltonian Operator object - state_in: the InitialState component + state_in: the InitialState component or a quantum circuit representing the initial quantum state iqft: the Inverse Quantum Fourier Transform as circuit or Aqua component @@ -158,8 +158,10 @@ def construct_circuit( qc.add_register(aux) # initialize state_in - if self._state_in is not None: + if isinstance(self._state_in, InitialState): qc.data += self._state_in.construct_circuit('circuit', q).data + elif isinstance(self._state_in, QuantumCircuit): + qc.append(self._state_in.to_gate(), q) elif self._state_in_circuit_factory is not None: self._state_in_circuit_factory.build(qc, q, aux) diff --git a/qiskit/chemistry/components/initial_states/vscf_circuit.py b/qiskit/chemistry/components/initial_states/vscf_circuit.py new file mode 100644 index 0000000000..f614f52c90 --- /dev/null +++ b/qiskit/chemistry/components/initial_states/vscf_circuit.py @@ -0,0 +1,57 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Initial state for vibrational modes.""" + +from typing import List +import numpy as np +from qiskit import QuantumRegister, QuantumCircuit + + +class VSCF(QuantumCircuit): + r""" Initial state for vibrational modes. + + Creates an occupation number vector as defined in + Ollitrault Pauline J., Chemical science 11 (2020): 6842-6855. + e.g. for 2 modes with 4 modals per mode it creates: \|1000 1000> + """ + + def __init__(self, basis: List[int]) -> None: + """ + Args: + basis: Is a list defining the number of modals per mode. E.g. for a 3 modes system + with 4 modals per mode basis = [4,4,4] + """ + super().__init__() + + # get the bitstring encoding initial state + bitstr = _build_bitstr(basis) + + # construct the circuit + qr = QuantumRegister(len(bitstr), 'q') + super().__init__(qr, name='VSCF') + + # add gates in the right positions + for i, bit in enumerate(reversed(bitstr)): + if bit: + self.x(i) + + +def _build_bitstr(basis): + num_qubits = sum(basis) + bitstr = np.zeros(num_qubits, np.bool) + count = 0 + for modal in basis: + bitstr[num_qubits - count - 1] = True + count += modal + + return bitstr diff --git a/qiskit/chemistry/components/variational_forms/uccsd.py b/qiskit/chemistry/components/variational_forms/uccsd.py index a2cc61d08b..bcbb78d7b5 100644 --- a/qiskit/chemistry/components/variational_forms/uccsd.py +++ b/qiskit/chemistry/components/variational_forms/uccsd.py @@ -52,7 +52,7 @@ def __init__(self, reps: int = 1, active_occupied: Optional[List[int]] = None, active_unoccupied: Optional[List[int]] = None, - initial_state: Optional[InitialState] = None, + initial_state: Optional[Union[QuantumCircuit, InitialState]] = None, qubit_mapping: str = 'parity', two_qubit_reduction: bool = True, num_time_slices: int = 1, @@ -380,8 +380,11 @@ def construct_circuit(self, parameters, q=None): if q is None: q = QuantumRegister(self._num_qubits, name='q') - if self._initial_state is not None: + if isinstance(self._initial_state, InitialState): circuit = self._initial_state.construct_circuit('circuit', q) + elif isinstance(self._initial_state, QuantumCircuit): + circuit = QuantumCircuit(q) + circuit.compose(self._initial_state, inplace=True) else: circuit = QuantumCircuit(q) @@ -447,11 +450,7 @@ def preferred_init_points(self): if self._initial_state is None: return None else: - bitstr = self._initial_state.bitstr - if bitstr is not None: - return np.zeros(self._num_parameters, dtype=np.float) - else: - return None + return np.zeros(self._num_parameters, dtype=np.float) @staticmethod def compute_excitation_lists(num_particles, num_orbitals, active_occ_list=None, diff --git a/test/chemistry/test_end2end_with_qpe.py b/test/chemistry/test_end2end_with_qpe.py index f990dfdc50..0a14854caf 100644 --- a/test/chemistry/test_end2end_with_qpe.py +++ b/test/chemistry/test_end2end_with_qpe.py @@ -24,7 +24,8 @@ from qiskit.aqua.operators import Z2Symmetries from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry import FermionicOperator, QiskitChemistryError -from qiskit.chemistry.components.initial_states import HartreeFock +# from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.components.initial_states.hf import HartreeFock @ddt diff --git a/test/chemistry/test_initial_state_hartree_fock.py b/test/chemistry/test_initial_state_hartree_fock.py index 055b634466..654783c685 100644 --- a/test/chemistry/test_initial_state_hartree_fock.py +++ b/test/chemistry/test_initial_state_hartree_fock.py @@ -16,7 +16,9 @@ from test.chemistry import QiskitChemistryTestCase import numpy as np from ddt import ddt, idata, unpack +from qiskit import QuantumCircuit from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.components.initial_states.hf import HartreeFock as HF from qiskit.aqua.operators.legacy import op_converter from qiskit.chemistry import QiskitChemistryError from qiskit.chemistry.drivers import PySCFDriver, UnitsType @@ -110,5 +112,45 @@ def test_hf_value(self, mapping): self.assertAlmostEqual(qmolecule.hf_energy, hf_energy, places=8) +@ddt +class TestHartreeFock(QiskitChemistryTestCase): + """ Initial State HartreeFock tests """ + + def test_qubits_4_jw_h2(self): + """ qubits 4 jw h2 test """ + state = HF(4, (1, 1), 'jordan_wigner', False) + ref = QuantumCircuit(4) + ref.x([0, 2]) + self.assertEqual(state, ref) + + def test_qubits_4_py_h2(self): + """ qubits 4 py h2 test """ + state = HF(4, (1, 1), 'parity', False) + ref = QuantumCircuit(4) + ref.x([0, 1]) + self.assertEqual(state, ref) + + def test_qubits_4_bk_h2(self): + """ qubits 4 bk h2 test """ + state = HF(4, (1, 1), 'bravyi_kitaev', False) + ref = QuantumCircuit(4) + ref.x([0, 1, 2]) + self.assertEqual(state, ref) + + def test_qubits_2_py_h2(self): + """ qubits 2 py h2 test """ + state = HF(4, 2, 'parity', True) + ref = QuantumCircuit(2) + ref.x(0) + self.assertEqual(state, ref) + + def test_qubits_6_py_lih(self): + """ qubits 6 py lih test """ + state = HF(10, (1, 1), 'parity', True, [1, 2]) + ref = QuantumCircuit(6) + ref.x([0, 1]) + self.assertEqual(state, ref) + + if __name__ == '__main__': unittest.main() diff --git a/test/chemistry/test_initial_state_vscf.py b/test/chemistry/test_initial_state_vscf.py index c5eb7537bc..aa81eba3bd 100644 --- a/test/chemistry/test_initial_state_vscf.py +++ b/test/chemistry/test_initial_state_vscf.py @@ -15,8 +15,9 @@ import unittest from test.chemistry import QiskitChemistryTestCase import numpy as np - -from qiskit.chemistry.components.initial_states import VSCF +from qiskit import QuantumCircuit +from qiskit.chemistry.components.initial_states import VSCF as VSCFI +from qiskit.chemistry.components.initial_states.vscf_circuit import VSCF class TestInitialStateVSCF(QiskitChemistryTestCase): @@ -25,7 +26,7 @@ class TestInitialStateVSCF(QiskitChemistryTestCase): def test_qubits_4(self): """ 2 modes 2 modals - test """ basis = [2, 2] - vscf = VSCF(basis) + vscf = VSCFI(basis) cct = vscf.construct_circuit('vector') np.testing.assert_array_equal(cct, [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) @@ -33,7 +34,7 @@ def test_qubits_4(self): def test_qubits_5(self): """ 2 modes 2 modals for the first mode and 3 modals for the second - test """ basis = [2, 3] - vscf = VSCF(basis) + vscf = VSCFI(basis) cct = vscf.construct_circuit('vector') np.testing.assert_array_equal(cct, [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, @@ -41,5 +42,27 @@ def test_qubits_5(self): 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) +class TestVSCF(QiskitChemistryTestCase): + """ Initial State vscf tests """ + + def test_qubits_4(self): + """ 2 modes 2 modals - test """ + basis = [2, 2] + vscf = VSCF(basis) + ref = QuantumCircuit(4) + ref.x([0, 2]) + + self.assertEqual(ref, vscf) + + def test_qubits_5(self): + """ 2 modes 2 modals for the first mode and 3 modals for the second - test """ + basis = [2, 3] + vscf = VSCF(basis) + ref = QuantumCircuit(5) + ref.x([0, 2]) + + self.assertEqual(ref, vscf) + + if __name__ == '__main__': unittest.main() diff --git a/test/chemistry/test_uccsd_hartree_fock.py b/test/chemistry/test_uccsd_hartree_fock.py index f01b271c3a..f4df160c2a 100644 --- a/test/chemistry/test_uccsd_hartree_fock.py +++ b/test/chemistry/test_uccsd_hartree_fock.py @@ -20,7 +20,7 @@ from qiskit.aqua.algorithms import VQE from qiskit.aqua.components.optimizers import SLSQP, SPSA from qiskit.aqua.operators import AerPauliExpectation, PauliExpectation -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.components.initial_states.hf import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.drivers import HDF5Driver from qiskit.chemistry.core import Hamiltonian, QubitMappingType diff --git a/test/chemistry/test_vqe_uccsd_adapt.py b/test/chemistry/test_vqe_uccsd_adapt.py index 7df98b7e82..1052f927c7 100644 --- a/test/chemistry/test_vqe_uccsd_adapt.py +++ b/test/chemistry/test_vqe_uccsd_adapt.py @@ -21,7 +21,7 @@ from qiskit.aqua.operators.legacy.weighted_pauli_operator import Z2Symmetries from qiskit.chemistry import FermionicOperator from qiskit.chemistry.algorithms import VQEAdapt -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.components.initial_states.hf import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry import QiskitChemistryError @@ -29,6 +29,7 @@ class TestVQEAdaptUCCSD(QiskitChemistryTestCase): """ Test Adaptive VQE with UCCSD""" + def setUp(self): super().setUp() # np.random.seed(50) From b6e20229a3a79ba92aa947ce5f539625ce0feed9 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Sun, 18 Oct 2020 15:18:17 +0200 Subject: [PATCH 04/22] fix type change to tuple --- test/chemistry/test_uccsd_hartree_fock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/chemistry/test_uccsd_hartree_fock.py b/test/chemistry/test_uccsd_hartree_fock.py index f4df160c2a..bb2bb8b1b0 100644 --- a/test/chemistry/test_uccsd_hartree_fock.py +++ b/test/chemistry/test_uccsd_hartree_fock.py @@ -46,7 +46,7 @@ def setUp(self): self.optimizer = SLSQP(maxiter=100) initial_state = HartreeFock(core.molecule_info['num_orbitals'], - core.molecule_info['num_particles'], + tuple(core.molecule_info['num_particles']), qubit_mapping=core._qubit_mapping, two_qubit_reduction=core._two_qubit_reduction) self.var_form = UCCSD(num_orbitals=core.molecule_info['num_orbitals'], From 546e0aeb5daaa7c3207bb69c8ef8c0865a42b12f Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 19 Oct 2020 14:22:17 +0200 Subject: [PATCH 05/22] merge hf initial state and circuit --- .../components/initial_states/hartree_fock.py | 154 +++++++++--------- 1 file changed, 78 insertions(+), 76 deletions(-) diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index c3d221f6dd..79e49e610e 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -10,9 +10,10 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -""" Hartree-Fock initial state.""" +"""Hartree-Fock initial state.""" -from typing import Optional, Union, List +import warnings +from typing import Optional, Union, List, Tuple import logging import numpy as np from qiskit import QuantumRegister, QuantumCircuit @@ -22,12 +23,12 @@ logger = logging.getLogger(__name__) -class HartreeFock(InitialState): +class HartreeFock(QuantumCircuit, InitialState): """A Hartree-Fock initial state.""" def __init__(self, num_orbitals: int, - num_particles: Union[List[int], int], + num_particles: Union[Tuple[int, int], List[int], int], qubit_mapping: str = 'parity', two_qubit_reduction: bool = True, sq_list: Optional[List[int]] = None) -> None: @@ -45,77 +46,30 @@ def __init__(self, ValueError: wrong setting in num_particles and num_orbitals. ValueError: wrong setting for computed num_qubits and supplied num_qubits. """ + # validate the input validate_min('num_orbitals', num_orbitals, 1) - if isinstance(num_particles, list) and len(num_particles) != 2: - raise ValueError('Num particles value {}. Number of values allowed is 2'.format( - num_particles)) validate_in_set('qubit_mapping', qubit_mapping, {'jordan_wigner', 'parity', 'bravyi_kitaev'}) - super().__init__() - self._sq_list = sq_list - self._qubit_tapering = bool(self._sq_list) - self._qubit_mapping = qubit_mapping.lower() - self._two_qubit_reduction = two_qubit_reduction - if self._qubit_mapping != 'parity': - if self._two_qubit_reduction: - logger.warning("two_qubit_reduction only works with parity qubit mapping " - "but you have %s. We switch two_qubit_reduction " - "to False.", self._qubit_mapping) - self._two_qubit_reduction = False - - self._num_orbitals = num_orbitals - if isinstance(num_particles, list): - self._num_alpha = num_particles[0] - self._num_beta = num_particles[1] - else: - logger.info("We assume that the number of alphas and betas are the same.") - self._num_alpha = num_particles // 2 - self._num_beta = num_particles // 2 - - self._num_particles = self._num_alpha + self._num_beta - - if self._num_particles > self._num_orbitals: - raise ValueError("# of particles must be less than or equal to # of orbitals.") - - self._num_qubits = num_orbitals - 2 if self._two_qubit_reduction else self._num_orbitals - self._num_qubits = self._num_qubits \ - if not self._qubit_tapering else self._num_qubits - len(sq_list) - - self._bitstr = None - def _build_bitstr(self): + if qubit_mapping != 'parity' and two_qubit_reduction: + warnings.warn('two_qubit_reduction only works with parity qubit mapping ' + 'but you have %s. We switch two_qubit_reduction ' + 'to False.', qubit_mapping) + two_qubit_reduction = False - half_orbitals = self._num_orbitals // 2 - bitstr = np.zeros(self._num_orbitals, np.bool) - bitstr[-self._num_alpha:] = True - bitstr[-(half_orbitals + self._num_beta):-half_orbitals] = True + # get the bitstring encoding the Hartree Fock state + bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, + two_qubit_reduction, sq_list) + self._bitstr = bitstr - if self._qubit_mapping == 'parity': - new_bitstr = bitstr.copy() + # construct the circuit + qr = QuantumRegister(len(bitstr), 'q') + super().__init__(qr, name='HF') - t_r = np.triu(np.ones((self._num_orbitals, self._num_orbitals))) - new_bitstr = t_r.dot(new_bitstr.astype(np.int)) % 2 # pylint: disable=no-member - - bitstr = np.append(new_bitstr[1:half_orbitals], new_bitstr[half_orbitals + 1:]) \ - if self._two_qubit_reduction else new_bitstr - - elif self._qubit_mapping == 'bravyi_kitaev': - binary_superset_size = int(np.ceil(np.log2(self._num_orbitals))) - beta = 1 - basis = np.asarray([[1, 0], [0, 1]]) - for _ in range(binary_superset_size): - beta = np.kron(basis, beta) - beta[0, :] = 1 - start_idx = beta.shape[0] - self._num_orbitals - beta = beta[start_idx:, start_idx:] - new_bitstr = beta.dot(bitstr.astype(int)) % 2 - bitstr = new_bitstr.astype(np.bool) - - if self._qubit_tapering: - sq_list = (len(bitstr) - 1) - np.asarray(self._sq_list) - bitstr = np.delete(bitstr, sq_list) - - self._bitstr = bitstr.astype(np.bool) + # add gates in the right positions + for i, bit in enumerate(reversed(bitstr)): + if bit: + self.x(i) def construct_circuit(self, mode='circuit', register=None): """ @@ -133,8 +87,10 @@ def construct_circuit(self, mode='circuit', register=None): Raises: ValueError: when mode is not 'vector' or 'circuit'. """ - if self._bitstr is None: - self._build_bitstr() + warnings.warn('The HartreeFock.construct_circuit method is deprecated as of Aqua 0.9.0 and ' + 'will be removed no earlier than 3 months after the release. The HarteeFock ' + 'class is now a QuantumCircuit instance and can directly be used as such.', + DeprecationWarning, stacklevel=2) if mode == 'vector': state = 1.0 one = np.asarray([0.0, 1.0]) @@ -144,11 +100,9 @@ def construct_circuit(self, mode='circuit', register=None): return state elif mode == 'circuit': if register is None: - register = QuantumRegister(self._num_qubits, name='q') + register = QuantumRegister(self.num_qubits, name='q') quantum_circuit = QuantumCircuit(register) - for qubit_idx, bit in enumerate(self._bitstr[::-1]): - if bit: - quantum_circuit.x(register[qubit_idx]) + quantum_circuit.compose(self, inplace=True) return quantum_circuit else: raise ValueError('Mode should be either "vector" or "circuit"') @@ -156,6 +110,54 @@ def construct_circuit(self, mode='circuit', register=None): @property def bitstr(self): """Getter of the bit string represented the statevector.""" - if self._bitstr is None: - self._build_bitstr() + warnings.warn('The HartreeFock.bitstr property is deprecated as of Aqua 0.9.0 and will be ' + 'removed no earlier than 3 months after the release. To get the bitstring ' + 'you can use the quantum_info.Statevector class and the probabilities_dict ' + 'method.', DeprecationWarning, stacklevel=2) return self._bitstr + + +def _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction=True, + sq_list=None): + if isinstance(num_particles, tuple): + num_alpha, num_beta = num_particles + else: + logger.info('We assume that the number of alphas and betas are the same.') + num_alpha = num_beta = num_particles // 2 + + num_particles = num_alpha + num_beta + + if num_particles > num_orbitals: + raise ValueError('# of particles must be less than or equal to # of orbitals.') + + half_orbitals = num_orbitals // 2 + bitstr = np.zeros(num_orbitals, np.bool) + bitstr[-num_alpha:] = True + bitstr[-(half_orbitals + num_beta):-half_orbitals] = True + + if qubit_mapping == 'parity': + new_bitstr = bitstr.copy() + + t_r = np.triu(np.ones((num_orbitals, num_orbitals))) + new_bitstr = t_r.dot(new_bitstr.astype(np.int)) % 2 # pylint: disable=no-member + + bitstr = np.append(new_bitstr[1:half_orbitals], new_bitstr[half_orbitals + 1:]) \ + if two_qubit_reduction else new_bitstr + + elif qubit_mapping == 'bravyi_kitaev': + binary_superset_size = int(np.ceil(np.log2(num_orbitals))) + beta = 1 + basis = np.asarray([[1, 0], [0, 1]]) + for _ in range(binary_superset_size): + beta = np.kron(basis, beta) + beta[0, :] = 1 + start_idx = beta.shape[0] - num_orbitals + beta = beta[start_idx:, start_idx:] + new_bitstr = beta.dot(bitstr.astype(int)) % 2 + bitstr = new_bitstr.astype(np.bool) + + if sq_list is not None: + sq_list = (len(bitstr) - 1) - np.asarray(sq_list) + bitstr = np.delete(bitstr, sq_list) + + return bitstr.astype(np.bool) From 4eebf01831052e36cddbb3171921ec2e387b99de Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 19 Oct 2020 19:15:49 +0200 Subject: [PATCH 06/22] merge initstate+circuit --- .../chemistry/components/initial_states/hf.py | 112 ------------------ .../components/initial_states/vscf_circuit.py | 57 --------- 2 files changed, 169 deletions(-) delete mode 100644 qiskit/chemistry/components/initial_states/hf.py delete mode 100644 qiskit/chemistry/components/initial_states/vscf_circuit.py diff --git a/qiskit/chemistry/components/initial_states/hf.py b/qiskit/chemistry/components/initial_states/hf.py deleted file mode 100644 index 5b7dd1e4f7..0000000000 --- a/qiskit/chemistry/components/initial_states/hf.py +++ /dev/null @@ -1,112 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2020. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Hartree-Fock initial state.""" - -from typing import Optional, Union, List, Tuple -import warnings -import logging -import numpy as np -from qiskit import QuantumRegister, QuantumCircuit -from qiskit.aqua.utils.validation import validate_min, validate_in_set - -logger = logging.getLogger(__name__) - - -class HartreeFock(QuantumCircuit): - """A Hartree-Fock initial state.""" - - def __init__(self, - num_orbitals: int, - num_particles: Union[Tuple[int, int], int], - qubit_mapping: str = 'parity', - two_qubit_reduction: bool = True, - sq_list: Optional[List[int]] = None) -> None: - """ - Args: - num_orbitals: number of spin orbitals, has a min. value of 1. - num_particles: number of particles, if it is a list, the first number - is alpha and the second number if beta. - qubit_mapping: mapping type for qubit operator - two_qubit_reduction: flag indicating whether or not two qubit is reduced - sq_list: position of the single-qubit operators that - anticommute with the cliffords - """ - # validate the input - validate_min('num_orbitals', num_orbitals, 1) - validate_in_set('qubit_mapping', qubit_mapping, - {'jordan_wigner', 'parity', 'bravyi_kitaev'}) - - if qubit_mapping != 'parity' and two_qubit_reduction: - warnings.warn('two_qubit_reduction only works with parity qubit mapping ' - 'but you have %s. We switch two_qubit_reduction ' - 'to False.', qubit_mapping) - two_qubit_reduction = False - - # get the bitstring encoding the Hartree Fock state - bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, - two_qubit_reduction, sq_list) - - # construct the circuit - qr = QuantumRegister(len(bitstr), 'q') - super().__init__(qr, name='HF') - - # add gates in the right positions - for i, bit in enumerate(reversed(bitstr)): - if bit: - self.x(i) - - -def _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction=True, - sq_list=None): - if isinstance(num_particles, tuple): - num_alpha, num_beta = num_particles - else: - logger.info('We assume that the number of alphas and betas are the same.') - num_alpha = num_beta = num_particles // 2 - - num_particles = num_alpha + num_beta - - if num_particles > num_orbitals: - raise ValueError('# of particles must be less than or equal to # of orbitals.') - - half_orbitals = num_orbitals // 2 - bitstr = np.zeros(num_orbitals, np.bool) - bitstr[-num_alpha:] = True - bitstr[-(half_orbitals + num_beta):-half_orbitals] = True - - if qubit_mapping == 'parity': - new_bitstr = bitstr.copy() - - t_r = np.triu(np.ones((num_orbitals, num_orbitals))) - new_bitstr = t_r.dot(new_bitstr.astype(np.int)) % 2 # pylint: disable=no-member - - bitstr = np.append(new_bitstr[1:half_orbitals], new_bitstr[half_orbitals + 1:]) \ - if two_qubit_reduction else new_bitstr - - elif qubit_mapping == 'bravyi_kitaev': - binary_superset_size = int(np.ceil(np.log2(num_orbitals))) - beta = 1 - basis = np.asarray([[1, 0], [0, 1]]) - for _ in range(binary_superset_size): - beta = np.kron(basis, beta) - beta[0, :] = 1 - start_idx = beta.shape[0] - num_orbitals - beta = beta[start_idx:, start_idx:] - new_bitstr = beta.dot(bitstr.astype(int)) % 2 - bitstr = new_bitstr.astype(np.bool) - - if sq_list is not None: - sq_list = (len(bitstr) - 1) - np.asarray(sq_list) - bitstr = np.delete(bitstr, sq_list) - - return bitstr.astype(np.bool) diff --git a/qiskit/chemistry/components/initial_states/vscf_circuit.py b/qiskit/chemistry/components/initial_states/vscf_circuit.py deleted file mode 100644 index f614f52c90..0000000000 --- a/qiskit/chemistry/components/initial_states/vscf_circuit.py +++ /dev/null @@ -1,57 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2020. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Initial state for vibrational modes.""" - -from typing import List -import numpy as np -from qiskit import QuantumRegister, QuantumCircuit - - -class VSCF(QuantumCircuit): - r""" Initial state for vibrational modes. - - Creates an occupation number vector as defined in - Ollitrault Pauline J., Chemical science 11 (2020): 6842-6855. - e.g. for 2 modes with 4 modals per mode it creates: \|1000 1000> - """ - - def __init__(self, basis: List[int]) -> None: - """ - Args: - basis: Is a list defining the number of modals per mode. E.g. for a 3 modes system - with 4 modals per mode basis = [4,4,4] - """ - super().__init__() - - # get the bitstring encoding initial state - bitstr = _build_bitstr(basis) - - # construct the circuit - qr = QuantumRegister(len(bitstr), 'q') - super().__init__(qr, name='VSCF') - - # add gates in the right positions - for i, bit in enumerate(reversed(bitstr)): - if bit: - self.x(i) - - -def _build_bitstr(basis): - num_qubits = sum(basis) - bitstr = np.zeros(num_qubits, np.bool) - count = 0 - for modal in basis: - bitstr[num_qubits - count - 1] = True - count += modal - - return bitstr From 2b8f57fb7be04b867456d39db5316f374bebf06e Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 19 Oct 2020 19:15:59 +0200 Subject: [PATCH 07/22] merge initstate+circuit --- .../algorithms/minimum_eigen_solvers/iqpe.py | 6 +- .../aqua/circuits/phase_estimation_circuit.py | 6 +- .../components/initial_states/hartree_fock.py | 7 ++ .../components/initial_states/vscf.py | 77 ++++++++++--------- .../test_initial_state_hartree_fock.py | 21 +++-- test/chemistry/test_initial_state_vscf.py | 9 +++ test/chemistry/test_uccsd_hartree_fock.py | 2 +- 7 files changed, 79 insertions(+), 49 deletions(-) diff --git a/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py b/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py index 05c3cf384d..36bfe4ec49 100644 --- a/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py +++ b/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py @@ -192,10 +192,10 @@ def construct_circuit(self, self._ancillary_register = a self._state_register = q qc = QuantumCircuit(q) - if isinstance(self._state_in, InitialState): - qc += self._state_in.construct_circuit('circuit', q) - else: + if isinstance(self._state_in, QuantumCircuit): qc.append(self._state_in.to_gate(), q) + else: + qc += self._state_in.construct_circuit('circuit', q) # hadamard on a[0] qc.add_register(a) qc.h(a[0]) diff --git a/qiskit/aqua/circuits/phase_estimation_circuit.py b/qiskit/aqua/circuits/phase_estimation_circuit.py index 048e97a812..391244b2c2 100644 --- a/qiskit/aqua/circuits/phase_estimation_circuit.py +++ b/qiskit/aqua/circuits/phase_estimation_circuit.py @@ -158,10 +158,10 @@ def construct_circuit( qc.add_register(aux) # initialize state_in - if isinstance(self._state_in, InitialState): - qc.data += self._state_in.construct_circuit('circuit', q).data - elif isinstance(self._state_in, QuantumCircuit): + if isinstance(self._state_in, QuantumCircuit): qc.append(self._state_in.to_gate(), q) + elif isinstance(self._state_in, InitialState): + qc.data += self._state_in.construct_circuit('circuit', q).data elif self._state_in_circuit_factory is not None: self._state_in_circuit_factory.build(qc, q, aux) diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index 79e49e610e..f12ce8fc50 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -57,6 +57,13 @@ def __init__(self, 'to False.', qubit_mapping) two_qubit_reduction = False + if isinstance(num_particles, list): + warnings.warn('The ``num_particles`` argument should either be a single integer or a ' + 'tuple of two integers, not a list. This behavious is deprecated as of ' + 'Aqua 0.9 and will be removed no earlier than 3 months after the ' + 'release.', DeprecationWarning, stacklevel=2) + num_particles = tuple(num_particles) + # get the bitstring encoding the Hartree Fock state bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction, sq_list) diff --git a/qiskit/chemistry/components/initial_states/vscf.py b/qiskit/chemistry/components/initial_states/vscf.py index 6bc50f2a88..5893ed81dd 100644 --- a/qiskit/chemistry/components/initial_states/vscf.py +++ b/qiskit/chemistry/components/initial_states/vscf.py @@ -13,19 +13,19 @@ """ Initial state for vibrational modes. """ import logging +import warnings from typing import List import numpy as np from qiskit import QuantumRegister, QuantumCircuit - from qiskit.aqua.components.initial_states import InitialState logger = logging.getLogger(__name__) -class VSCF(InitialState): - r""" Initial state for vibrational modes. +class VSCF(QuantumCircuit, InitialState): + r"""Initial state for vibrational modes. Creates an occupation number vector as defined in Ollitrault Pauline J., Chemical science 11 (2020): 6842-6855. @@ -38,30 +38,26 @@ def __init__(self, basis: List[int]) -> None: basis: Is a list defining the number of modals per mode. E.g. for a 3 modes system with 4 modals per mode basis = [4,4,4] """ - super().__init__() - self._basis = basis - self._num_qubits = sum(basis) - - self._bitstr = self._build_bitstr() + # get the bitstring encoding initial state + bitstr = _build_bitstr(basis) + self._bitstr = bitstr - def _build_bitstr(self) -> np.ndarray: + # construct the circuit + qr = QuantumRegister(len(bitstr), 'q') + super().__init__(qr, name='VSCF') - bitstr = np.zeros(self._num_qubits, np.bool) - count = 0 - for i in range(len(self._basis)): - bitstr[self._num_qubits-count-1] = True - count += self._basis[i] + # add gates in the right positions + for i, bit in enumerate(reversed(bitstr)): + if bit: + self.x(i) - return bitstr - - def construct_circuit(self, mode: str = 'circuit', register: QuantumRegister = None) \ - -> QuantumCircuit: - """ - Construct the circuit of desired initial state. + def construct_circuit(self, mode='circuit', register=None): + """Construct the statevector of desired initial state. Args: - mode: `vector` or `circuit`. The `vector` mode produces the vector. - While the `circuit` constructs the quantum circuit corresponding that vector. + mode (string): `vector` or `circuit`. The `vector` mode produces the vector. + While the `circuit` constructs the quantum circuit corresponding that + vector. register (QuantumRegister): register for circuit construction. Returns: @@ -70,8 +66,10 @@ def construct_circuit(self, mode: str = 'circuit', register: QuantumRegister = N Raises: ValueError: when mode is not 'vector' or 'circuit'. """ - if self._bitstr is None: - self._build_bitstr() + warnings.warn('The VSCF.construct_circuit method is deprecated as of Aqua 0.9.0 and ' + 'will be removed no earlier than 3 months after the release. The HarteeFock ' + 'class is now a QuantumCircuit instance and can directly be used as such.', + DeprecationWarning, stacklevel=2) if mode == 'vector': state = 1.0 one = np.asarray([0.0, 1.0]) @@ -81,22 +79,29 @@ def construct_circuit(self, mode: str = 'circuit', register: QuantumRegister = N return state elif mode == 'circuit': if register is None: - register = QuantumRegister(self._num_qubits, name='q') + register = QuantumRegister(self.num_qubits, name='q') quantum_circuit = QuantumCircuit(register) - for qubit_idx, bit in enumerate(self._bitstr[::-1]): - if bit: - quantum_circuit.x(register[qubit_idx]) + quantum_circuit.compose(self, inplace=True) return quantum_circuit else: raise ValueError('Mode should be either "vector" or "circuit"') @property - def bitstr(self) -> np.ndarray: - """Getter of the bit string represented the statevector. - - Returns: - numpy.ndarray containing the bitstring representation - """ - if self._bitstr is None: - self._build_bitstr() + def bitstr(self): + """Getter of the bit string represented the statevector.""" + warnings.warn('The VSCF.bitstr property is deprecated as of Aqua 0.9.0 and will be ' + 'removed no earlier than 3 months after the release. To get the bitstring ' + 'you can use the quantum_info.Statevector class and the probabilities_dict ' + 'method.', DeprecationWarning, stacklevel=2) return self._bitstr + + +def _build_bitstr(basis): + num_qubits = sum(basis) + bitstr = np.zeros(num_qubits, np.bool) + count = 0 + for modal in basis: + bitstr[num_qubits - count - 1] = True + count += modal + + return bitstr diff --git a/test/chemistry/test_initial_state_hartree_fock.py b/test/chemistry/test_initial_state_hartree_fock.py index 654783c685..aa00fec64b 100644 --- a/test/chemistry/test_initial_state_hartree_fock.py +++ b/test/chemistry/test_initial_state_hartree_fock.py @@ -13,12 +13,13 @@ """ Test Initial State HartreeFock """ import unittest +import warnings from test.chemistry import QiskitChemistryTestCase import numpy as np from ddt import ddt, idata, unpack from qiskit import QuantumCircuit from qiskit.chemistry.components.initial_states import HartreeFock -from qiskit.chemistry.components.initial_states.hf import HartreeFock as HF +# from qiskit.chemistry.components.initial_states.hf import HartreeFock as HartreeFock from qiskit.aqua.operators.legacy import op_converter from qiskit.chemistry import QiskitChemistryError from qiskit.chemistry.drivers import PySCFDriver, UnitsType @@ -29,6 +30,14 @@ class TestInitialStateHartreeFock(QiskitChemistryTestCase): """ Initial State HartreeFock tests """ + def setUp(self): + super().setUp() + warnings.filterwarnings('ignore', category=DeprecationWarning) + + def tearDown(self): + super().tearDown() + warnings.filterwarnings('always', category=DeprecationWarning) + def test_qubits_4_jw_h2(self): """ qubits 4 jw h2 test """ hrfo = HartreeFock(4, [1, 1], 'jordan_wigner', False) @@ -118,35 +127,35 @@ class TestHartreeFock(QiskitChemistryTestCase): def test_qubits_4_jw_h2(self): """ qubits 4 jw h2 test """ - state = HF(4, (1, 1), 'jordan_wigner', False) + state = HartreeFock(4, (1, 1), 'jordan_wigner', False) ref = QuantumCircuit(4) ref.x([0, 2]) self.assertEqual(state, ref) def test_qubits_4_py_h2(self): """ qubits 4 py h2 test """ - state = HF(4, (1, 1), 'parity', False) + state = HartreeFock(4, (1, 1), 'parity', False) ref = QuantumCircuit(4) ref.x([0, 1]) self.assertEqual(state, ref) def test_qubits_4_bk_h2(self): """ qubits 4 bk h2 test """ - state = HF(4, (1, 1), 'bravyi_kitaev', False) + state = HartreeFock(4, (1, 1), 'bravyi_kitaev', False) ref = QuantumCircuit(4) ref.x([0, 1, 2]) self.assertEqual(state, ref) def test_qubits_2_py_h2(self): """ qubits 2 py h2 test """ - state = HF(4, 2, 'parity', True) + state = HartreeFock(4, 2, 'parity', True) ref = QuantumCircuit(2) ref.x(0) self.assertEqual(state, ref) def test_qubits_6_py_lih(self): """ qubits 6 py lih test """ - state = HF(10, (1, 1), 'parity', True, [1, 2]) + state = HartreeFock(10, (1, 1), 'parity', True, [1, 2]) ref = QuantumCircuit(6) ref.x([0, 1]) self.assertEqual(state, ref) diff --git a/test/chemistry/test_initial_state_vscf.py b/test/chemistry/test_initial_state_vscf.py index aa81eba3bd..9c8a8b14a2 100644 --- a/test/chemistry/test_initial_state_vscf.py +++ b/test/chemistry/test_initial_state_vscf.py @@ -13,6 +13,7 @@ """ Test Initial State HartreeFock """ import unittest +import warnings from test.chemistry import QiskitChemistryTestCase import numpy as np from qiskit import QuantumCircuit @@ -23,6 +24,14 @@ class TestInitialStateVSCF(QiskitChemistryTestCase): """ Initial State vscf tests """ + def setUp(self): + super().setUp() + warnings.filterwarnings('ignore', category=DeprecationWarning) + + def tearDown(self): + super().tearDown() + warnings.filterwarnings('always', category=DeprecationWarning) + def test_qubits_4(self): """ 2 modes 2 modals - test """ basis = [2, 2] diff --git a/test/chemistry/test_uccsd_hartree_fock.py b/test/chemistry/test_uccsd_hartree_fock.py index bb2bb8b1b0..09e6cdd18b 100644 --- a/test/chemistry/test_uccsd_hartree_fock.py +++ b/test/chemistry/test_uccsd_hartree_fock.py @@ -20,7 +20,7 @@ from qiskit.aqua.algorithms import VQE from qiskit.aqua.components.optimizers import SLSQP, SPSA from qiskit.aqua.operators import AerPauliExpectation, PauliExpectation -from qiskit.chemistry.components.initial_states.hf import HartreeFock +from qiskit.chemistry.components.initial_states import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.drivers import HDF5Driver from qiskit.chemistry.core import Hamiltonian, QubitMappingType From 8cec413474e1dee7cd6baf79a5bdb10b510df4f3 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 10:40:25 +0200 Subject: [PATCH 08/22] update EOH --- qiskit/aqua/algorithms/education/eoh.py | 10 +++++++--- .../components/initial_states/hartree_fock.py | 3 +-- test/aqua/test_eoh.py | 19 ++++++++++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/qiskit/aqua/algorithms/education/eoh.py b/qiskit/aqua/algorithms/education/eoh.py index 715c4df666..d2b60d6f0c 100644 --- a/qiskit/aqua/algorithms/education/eoh.py +++ b/qiskit/aqua/algorithms/education/eoh.py @@ -16,7 +16,7 @@ import logging from typing import Optional, Union, Dict, Any -from qiskit import QuantumRegister +from qiskit import QuantumRegister, QuantumCircuit from qiskit.providers import BaseBackend from qiskit.providers import Backend from qiskit.aqua import QuantumInstance @@ -42,7 +42,7 @@ class EOH(QuantumAlgorithm): """ def __init__(self, operator: LegacyBaseOperator, - initial_state: InitialState, + initial_state: Union[InitialState, QuantumCircuit], evo_operator: LegacyBaseOperator, evo_time: float = 1, num_time_slices: int = 1, @@ -84,7 +84,11 @@ def construct_circuit(self): QuantumCircuit: the circuit. """ quantum_registers = QuantumRegister(self._operator.num_qubits, name='q') - qc = self._initial_state.construct_circuit('circuit', quantum_registers) + if isinstance(self._initial_state, QuantumCircuit): + qc = QuantumCircuit(quantum_registers) + qc.compose(self._initial_state, inplace=True) + else: + qc = self._initial_state.construct_circuit('circuit', quantum_registers) qc += self._evo_operator.evolve( evo_time=self._evo_time, diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index f12ce8fc50..a4aa9342d5 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -79,8 +79,7 @@ def __init__(self, self.x(i) def construct_circuit(self, mode='circuit', register=None): - """ - Construct the statevector of desired initial state. + """Construct the statevector of desired initial state. Args: mode (string): `vector` or `circuit`. The `vector` mode produces the vector. diff --git a/test/aqua/test_eoh.py b/test/aqua/test_eoh.py index 02481e3bd7..aee5e063e1 100644 --- a/test/aqua/test_eoh.py +++ b/test/aqua/test_eoh.py @@ -13,20 +13,25 @@ """ Test EOH """ import unittest +import warnings from test.aqua import QiskitAquaTestCase +from ddt import ddt, data -from qiskit import BasicAer +import numpy as np +from qiskit import BasicAer, QuantumCircuit from qiskit.aqua.operators import MatrixOperator from qiskit.aqua import QuantumInstance, aqua_globals from qiskit.aqua.components.initial_states import Custom from qiskit.aqua.algorithms import EOH +@ddt class TestEOH(QiskitAquaTestCase): """Evolution tests.""" - def test_eoh(self): + @data('initial_state', 'circuit') + def test_eoh(self, mode): """ EOH test """ size = 2 aqua_globals.random_seed = 0 @@ -39,7 +44,15 @@ def test_eoh(self): h_1 = temp + temp.T evo_op = MatrixOperator(matrix=h_1) - state_in = Custom(size, state='random') + if mode == 'initial_state': + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + state_in = Custom(size, state='random') + else: + random_state = aqua_globals.random.random(2 ** size) + random_state = random_state / np.linalg.norm(random_state) + state_in = QuantumCircuit(size) + state_in.initialize(random_state, range(size)) evo_time = 1 num_time_slices = 100 From 131e5aaea1f7d04cb32fd3837380e48a8fec4f84 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 13:20:23 +0200 Subject: [PATCH 09/22] update hhl and qaia --- qiskit/aqua/algorithms/linear_solvers/hhl.py | 7 +++-- .../minimum_eigen_solvers/qaoa/qaoa.py | 3 +- .../minimum_eigen_solvers/qaoa/var_form.py | 9 ++++-- test/aqua/test_hhl.py | 30 +++++++++++++------ 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/qiskit/aqua/algorithms/linear_solvers/hhl.py b/qiskit/aqua/algorithms/linear_solvers/hhl.py index 36bf8f55c8..a4e9039bc7 100644 --- a/qiskit/aqua/algorithms/linear_solvers/hhl.py +++ b/qiskit/aqua/algorithms/linear_solvers/hhl.py @@ -91,7 +91,7 @@ def __init__( truncate_powerdim: bool = False, truncate_hermitian: bool = False, eigs: Optional[Eigenvalues] = None, - init_state: Optional[InitialState] = None, + init_state: Optional[Union[QuantumCircuit, InitialState]] = None, reciprocal: Optional[Reciprocal] = None, num_q: int = 0, num_a: int = 0, @@ -206,7 +206,10 @@ def construct_circuit(self, measurement: bool = False) -> QuantumCircuit: qc = QuantumCircuit(q) # InitialState - qc += self._init_state.construct_circuit("circuit", q) + if isinstance(self._init_state, QuantumCircuit): + qc.compose(self._init_state, inplace=True) + elif self._init_state is not None: + qc += self._init_state.construct_circuit("circuit", q) # EigenvalueEstimation (QPE) qc += self._eigs.construct_circuit("circuit", q) diff --git a/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/qaoa.py b/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/qaoa.py index f4c1bac17d..8dcb36f8e6 100755 --- a/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/qaoa.py +++ b/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/qaoa.py @@ -16,6 +16,7 @@ import logging import numpy as np +from qiskit.circuit import QuantumCircuit from qiskit.providers import BaseBackend from qiskit.providers import Backend from qiskit.aqua import QuantumInstance @@ -66,7 +67,7 @@ def __init__(self, operator: Union[OperatorBase, LegacyBaseOperator] = None, optimizer: Optimizer = None, p: int = 1, - initial_state: Optional[InitialState] = None, + initial_state: Optional[Union[QuantumCircuit, InitialState]] = None, mixer: Union[OperatorBase, LegacyBaseOperator] = None, initial_point: Optional[np.ndarray] = None, expectation: Optional[ExpectationBase] = None, diff --git a/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py b/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py index 16160da042..a594ca103f 100755 --- a/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py +++ b/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py @@ -12,10 +12,11 @@ """Global X phases and parameterized problem hamiltonian.""" -from typing import Optional +from typing import Optional, Union import numpy as np +from qiskit import QuantumCircuit from qiskit.aqua.operators import (OperatorBase, X, I, H, Zero, CircuitStateFn, EvolutionFactory, LegacyBaseOperator) from qiskit.aqua.components.variational_forms import VariationalForm @@ -31,7 +32,7 @@ class QAOAVarForm(VariationalForm): def __init__(self, cost_operator: OperatorBase, p: int, - initial_state: Optional[InitialState] = None, + initial_state: Optional[Union[QuantumCircuit, InitialState]] = None, mixer_operator: Optional[OperatorBase] = None): """ Constructor, following the QAOA paper https://arxiv.org/abs/1411.4028 @@ -82,7 +83,9 @@ def construct_circuit(self, parameters, q=None): circuit = (H ^ self._num_qubits) # initialize circuit, possibly based on given register/initial state - if self._initial_state is not None: + if isinstance(self._initial_state, QuantumCircuit): + init_state = CircuitStateFn(self._initial_state) + elif self._initial_state is not None: init_state = CircuitStateFn(self._initial_state.construct_circuit('circuit')) else: init_state = Zero diff --git a/test/aqua/test_hhl.py b/test/aqua/test_hhl.py index ad8060bd0f..4390a7be1f 100644 --- a/test/aqua/test_hhl.py +++ b/test/aqua/test_hhl.py @@ -18,7 +18,7 @@ import numpy as np from ddt import ddt, idata, data, unpack -from qiskit import BasicAer +from qiskit import BasicAer, QuantumCircuit from qiskit.quantum_info import state_fidelity from qiskit.circuit.library import QFT @@ -83,7 +83,9 @@ def test_hhl_diagonal(self, vector): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + init_state = Custom(num_q, state_vector=vector) # Initialize reciprocal rotation module reci = LookupRotation(negative_evals=eigs._negative_evals, evo_time=eigs._evo_time) @@ -127,7 +129,8 @@ def test_hhl_diagonal_negative(self, vector): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + init_state = QuantumCircuit(num_q) + init_state.initialize(vector / np.linalg.norm(vector), range(num_q)) # Initialize reciprocal rotation module reci = LookupRotation(negative_evals=eigs._negative_evals, evo_time=eigs._evo_time) @@ -172,7 +175,9 @@ def test_hhl_diagonal_longdivison(self, vector): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + init_state = Custom(num_q, state_vector=vector) # Initialize reciprocal reci = LongDivision(scale=1.0, negative_evals=eigs._negative_evals, evo_time=eigs._evo_time) @@ -217,7 +222,8 @@ def test_hhl_diagonal_qasm(self, vector): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + init_state = QuantumCircuit(num_q) + init_state.initialize(vector / np.linalg.norm(vector), range(num_q)) # Initialize reciprocal rotation module reci = LookupRotation(negative_evals=eigs._negative_evals, @@ -263,7 +269,9 @@ def test_hhl_diagonal_other_dim(self, n, num_ancillary): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + init_state = Custom(num_q, state_vector=vector) # Initialize reciprocal rotation module reci = LookupRotation(negative_evals=eigs._negative_evals, evo_time=eigs._evo_time) @@ -312,7 +320,8 @@ def test_hhl_negative_eigs(self): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + init_state = QuantumCircuit(num_q) + init_state.initialize(vector / np.linalg.norm(vector), range(num_q)) # Initialize reciprocal rotation module reci = LookupRotation(negative_evals=eigs._negative_evals, evo_time=eigs._evo_time) @@ -357,7 +366,9 @@ def test_hhl_random_hermitian(self): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + init_state = Custom(num_q, state_vector=vector) # Initialize reciprocal rotation module reci = LookupRotation(negative_evals=eigs._negative_evals, evo_time=eigs._evo_time) @@ -398,7 +409,8 @@ def test_hhl_non_hermitian(self): num_q, num_a = eigs.get_register_sizes() # Initialize initial state module - init_state = Custom(num_q, state_vector=vector) + init_state = QuantumCircuit(num_q) + init_state.initialize(vector / np.linalg.norm(vector), range(num_q)) # Initialize reciprocal rotation module reci = LookupRotation(negative_evals=eigs._negative_evals, evo_time=eigs._evo_time) From 1f696f249e97745ae356c1673b8ff78530e1d481 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 13:24:46 +0200 Subject: [PATCH 10/22] update chc and uvcc --- qiskit/chemistry/components/variational_forms/chc.py | 10 +++++++--- qiskit/chemistry/components/variational_forms/uvcc.py | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/qiskit/chemistry/components/variational_forms/chc.py b/qiskit/chemistry/components/variational_forms/chc.py index a1c6804385..139829023c 100644 --- a/qiskit/chemistry/components/variational_forms/chc.py +++ b/qiskit/chemistry/components/variational_forms/chc.py @@ -39,7 +39,7 @@ class CHC(VariationalForm): def __init__(self, num_qubits: Optional[int] = None, reps: int = 1, ladder: bool = False, excitations: Optional[List[List[int]]] = None, entanglement: Union[str, List[int]] = 'full', - initial_state: Optional[InitialState] = None) -> None: + initial_state: Optional[Union[QuantumCircuit, InitialState]] = None) -> None: """ Args: @@ -48,7 +48,7 @@ def __init__(self, num_qubits: Optional[int] = None, reps: int = 1, ladder: bool ladder: use ladder of CNOTs between to indices in the entangling block excitations: indices corresponding to the excitations to include in the circuit entanglement: physical connections between the qubits - initial_state: an initial state object + initial_state: an initial state to prepend to the variational form """ super().__init__() @@ -114,7 +114,11 @@ def construct_circuit(self, parameters: Union[np.ndarray, List[Parameter], Param if q is None: q = QuantumRegister(self._num_qubits, name='q') - if self._initial_state is not None: + + if isinstance(self._initial_state, QuantumCircuit): + circuit = QuantumCircuit(q) + circuit.append(self._initial_state.to_gate(), range(self._initial_state.num_qubits)) + elif self._initial_state is not None: circuit = self._initial_state.construct_circuit('circuit', q) else: circuit = QuantumCircuit(q) diff --git a/qiskit/chemistry/components/variational_forms/uvcc.py b/qiskit/chemistry/components/variational_forms/uvcc.py index 061b146e5e..7b0ec3511f 100644 --- a/qiskit/chemistry/components/variational_forms/uvcc.py +++ b/qiskit/chemistry/components/variational_forms/uvcc.py @@ -44,7 +44,7 @@ def __init__(self, num_qubits: int, degrees: List[int], reps: int = 1, excitations: Optional[List[List[List[int]]]] = None, - initial_state: Optional[InitialState] = None, + initial_state: Optional[Union[QuantumCircuit, InitialState]] = None, qubit_mapping: str = 'direct', num_time_slices: int = 1, shallow_circuit_concat: bool = True) -> None: @@ -181,7 +181,11 @@ def construct_circuit(self, parameters: Union[np.ndarray, List[Parameter], Param if q is None: q = QuantumRegister(self._num_qubits, name='q') - if self._initial_state is not None: + + if isinstance(self._initial_state, QuantumCircuit): + circuit = QuantumCircuit(q) + circuit.append(self._initial_state.to_gate(), range(self._initial_state.num_qubits)) + elif self._initial_state is not None: circuit = self._initial_state.construct_circuit('circuit', q) else: circuit = QuantumCircuit(q) From 72d3b31633333b52da93ec01ca9e25185ec208f8 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 13:34:28 +0200 Subject: [PATCH 11/22] deprecate InitialState components --- qiskit/aqua/components/initial_states/custom.py | 5 +++++ .../aqua/components/initial_states/initial_state.py | 12 ++++++++++++ .../aqua/components/initial_states/var_form_based.py | 8 ++++++++ qiskit/aqua/components/initial_states/zero.py | 4 ++++ test/aqua/test_initial_state_custom.py | 10 ++++++++++ test/aqua/test_initial_state_zero.py | 10 ++++++++++ 6 files changed, 49 insertions(+) diff --git a/qiskit/aqua/components/initial_states/custom.py b/qiskit/aqua/components/initial_states/custom.py index 95895aa7a5..4e77145fc0 100644 --- a/qiskit/aqua/components/initial_states/custom.py +++ b/qiskit/aqua/components/initial_states/custom.py @@ -112,6 +112,11 @@ def __init__(self, self._state_vector = normalize_vector(state_vector) self._state = None + @staticmethod + def _replacement(): + return 'Custom(state_vector=vector) is the same as a circuit where the ' \ + + '``initialize(vector/np.linalg.norm(vector))`` method has been called.' + def construct_circuit(self, mode='circuit', register=None): # pylint: disable=import-outside-toplevel from qiskit import BasicAer diff --git a/qiskit/aqua/components/initial_states/initial_state.py b/qiskit/aqua/components/initial_states/initial_state.py index bef2436986..6efadd5969 100644 --- a/qiskit/aqua/components/initial_states/initial_state.py +++ b/qiskit/aqua/components/initial_states/initial_state.py @@ -15,6 +15,7 @@ form or in eoh as a trial state to evolve """ +import warnings from typing import Optional # below to allow it for python 3.6.1 try: @@ -39,6 +40,17 @@ class InitialState(ABC): def __init__(self) -> None: super().__init__() + warnings.warn('The {} class is deprecated as of Aqua 0.9 and will be removed no earlier ' + 'than 3 months after the release date. Instead, all algorithms and circuits ' + 'accept a plain QuantumCircuit. {}'.format( + self.__class__.__name__, self._replacement(), + ), + category=DeprecationWarning, stacklevel=2) + + @staticmethod + def _replacement(): + return '' + @abstractmethod def construct_circuit(self, mode: str = 'circuit', diff --git a/qiskit/aqua/components/initial_states/var_form_based.py b/qiskit/aqua/components/initial_states/var_form_based.py index 08a6e5eec5..85e56a28a1 100644 --- a/qiskit/aqua/components/initial_states/var_form_based.py +++ b/qiskit/aqua/components/initial_states/var_form_based.py @@ -13,6 +13,7 @@ """The variational form based initial state""" from typing import Union, List, Dict +import warnings import numpy as np from qiskit import QuantumCircuit from qiskit.circuit import Parameter @@ -51,6 +52,13 @@ def __init__(self, self._var_form = var_form self._var_form_params = params + warnings.warn('The {} class is deprecated as of Aqua 0.9 and will be removed no earlier ' + 'than 3 months after the release date. Instead, all algorithms and circuits ' + 'accept a plain QuantumCircuit.'.format( + self.__class__.__name__ + ), + category=DeprecationWarning, stacklevel=2) + def construct_circuit(self, mode='circuit', register=None): """ Construct the statevector of desired initial state. diff --git a/qiskit/aqua/components/initial_states/zero.py b/qiskit/aqua/components/initial_states/zero.py index 3ee1640aea..71df1d2518 100644 --- a/qiskit/aqua/components/initial_states/zero.py +++ b/qiskit/aqua/components/initial_states/zero.py @@ -37,6 +37,10 @@ def __init__(self, num_qubits: int) -> None: validate_min('num_qubits', num_qubits, 1) self._num_qubits = num_qubits + @staticmethod + def _replacement(): + return 'Zero(num_qubits) is the same as a empty QuantumCircuit(num_qubits).' + def construct_circuit(self, mode='circuit', register=None): if mode == 'vector': return np.array([1.0] + [0.0] * (np.power(2, self._num_qubits) - 1)) diff --git a/test/aqua/test_initial_state_custom.py b/test/aqua/test_initial_state_custom.py index b2b671da6c..c3e5c625b7 100644 --- a/test/aqua/test_initial_state_custom.py +++ b/test/aqua/test_initial_state_custom.py @@ -12,6 +12,7 @@ """ Test Initial State Custom """ +import warnings import unittest from test.aqua import QiskitAquaTestCase @@ -23,6 +24,15 @@ class TestInitialStateCustom(QiskitAquaTestCase): """ Test Initial State Custom """ + + def setUp(self): + super().setUp() + warnings.filterwarnings('ignore', category=DeprecationWarning) + + def tearDown(self): + super().tearDown() + warnings.filterwarnings('always', category=DeprecationWarning) + def test_qubits_2_zero_vector(self): """ qubits 2 zero vector test """ custom = Custom(2, state='zero') diff --git a/test/aqua/test_initial_state_zero.py b/test/aqua/test_initial_state_zero.py index 32d66aa938..44b6bc0061 100644 --- a/test/aqua/test_initial_state_zero.py +++ b/test/aqua/test_initial_state_zero.py @@ -13,6 +13,7 @@ """ Test Initial State Zero """ import unittest +import warnings from test.aqua import QiskitAquaTestCase import numpy as np from qiskit.aqua.components.initial_states import Zero @@ -20,6 +21,15 @@ class TestInitialStateZero(QiskitAquaTestCase): """ Test Initial State Zero """ + + def setUp(self): + super().setUp() + warnings.filterwarnings('ignore', category=DeprecationWarning) + + def tearDown(self): + super().tearDown() + warnings.filterwarnings('always', category=DeprecationWarning) + def test_qubits_2_vector(self): """ Qubits 2 vector test """ zero = Zero(2) From 8019dbbbb194d383b5a1c9f67c91d03bfdfd38a3 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 13:50:37 +0200 Subject: [PATCH 12/22] update varformbased test --- test/aqua/test_vqe2iqpe.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/aqua/test_vqe2iqpe.py b/test/aqua/test_vqe2iqpe.py index 9c6f4efe2d..25ed8fc163 100644 --- a/test/aqua/test_vqe2iqpe.py +++ b/test/aqua/test_vqe2iqpe.py @@ -13,7 +13,9 @@ """ Test VQE to IQPE """ import unittest +import warnings from test.aqua import QiskitAquaTestCase +from ddt import ddt, data from qiskit import BasicAer from qiskit.circuit.library import TwoLocal @@ -27,6 +29,7 @@ from qiskit.aqua.algorithms import IQPE +@ddt class TestVQE2IQPE(QiskitAquaTestCase): """ Test VQE to IQPE """ @@ -40,11 +43,12 @@ def setUp(self): - 0.01128010425623538 * (Z ^ Z) \ + 0.18093119978423156 * (X ^ X) - def test_vqe_2_iqpe(self): + @data('initial_state', 'circuit') + def test_vqe_2_iqpe(self, mode): """ vqe to iqpe test """ backend = BasicAer.get_backend('qasm_simulator') num_qbits = self.qubit_op.num_qubits - wavefunction = TwoLocal(num_qbits, ['ry', 'rz'], 'cz', reps=3, insert_barriers=True) + wavefunction = TwoLocal(num_qbits, ['ry', 'rz'], 'cz', reps=3) optimizer = SPSA(maxiter=10) algo = VQE(self.qubit_op, wavefunction, optimizer) @@ -61,7 +65,12 @@ def test_vqe_2_iqpe(self): num_iterations = 6 param_dict = result.optimal_parameters - state_in = VarFormBased(wavefunction, param_dict) + if mode == 'initial_state': + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + state_in = VarFormBased(wavefunction, param_dict) + else: + state_in = wavefunction.assign_parameters(param_dict) iqpe = IQPE(self.qubit_op, state_in, num_time_slices, num_iterations, expansion_mode='suzuki', expansion_order=2, From 96d5eb8160faa3ca3c98d9ce7ba5bba97e780083 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 13:55:07 +0200 Subject: [PATCH 13/22] fix running tests & mypy --- qiskit/chemistry/components/initial_states/hartree_fock.py | 4 ++-- test/chemistry/test_end2end_with_qpe.py | 3 +-- test/chemistry/test_initial_state_hartree_fock.py | 1 - test/chemistry/test_initial_state_vscf.py | 7 +++---- test/chemistry/test_vqe_uccsd_adapt.py | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index a4aa9342d5..519b0c88a9 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -54,7 +54,7 @@ def __init__(self, if qubit_mapping != 'parity' and two_qubit_reduction: warnings.warn('two_qubit_reduction only works with parity qubit mapping ' 'but you have %s. We switch two_qubit_reduction ' - 'to False.', qubit_mapping) + 'to False.' % qubit_mapping) two_qubit_reduction = False if isinstance(num_particles, list): @@ -62,7 +62,7 @@ def __init__(self, 'tuple of two integers, not a list. This behavious is deprecated as of ' 'Aqua 0.9 and will be removed no earlier than 3 months after the ' 'release.', DeprecationWarning, stacklevel=2) - num_particles = tuple(num_particles) + num_particles = tuple(num_particles) # type: ignore # get the bitstring encoding the Hartree Fock state bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, diff --git a/test/chemistry/test_end2end_with_qpe.py b/test/chemistry/test_end2end_with_qpe.py index 0a14854caf..f990dfdc50 100644 --- a/test/chemistry/test_end2end_with_qpe.py +++ b/test/chemistry/test_end2end_with_qpe.py @@ -24,8 +24,7 @@ from qiskit.aqua.operators import Z2Symmetries from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry import FermionicOperator, QiskitChemistryError -# from qiskit.chemistry.components.initial_states import HartreeFock -from qiskit.chemistry.components.initial_states.hf import HartreeFock +from qiskit.chemistry.components.initial_states import HartreeFock @ddt diff --git a/test/chemistry/test_initial_state_hartree_fock.py b/test/chemistry/test_initial_state_hartree_fock.py index aa00fec64b..73d736c576 100644 --- a/test/chemistry/test_initial_state_hartree_fock.py +++ b/test/chemistry/test_initial_state_hartree_fock.py @@ -19,7 +19,6 @@ from ddt import ddt, idata, unpack from qiskit import QuantumCircuit from qiskit.chemistry.components.initial_states import HartreeFock -# from qiskit.chemistry.components.initial_states.hf import HartreeFock as HartreeFock from qiskit.aqua.operators.legacy import op_converter from qiskit.chemistry import QiskitChemistryError from qiskit.chemistry.drivers import PySCFDriver, UnitsType diff --git a/test/chemistry/test_initial_state_vscf.py b/test/chemistry/test_initial_state_vscf.py index 9c8a8b14a2..567e83a6e5 100644 --- a/test/chemistry/test_initial_state_vscf.py +++ b/test/chemistry/test_initial_state_vscf.py @@ -17,8 +17,7 @@ from test.chemistry import QiskitChemistryTestCase import numpy as np from qiskit import QuantumCircuit -from qiskit.chemistry.components.initial_states import VSCF as VSCFI -from qiskit.chemistry.components.initial_states.vscf_circuit import VSCF +from qiskit.chemistry.components.initial_states import VSCF as VSCF class TestInitialStateVSCF(QiskitChemistryTestCase): @@ -35,7 +34,7 @@ def tearDown(self): def test_qubits_4(self): """ 2 modes 2 modals - test """ basis = [2, 2] - vscf = VSCFI(basis) + vscf = VSCF(basis) cct = vscf.construct_circuit('vector') np.testing.assert_array_equal(cct, [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) @@ -43,7 +42,7 @@ def test_qubits_4(self): def test_qubits_5(self): """ 2 modes 2 modals for the first mode and 3 modals for the second - test """ basis = [2, 3] - vscf = VSCFI(basis) + vscf = VSCF(basis) cct = vscf.construct_circuit('vector') np.testing.assert_array_equal(cct, [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, diff --git a/test/chemistry/test_vqe_uccsd_adapt.py b/test/chemistry/test_vqe_uccsd_adapt.py index 1052f927c7..66c79b6703 100644 --- a/test/chemistry/test_vqe_uccsd_adapt.py +++ b/test/chemistry/test_vqe_uccsd_adapt.py @@ -21,7 +21,7 @@ from qiskit.aqua.operators.legacy.weighted_pauli_operator import Z2Symmetries from qiskit.chemistry import FermionicOperator from qiskit.chemistry.algorithms import VQEAdapt -from qiskit.chemistry.components.initial_states.hf import HartreeFock +from qiskit.chemistry.components.initial_states import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry import QiskitChemistryError From ac2970d992078b1f1f3124745e34016d05b0d75a Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 14:11:51 +0200 Subject: [PATCH 14/22] add reno --- ...ecate-initial-states-61cd9f2842971ccb.yaml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 releasenotes/notes/deprecate-initial-states-61cd9f2842971ccb.yaml diff --git a/releasenotes/notes/deprecate-initial-states-61cd9f2842971ccb.yaml b/releasenotes/notes/deprecate-initial-states-61cd9f2842971ccb.yaml new file mode 100644 index 0000000000..2a28ce8fa3 --- /dev/null +++ b/releasenotes/notes/deprecate-initial-states-61cd9f2842971ccb.yaml @@ -0,0 +1,24 @@ +--- +features: + - | + The ``HartreeFock`` and ``VSCF`` initial state components are now circuits, + so they provide all methods and flexibility of the ``QuantumCircuit`` object. +deprecations: + - | + The ``InitialState`` object and derived classes, as well as the ``VarFormBased`` + class, have been deprecated. Instead, the ``QuantumCircuit`` can be used. + The individual classes emit deprecation warnings on how they can be replaced, + but here is a short overview. + + .. code-block:: + + InitialState component | How to replace + -----------------------+---------------------------------------------------------------- + Zero | an empty QuantumCircuit + Custom(circuit) | use the circuit directly as input + Custom(state_vector) | qc = QuantumCircuit(n) + | qc.initialize(state_vector, qc.qubits) # normalize vector! + Custom('random') | use the initialize instruction with random amplitudes + VarFormBased | use the circuit of the variational form directly + HartreeFock | has been replaced in-place, can still use this class + VSCF | has been replaced in-place, can still use this class From e0f7553450ec2d0b82983408bdffa364f8eb2f22 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 16:31:31 +0200 Subject: [PATCH 15/22] update more tests --- .../components/variational_forms/uccsd.py | 6 +++--- test/aqua/test_iqpe.py | 19 +++++++++++++------ test/chemistry/test_initial_state_vscf.py | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/qiskit/chemistry/components/variational_forms/uccsd.py b/qiskit/chemistry/components/variational_forms/uccsd.py index bcbb78d7b5..eaddde1575 100644 --- a/qiskit/chemistry/components/variational_forms/uccsd.py +++ b/qiskit/chemistry/components/variational_forms/uccsd.py @@ -380,11 +380,11 @@ def construct_circuit(self, parameters, q=None): if q is None: q = QuantumRegister(self._num_qubits, name='q') - if isinstance(self._initial_state, InitialState): - circuit = self._initial_state.construct_circuit('circuit', q) - elif isinstance(self._initial_state, QuantumCircuit): + if isinstance(self._initial_state, QuantumCircuit): circuit = QuantumCircuit(q) circuit.compose(self._initial_state, inplace=True) + elif isinstance(self._initial_state, InitialState): + circuit = self._initial_state.construct_circuit('circuit', q) else: circuit = QuantumCircuit(q) diff --git a/test/aqua/test_iqpe.py b/test/aqua/test_iqpe.py index af5f5d0fda..d089791d3f 100644 --- a/test/aqua/test_iqpe.py +++ b/test/aqua/test_iqpe.py @@ -13,10 +13,11 @@ """ Test IQPE """ import unittest +import warnings from test.aqua import QiskitAquaTestCase import numpy as np from ddt import ddt, idata, unpack -from qiskit import BasicAer +from qiskit import BasicAer, QuantumCircuit from qiskit.aqua import QuantumInstance from qiskit.aqua.utils import decimal_to_binary from qiskit.aqua.algorithms import IQPE @@ -67,12 +68,12 @@ def setUp(self): } @idata([ - ['QUBIT_OP_SIMPLE', 'qasm_simulator', 1, 5], - ['QUBIT_OP_ZZ', 'statevector_simulator', 1, 1], - ['QUBIT_OP_H2_WITH_2_QUBIT_REDUCTION', 'statevector_simulator', 1, 6], + ['QUBIT_OP_SIMPLE', 'qasm_simulator', 1, 5, True], + ['QUBIT_OP_ZZ', 'statevector_simulator', 1, 1, False], + ['QUBIT_OP_H2_WITH_2_QUBIT_REDUCTION', 'statevector_simulator', 1, 6, True], ]) @unpack - def test_iqpe(self, qubit_op, simulator, num_time_slices, num_iterations): + def test_iqpe(self, qubit_op, simulator, num_time_slices, num_iterations, use_circuits): """ iqpe test """ self.log.debug('Testing IQPE') qubit_op = self._dict[qubit_op] @@ -84,7 +85,13 @@ def test_iqpe(self, qubit_op, simulator, num_time_slices, num_iterations): self.log.debug('The exact eigenvalue is: %s', ref_eigenval) self.log.debug('The corresponding eigenvector: %s', ref_eigenvec) - state_in = Custom(qubit_op.num_qubits, state_vector=ref_eigenvec) + if use_circuits: + state_in = QuantumCircuit(qubit_op.num_qubits) + state_in.initialize(ref_eigenvec, state_in.qubits) + else: + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + state_in = Custom(qubit_op.num_qubits, state_vector=ref_eigenvec) iqpe = IQPE(qubit_op, state_in, num_time_slices, num_iterations, expansion_mode='suzuki', expansion_order=2, shallow_circuit_concat=True) diff --git a/test/chemistry/test_initial_state_vscf.py b/test/chemistry/test_initial_state_vscf.py index 567e83a6e5..0d579135d0 100644 --- a/test/chemistry/test_initial_state_vscf.py +++ b/test/chemistry/test_initial_state_vscf.py @@ -17,7 +17,7 @@ from test.chemistry import QiskitChemistryTestCase import numpy as np from qiskit import QuantumCircuit -from qiskit.chemistry.components.initial_states import VSCF as VSCF +from qiskit.chemistry.components.initial_states import VSCF class TestInitialStateVSCF(QiskitChemistryTestCase): From 9a09cf75195f4875644f4fb8a553e629578ef06a Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 17:40:44 +0200 Subject: [PATCH 16/22] do not convert sqlist to array --- qiskit/chemistry/components/initial_states/hartree_fock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index 519b0c88a9..63ab43b498 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -163,7 +163,7 @@ def _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reductio bitstr = new_bitstr.astype(np.bool) if sq_list is not None: - sq_list = (len(bitstr) - 1) - np.asarray(sq_list) + sq_list = [len(bitstr) - 1 - position for position in sq_list] bitstr = np.delete(bitstr, sq_list) return bitstr.astype(np.bool) From e8fff1bf1a77d7178d6b0863f2842ebd79db6e03 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 20 Oct 2020 19:08:39 +0200 Subject: [PATCH 17/22] fix iqpe test --- qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py | 2 +- test/aqua/test_iqpe.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py b/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py index 36bfe4ec49..a7c24d6369 100644 --- a/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py +++ b/qiskit/aqua/algorithms/minimum_eigen_solvers/iqpe.py @@ -193,7 +193,7 @@ def construct_circuit(self, self._state_register = q qc = QuantumCircuit(q) if isinstance(self._state_in, QuantumCircuit): - qc.append(self._state_in.to_gate(), q) + qc.append(self._state_in, q) else: qc += self._state_in.construct_circuit('circuit', q) # hadamard on a[0] diff --git a/test/aqua/test_iqpe.py b/test/aqua/test_iqpe.py index d089791d3f..b30a5e0ab0 100644 --- a/test/aqua/test_iqpe.py +++ b/test/aqua/test_iqpe.py @@ -87,7 +87,7 @@ def test_iqpe(self, qubit_op, simulator, num_time_slices, num_iterations, use_ci if use_circuits: state_in = QuantumCircuit(qubit_op.num_qubits) - state_in.initialize(ref_eigenvec, state_in.qubits) + state_in.initialize(ref_eigenvec.primitive.data, state_in.qubits) else: with warnings.catch_warnings(): warnings.filterwarnings('ignore', category=DeprecationWarning) From 888047ac3f59098135bdcc1dcaaa5d70eb210a40 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 26 Oct 2020 13:34:52 +0100 Subject: [PATCH 18/22] fix variable renaming from merge --- qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py b/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py index abea0c7b98..f124d46773 100755 --- a/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py +++ b/qiskit/aqua/algorithms/minimum_eigen_solvers/qaoa/var_form.py @@ -83,9 +83,9 @@ def construct_circuit(self, parameters, q=None): # initialize circuit, possibly based on given register/initial state if isinstance(self._initial_state, QuantumCircuit): - init_state = CircuitStateFn(self._initial_state) + circuit = CircuitStateFn(self._initial_state) elif self._initial_state is not None: - init_state = CircuitStateFn(self._initial_state.construct_circuit('circuit')) + circuit = CircuitStateFn(self._initial_state.construct_circuit('circuit')) else: circuit = (H ^ self._num_qubits) From 608aadeed059792f4f553b602ffbb1af90df2f9f Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Tue, 27 Oct 2020 16:13:45 +0100 Subject: [PATCH 19/22] move to circuit.lib and use tuple - move the initial state circuit to chemistry.circuit.library - globally replace num_particles by a tuple instead of list of integers --- README.md | 7 +- .../legacy/weighted_pauli_operator.py | 2 +- .../vqe_uccsd_factory.py | 2 +- .../molecular_ground_state_energy.py | 2 +- qiskit/chemistry/circuit/library/__init__.py | 39 ++++++ .../library/initial_states/__init__.py | 18 +++ .../library/initial_states/hartree_fock.py | 116 ++++++++++++++++++ .../circuit/library/initial_states/vscf.py | 60 +++++++++ .../components/initial_states/hartree_fock.py | 88 ++----------- .../components/initial_states/vscf.py | 42 ++----- .../components/variational_forms/uccsd.py | 8 +- qiskit/chemistry/core/hamiltonian.py | 14 +-- .../fermionic_transformation.py | 14 +-- .../circuit/library/test_hartree_fock.py | 62 ++++++++++ test/chemistry/circuit/library/test_vscf.py | 44 +++++++ test/chemistry/test_adapt_vqe.py | 2 +- test/chemistry/test_app_mgse.py | 2 +- test/chemistry/test_bopes_sampler.py | 5 +- test/chemistry/test_chc_vscf.py | 5 +- test/chemistry/test_core_hamiltonian.py | 2 +- .../test_core_hamiltonian_orb_reduce.py | 10 +- test/chemistry/test_end2end_with_iqpe.py | 2 +- test/chemistry/test_end2end_with_qpe.py | 2 +- .../test_fermionic_transformation.py | 2 +- ...est_fermionic_transformation_orb_reduce.py | 10 +- .../test_initial_state_hartree_fock.py | 41 ------- test/chemistry/test_initial_state_vscf.py | 25 +--- test/chemistry/test_qeom_vqe.py | 2 +- test/chemistry/test_readme_sample.py | 7 +- test/chemistry/test_swaprz.py | 5 +- test/chemistry/test_symmetries.py | 2 +- test/chemistry/test_uccsd_advanced.py | 2 +- test/chemistry/test_uccsd_hartree_fock.py | 5 +- test/chemistry/test_uvcc_vscf.py | 5 +- test/chemistry/test_vqe_uccsd_adapt.py | 2 +- 35 files changed, 431 insertions(+), 225 deletions(-) create mode 100644 qiskit/chemistry/circuit/library/__init__.py create mode 100644 qiskit/chemistry/circuit/library/initial_states/__init__.py create mode 100644 qiskit/chemistry/circuit/library/initial_states/hartree_fock.py create mode 100644 qiskit/chemistry/circuit/library/initial_states/vscf.py create mode 100644 test/chemistry/circuit/library/test_hartree_fock.py create mode 100644 test/chemistry/circuit/library/test_vscf.py diff --git a/README.md b/README.md index 12df2a29a7..5c9275036c 100644 --- a/README.md +++ b/README.md @@ -223,12 +223,15 @@ from qiskit.aqua.components.optimizers import L_BFGS_B optimizer = L_BFGS_B() # setup the initial state for the variational form -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock init_state = HartreeFock(num_spin_orbitals, num_particles) # setup the variational form for VQE from qiskit.circuit.library import TwoLocal -var_form = TwoLocal(num_qubits, ['ry', 'rz'], 'cz', initial_state=init_state) +var_form = TwoLocal(num_qubits, ['ry', 'rz'], 'cz') + +# add the initial state +var_form.compose(init_state, front=True) # setup and run VQE from qiskit.aqua.algorithms import VQE diff --git a/qiskit/aqua/operators/legacy/weighted_pauli_operator.py b/qiskit/aqua/operators/legacy/weighted_pauli_operator.py index 0893cbf863..4f1ab27649 100644 --- a/qiskit/aqua/operators/legacy/weighted_pauli_operator.py +++ b/qiskit/aqua/operators/legacy/weighted_pauli_operator.py @@ -1250,7 +1250,7 @@ def two_qubit_reduction(operator, num_particles): "Return the empty operator back.") return operator - if isinstance(num_particles, list): + if isinstance(num_particles, (tuple, list)): num_alpha = num_particles[0] num_beta = num_particles[1] else: diff --git a/qiskit/chemistry/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uccsd_factory.py b/qiskit/chemistry/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uccsd_factory.py index c1623f6d4c..eb430d20e3 100644 --- a/qiskit/chemistry/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uccsd_factory.py +++ b/qiskit/chemistry/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_uccsd_factory.py @@ -22,7 +22,7 @@ from ....components.variational_forms import UCCSD from ....transformations import Transformation from ....transformations.fermionic_transformation import FermionicTransformation -from ....components.initial_states import HartreeFock +from ....circuit.library import HartreeFock from .minimum_eigensolver_factory import MinimumEigensolverFactory diff --git a/qiskit/chemistry/applications/molecular_ground_state_energy.py b/qiskit/chemistry/applications/molecular_ground_state_energy.py index eecec094e5..63521f284b 100644 --- a/qiskit/chemistry/applications/molecular_ground_state_energy.py +++ b/qiskit/chemistry/applications/molecular_ground_state_energy.py @@ -21,7 +21,7 @@ from qiskit.aqua.algorithms import MinimumEigensolver, VQE from qiskit.aqua.operators import Z2Symmetries from qiskit.chemistry import QiskitChemistryError -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.core import (Hamiltonian, TransformationType, QubitMappingType, ChemistryOperator, MolecularGroundStateResult) diff --git a/qiskit/chemistry/circuit/library/__init__.py b/qiskit/chemistry/circuit/library/__init__.py new file mode 100644 index 0000000000..036a8bee87 --- /dev/null +++ b/qiskit/chemistry/circuit/library/__init__.py @@ -0,0 +1,39 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +=================================================================== +Chemistry Circuit Library (:mod:`qiskit.chemistry.circuit.library`) +=================================================================== + +A collection of circuits used as building blocks or inputs of algorithms in chemistry. + +.. currentmodule:: qiskit.chemistry.circuit.library + +Initial states +============== + +.. autosummary:: + :toctree: ../stubs/ + :nosignatures: + + HartreeFock + VSCF + +""" + +from .initial_states import ( + HartreeFock, + VSCF +) + +__all__ = ['HartreeFock', 'VSCF'] diff --git a/qiskit/chemistry/circuit/library/initial_states/__init__.py b/qiskit/chemistry/circuit/library/initial_states/__init__.py new file mode 100644 index 0000000000..82b47043a6 --- /dev/null +++ b/qiskit/chemistry/circuit/library/initial_states/__init__.py @@ -0,0 +1,18 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Initial state circuits.""" + +from .hartree_fock import HartreeFock +from .vscf import VSCF + +__all__ = ['HartreeFock', 'VSCF'] diff --git a/qiskit/chemistry/circuit/library/initial_states/hartree_fock.py b/qiskit/chemistry/circuit/library/initial_states/hartree_fock.py new file mode 100644 index 0000000000..c279a0f089 --- /dev/null +++ b/qiskit/chemistry/circuit/library/initial_states/hartree_fock.py @@ -0,0 +1,116 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Hartree-Fock initial state.""" + +import warnings +from typing import Optional, Union, List, Tuple +import logging +import numpy as np +from qiskit import QuantumRegister, QuantumCircuit +from qiskit.aqua.utils.validation import validate_min, validate_in_set + +logger = logging.getLogger(__name__) + + +class HartreeFock(QuantumCircuit): + """A Hartree-Fock initial state.""" + + def __init__(self, + num_orbitals: int, + num_particles: Union[Tuple[int, int], int], + qubit_mapping: str = 'parity', + two_qubit_reduction: bool = True, + sq_list: Optional[List[int]] = None) -> None: + """ + Args: + num_orbitals: number of spin orbitals, has a min. value of 1. + num_particles: number of particles, if it is a list, the first number + is alpha and the second number if beta. + qubit_mapping: mapping type for qubit operator + two_qubit_reduction: flag indicating whether or not two qubit is reduced + sq_list: position of the single-qubit operators that + anticommute with the cliffords + + Raises: + ValueError: wrong setting in num_particles and num_orbitals. + ValueError: wrong setting for computed num_qubits and supplied num_qubits. + """ + # validate the input + validate_min('num_orbitals', num_orbitals, 1) + validate_in_set('qubit_mapping', qubit_mapping, + {'jordan_wigner', 'parity', 'bravyi_kitaev'}) + + if qubit_mapping != 'parity' and two_qubit_reduction: + warnings.warn('two_qubit_reduction only works with parity qubit mapping ' + 'but you have %s. We switch two_qubit_reduction ' + 'to False.' % qubit_mapping) + two_qubit_reduction = False + + # get the bitstring encoding the Hartree Fock state + bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, + two_qubit_reduction, sq_list) + + # construct the circuit + qr = QuantumRegister(len(bitstr), 'q') + super().__init__(qr, name='HF') + + # add gates in the right positions + for i, bit in enumerate(reversed(bitstr)): + if bit: + self.x(i) + + +def _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction=True, + sq_list=None): + if isinstance(num_particles, tuple): + num_alpha, num_beta = num_particles + else: + logger.info('We assume that the number of alphas and betas are the same.') + num_alpha = num_beta = num_particles // 2 + + num_particles = num_alpha + num_beta + + if num_particles > num_orbitals: + raise ValueError('# of particles must be less than or equal to # of orbitals.') + + half_orbitals = num_orbitals // 2 + bitstr = np.zeros(num_orbitals, np.bool) + bitstr[-num_alpha:] = True + bitstr[-(half_orbitals + num_beta):-half_orbitals] = True + + if qubit_mapping == 'parity': + new_bitstr = bitstr.copy() + + t_r = np.triu(np.ones((num_orbitals, num_orbitals))) + new_bitstr = t_r.dot(new_bitstr.astype(np.int)) % 2 # pylint: disable=no-member + + bitstr = np.append(new_bitstr[1:half_orbitals], new_bitstr[half_orbitals + 1:]) \ + if two_qubit_reduction else new_bitstr + + elif qubit_mapping == 'bravyi_kitaev': + binary_superset_size = int(np.ceil(np.log2(num_orbitals))) + beta = 1 + basis = np.asarray([[1, 0], [0, 1]]) + for _ in range(binary_superset_size): + beta = np.kron(basis, beta) + beta[0, :] = 1 + start_idx = beta.shape[0] - num_orbitals + beta = beta[start_idx:, start_idx:] + new_bitstr = beta.dot(bitstr.astype(int)) % 2 + bitstr = new_bitstr.astype(np.bool) + + if sq_list is not None: + sq_list = [len(bitstr) - 1 - position for position in sq_list] + bitstr = np.delete(bitstr, sq_list) + + return bitstr.astype(np.bool) diff --git a/qiskit/chemistry/circuit/library/initial_states/vscf.py b/qiskit/chemistry/circuit/library/initial_states/vscf.py new file mode 100644 index 0000000000..8a877e6edc --- /dev/null +++ b/qiskit/chemistry/circuit/library/initial_states/vscf.py @@ -0,0 +1,60 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Initial state for vibrational modes.""" + +from typing import List + +import numpy as np + +from qiskit import QuantumRegister, QuantumCircuit + + +class VSCF(QuantumCircuit): + r"""Initial state for vibrational modes. + + Creates an occupation number vector as defined in [1]. + As example, for 2 modes with 4 modals per mode it creates: :math:`|1000 1000\rangle`. + + References: + + [1] Ollitrault Pauline J., Chemical science 11 (2020): 6842-6855. + """ + + def __init__(self, basis: List[int]) -> None: + """ + Args: + basis: Is a list defining the number of modals per mode. E.g. for a 3 modes system + with 4 modals per mode basis = [4,4,4] + """ + # get the bitstring encoding initial state + bitstr = _build_bitstr(basis) + + # construct the circuit + qr = QuantumRegister(len(bitstr), 'q') + super().__init__(qr, name='VSCF') + + # add gates in the right positions + for i, bit in enumerate(reversed(bitstr)): + if bit: + self.x(i) + + +def _build_bitstr(basis): + num_qubits = sum(basis) + bitstr = np.zeros(num_qubits, np.bool) + count = 0 + for modal in basis: + bitstr[num_qubits - count - 1] = True + count += modal + + return bitstr diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index 63ab43b498..74579f0e00 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -13,22 +13,23 @@ """Hartree-Fock initial state.""" import warnings -from typing import Optional, Union, List, Tuple +from typing import Optional, Union, List import logging import numpy as np from qiskit import QuantumRegister, QuantumCircuit from qiskit.aqua.utils.validation import validate_min, validate_in_set from qiskit.aqua.components.initial_states import InitialState +from qiskit.chemistry.circuit.library.initial_states.hartree_fock import _build_bitstr logger = logging.getLogger(__name__) -class HartreeFock(QuantumCircuit, InitialState): +class HartreeFock(InitialState): """A Hartree-Fock initial state.""" def __init__(self, num_orbitals: int, - num_particles: Union[Tuple[int, int], List[int], int], + num_particles: Union[List[int], int], qubit_mapping: str = 'parity', two_qubit_reduction: bool = True, sq_list: Optional[List[int]] = None) -> None: @@ -57,27 +58,16 @@ def __init__(self, 'to False.' % qubit_mapping) two_qubit_reduction = False - if isinstance(num_particles, list): - warnings.warn('The ``num_particles`` argument should either be a single integer or a ' - 'tuple of two integers, not a list. This behavious is deprecated as of ' - 'Aqua 0.9 and will be removed no earlier than 3 months after the ' - 'release.', DeprecationWarning, stacklevel=2) - num_particles = tuple(num_particles) # type: ignore + super().__init__() # get the bitstring encoding the Hartree Fock state + if isinstance(num_particles, list): + num_particles = tuple(num_particles) + bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction, sq_list) self._bitstr = bitstr - # construct the circuit - qr = QuantumRegister(len(bitstr), 'q') - super().__init__(qr, name='HF') - - # add gates in the right positions - for i, bit in enumerate(reversed(bitstr)): - if bit: - self.x(i) - def construct_circuit(self, mode='circuit', register=None): """Construct the statevector of desired initial state. @@ -93,10 +83,6 @@ def construct_circuit(self, mode='circuit', register=None): Raises: ValueError: when mode is not 'vector' or 'circuit'. """ - warnings.warn('The HartreeFock.construct_circuit method is deprecated as of Aqua 0.9.0 and ' - 'will be removed no earlier than 3 months after the release. The HarteeFock ' - 'class is now a QuantumCircuit instance and can directly be used as such.', - DeprecationWarning, stacklevel=2) if mode == 'vector': state = 1.0 one = np.asarray([0.0, 1.0]) @@ -106,9 +92,11 @@ def construct_circuit(self, mode='circuit', register=None): return state elif mode == 'circuit': if register is None: - register = QuantumRegister(self.num_qubits, name='q') - quantum_circuit = QuantumCircuit(register) - quantum_circuit.compose(self, inplace=True) + register = QuantumRegister(len(self.bitstr), name='q') + quantum_circuit = QuantumCircuit(register, name='HF') + for i, bit in enumerate(reversed(self.bitstr)): + if bit: + quantum_circuit.x(i) return quantum_circuit else: raise ValueError('Mode should be either "vector" or "circuit"') @@ -116,54 +104,4 @@ def construct_circuit(self, mode='circuit', register=None): @property def bitstr(self): """Getter of the bit string represented the statevector.""" - warnings.warn('The HartreeFock.bitstr property is deprecated as of Aqua 0.9.0 and will be ' - 'removed no earlier than 3 months after the release. To get the bitstring ' - 'you can use the quantum_info.Statevector class and the probabilities_dict ' - 'method.', DeprecationWarning, stacklevel=2) return self._bitstr - - -def _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction=True, - sq_list=None): - if isinstance(num_particles, tuple): - num_alpha, num_beta = num_particles - else: - logger.info('We assume that the number of alphas and betas are the same.') - num_alpha = num_beta = num_particles // 2 - - num_particles = num_alpha + num_beta - - if num_particles > num_orbitals: - raise ValueError('# of particles must be less than or equal to # of orbitals.') - - half_orbitals = num_orbitals // 2 - bitstr = np.zeros(num_orbitals, np.bool) - bitstr[-num_alpha:] = True - bitstr[-(half_orbitals + num_beta):-half_orbitals] = True - - if qubit_mapping == 'parity': - new_bitstr = bitstr.copy() - - t_r = np.triu(np.ones((num_orbitals, num_orbitals))) - new_bitstr = t_r.dot(new_bitstr.astype(np.int)) % 2 # pylint: disable=no-member - - bitstr = np.append(new_bitstr[1:half_orbitals], new_bitstr[half_orbitals + 1:]) \ - if two_qubit_reduction else new_bitstr - - elif qubit_mapping == 'bravyi_kitaev': - binary_superset_size = int(np.ceil(np.log2(num_orbitals))) - beta = 1 - basis = np.asarray([[1, 0], [0, 1]]) - for _ in range(binary_superset_size): - beta = np.kron(basis, beta) - beta[0, :] = 1 - start_idx = beta.shape[0] - num_orbitals - beta = beta[start_idx:, start_idx:] - new_bitstr = beta.dot(bitstr.astype(int)) % 2 - bitstr = new_bitstr.astype(np.bool) - - if sq_list is not None: - sq_list = [len(bitstr) - 1 - position for position in sq_list] - bitstr = np.delete(bitstr, sq_list) - - return bitstr.astype(np.bool) diff --git a/qiskit/chemistry/components/initial_states/vscf.py b/qiskit/chemistry/components/initial_states/vscf.py index 5893ed81dd..8a0b73b5ad 100644 --- a/qiskit/chemistry/components/initial_states/vscf.py +++ b/qiskit/chemistry/components/initial_states/vscf.py @@ -13,7 +13,6 @@ """ Initial state for vibrational modes. """ import logging -import warnings from typing import List import numpy as np @@ -21,10 +20,12 @@ from qiskit import QuantumRegister, QuantumCircuit from qiskit.aqua.components.initial_states import InitialState +from qiskit.chemistry.circuit.library.initial_states.vscf import _build_bitstr + logger = logging.getLogger(__name__) -class VSCF(QuantumCircuit, InitialState): +class VSCF(InitialState): r"""Initial state for vibrational modes. Creates an occupation number vector as defined in @@ -42,14 +43,7 @@ def __init__(self, basis: List[int]) -> None: bitstr = _build_bitstr(basis) self._bitstr = bitstr - # construct the circuit - qr = QuantumRegister(len(bitstr), 'q') - super().__init__(qr, name='VSCF') - - # add gates in the right positions - for i, bit in enumerate(reversed(bitstr)): - if bit: - self.x(i) + super().__init__() def construct_circuit(self, mode='circuit', register=None): """Construct the statevector of desired initial state. @@ -66,10 +60,6 @@ def construct_circuit(self, mode='circuit', register=None): Raises: ValueError: when mode is not 'vector' or 'circuit'. """ - warnings.warn('The VSCF.construct_circuit method is deprecated as of Aqua 0.9.0 and ' - 'will be removed no earlier than 3 months after the release. The HarteeFock ' - 'class is now a QuantumCircuit instance and can directly be used as such.', - DeprecationWarning, stacklevel=2) if mode == 'vector': state = 1.0 one = np.asarray([0.0, 1.0]) @@ -79,9 +69,12 @@ def construct_circuit(self, mode='circuit', register=None): return state elif mode == 'circuit': if register is None: - register = QuantumRegister(self.num_qubits, name='q') - quantum_circuit = QuantumCircuit(register) - quantum_circuit.compose(self, inplace=True) + register = QuantumRegister(len(self.bitstr), name='q') + quantum_circuit = QuantumCircuit(register, name='VSCF') + for i, bit in enumerate(reversed(self.bitstr)): + if bit: + quantum_circuit.x(i) + return quantum_circuit else: raise ValueError('Mode should be either "vector" or "circuit"') @@ -89,19 +82,4 @@ def construct_circuit(self, mode='circuit', register=None): @property def bitstr(self): """Getter of the bit string represented the statevector.""" - warnings.warn('The VSCF.bitstr property is deprecated as of Aqua 0.9.0 and will be ' - 'removed no earlier than 3 months after the release. To get the bitstring ' - 'you can use the quantum_info.Statevector class and the probabilities_dict ' - 'method.', DeprecationWarning, stacklevel=2) return self._bitstr - - -def _build_bitstr(basis): - num_qubits = sum(basis) - bitstr = np.zeros(num_qubits, np.bool) - count = 0 - for modal in basis: - bitstr[num_qubits - count - 1] = True - count += modal - - return bitstr diff --git a/qiskit/chemistry/components/variational_forms/uccsd.py b/qiskit/chemistry/components/variational_forms/uccsd.py index db62590826..0ec88d8e08 100644 --- a/qiskit/chemistry/components/variational_forms/uccsd.py +++ b/qiskit/chemistry/components/variational_forms/uccsd.py @@ -17,7 +17,7 @@ And for singlet q-UCCD (full) and pair q-UCCD see: https://arxiv.org/abs/1911.10864 """ -from typing import Optional, Union, List +from typing import Optional, Union, List, Tuple import logging import sys import collections @@ -48,7 +48,7 @@ class UCCSD(VariationalForm): def __init__(self, num_orbitals: int, - num_particles: Union[List[int], int], + num_particles: Union[Tuple[int, int], List[int], int], reps: int = 1, active_occupied: Optional[List[int]] = None, active_unoccupied: Optional[List[int]] = None, @@ -118,7 +118,7 @@ def __init__(self, else self._num_qubits - len(self._z2_symmetries.sq_list) self._reps = reps self._num_orbitals = num_orbitals - if isinstance(num_particles, list): + if isinstance(num_particles, (tuple, list)): self._num_alpha = num_particles[0] self._num_beta = num_particles[1] else: @@ -490,7 +490,7 @@ def compute_excitation_lists(num_particles, num_orbitals, active_occ_list=None, ValueError: invalid setting of number of orbitals """ - if isinstance(num_particles, list): + if isinstance(num_particles, (tuple, list)): num_alpha = num_particles[0] num_beta = num_particles[1] else: diff --git a/qiskit/chemistry/core/hamiltonian.py b/qiskit/chemistry/core/hamiltonian.py index 847be15fcb..9fe48891cd 100644 --- a/qiskit/chemistry/core/hamiltonian.py +++ b/qiskit/chemistry/core/hamiltonian.py @@ -26,7 +26,6 @@ from .chemistry_operator import (ChemistryOperator, MolecularGroundStateResult, DipoleTuple) -from ..components.initial_states import HartreeFock logger = logging.getLogger(__name__) @@ -264,7 +263,7 @@ def _dipole_op(dipole_integrals, axis): logger.info('Molecule num spin orbitals: %s, remaining for processing: %s', nspinorbs, new_nspinorbs) - self._add_molecule_info(self.INFO_NUM_PARTICLES, [new_num_alpha, new_num_beta]) + self._add_molecule_info(self.INFO_NUM_PARTICLES, (new_num_alpha, new_num_beta)) self._add_molecule_info(self.INFO_NUM_ORBITALS, new_nspinorbs) self._add_molecule_info(self.INFO_TWO_QUBIT_REDUCTION, self._two_qubit_reduction @@ -306,11 +305,12 @@ def _process_z2symmetry_reduction(self, qubit_op, aux_ops): aux_ops[i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': - hf_state = HartreeFock(num_orbitals=self._molecule_info[self.INFO_NUM_ORBITALS], - qubit_mapping=self._qubit_mapping, - two_qubit_reduction=self._two_qubit_reduction, - num_particles=self._molecule_info[self.INFO_NUM_PARTICLES]) - z2_symmetries = Hamiltonian._pick_sector(z2_symmetries, hf_state.bitstr) + from ..circuit.library.initial_states.hartree_fock import _build_bitstr + hf_bitstr = _build_bitstr(num_orbitals=self._molecule_info['num_orbitals'], + qubit_mapping=self._qubit_mapping, + two_qubit_reduction=self._two_qubit_reduction, + num_particles=self._molecule_info['num_particles']) + z2_symmetries = Hamiltonian._pick_sector(z2_symmetries, hf_bitstr) else: if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries): raise QiskitChemistryError('z2symmetry_reduction tapering values list has ' diff --git a/qiskit/chemistry/transformations/fermionic_transformation.py b/qiskit/chemistry/transformations/fermionic_transformation.py index 36e39b718a..e16c04bc59 100644 --- a/qiskit/chemistry/transformations/fermionic_transformation.py +++ b/qiskit/chemistry/transformations/fermionic_transformation.py @@ -33,7 +33,6 @@ from qiskit.chemistry.components.variational_forms import UCCSD from .transformation import Transformation -from ..components.initial_states import HartreeFock logger = logging.getLogger(__name__) @@ -364,7 +363,7 @@ def _dipole_op(dipole_integrals: np.ndarray, axis: str) \ logger.info('Molecule num spin orbitals: %s, remaining for processing: %s', nspinorbs, new_nspinorbs) - self._molecule_info['num_particles'] = [new_num_alpha, new_num_beta] + self._molecule_info['num_particles'] = (new_num_alpha, new_num_beta) self._molecule_info['num_orbitals'] = new_nspinorbs reduction = self._two_qubit_reduction if self._qubit_mapping == 'parity' else False self._molecule_info['two_qubit_reduction'] = reduction @@ -425,11 +424,12 @@ def _process_z2symmetry_reduction(self, aux_ops[i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': - hf_state = HartreeFock(num_orbitals=self._molecule_info['num_orbitals'], - qubit_mapping=self._qubit_mapping, - two_qubit_reduction=self._two_qubit_reduction, - num_particles=self._molecule_info['num_particles']) - z2_symmetries = FermionicTransformation._pick_sector(z2_symmetries, hf_state.bitstr) + from ..circuit.library.initial_states.hartree_fock import _build_bitstr + hf_bitstr = _build_bitstr(num_orbitals=self._molecule_info['num_orbitals'], + qubit_mapping=self._qubit_mapping, + two_qubit_reduction=self._two_qubit_reduction, + num_particles=self._molecule_info['num_particles']) + z2_symmetries = FermionicTransformation._pick_sector(z2_symmetries, hf_bitstr) else: if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries): raise QiskitChemistryError('z2symmetry_reduction tapering values list has ' diff --git a/test/chemistry/circuit/library/test_hartree_fock.py b/test/chemistry/circuit/library/test_hartree_fock.py new file mode 100644 index 0000000000..c91aa3dc86 --- /dev/null +++ b/test/chemistry/circuit/library/test_hartree_fock.py @@ -0,0 +1,62 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Test Hartree Fock initial state circuit.""" + +import unittest +from test.chemistry import QiskitChemistryTestCase + +from qiskit import QuantumCircuit +from qiskit.chemistry.circuit.library import HartreeFock + + +class TestHartreeFock(QiskitChemistryTestCase): + """ Initial State HartreeFock tests """ + + def test_qubits_4_jw_h2(self): + """ qubits 4 jw h2 test """ + state = HartreeFock(4, (1, 1), 'jordan_wigner', False) + ref = QuantumCircuit(4) + ref.x([0, 2]) + self.assertEqual(state, ref) + + def test_qubits_4_py_h2(self): + """ qubits 4 py h2 test """ + state = HartreeFock(4, (1, 1), 'parity', False) + ref = QuantumCircuit(4) + ref.x([0, 1]) + self.assertEqual(state, ref) + + def test_qubits_4_bk_h2(self): + """ qubits 4 bk h2 test """ + state = HartreeFock(4, (1, 1), 'bravyi_kitaev', False) + ref = QuantumCircuit(4) + ref.x([0, 1, 2]) + self.assertEqual(state, ref) + + def test_qubits_2_py_h2(self): + """ qubits 2 py h2 test """ + state = HartreeFock(4, 2, 'parity', True) + ref = QuantumCircuit(2) + ref.x(0) + self.assertEqual(state, ref) + + def test_qubits_6_py_lih(self): + """ qubits 6 py lih test """ + state = HartreeFock(10, (1, 1), 'parity', True, [1, 2]) + ref = QuantumCircuit(6) + ref.x([0, 1]) + self.assertEqual(state, ref) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/chemistry/circuit/library/test_vscf.py b/test/chemistry/circuit/library/test_vscf.py new file mode 100644 index 0000000000..dbc4e38a30 --- /dev/null +++ b/test/chemistry/circuit/library/test_vscf.py @@ -0,0 +1,44 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2020. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Test the VSCF initial state.""" + +import unittest +from test.chemistry import QiskitChemistryTestCase +from qiskit import QuantumCircuit +from qiskit.chemistry.circuit.library import VSCF + + +class TestVSCF(QiskitChemistryTestCase): + """ Initial State vscf tests """ + + def test_qubits_4(self): + """Test 2 modes 2 modals.""" + basis = [2, 2] + vscf = VSCF(basis) + ref = QuantumCircuit(4) + ref.x([0, 2]) + + self.assertEqual(ref, vscf) + + def test_qubits_5(self): + """Test 2 modes 2 modals for the first mode and 3 modals for the second.""" + basis = [2, 3] + vscf = VSCF(basis) + ref = QuantumCircuit(5) + ref.x([0, 2]) + + self.assertEqual(ref, vscf) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/chemistry/test_adapt_vqe.py b/test/chemistry/test_adapt_vqe.py index eee14a0a64..abd9f47ee5 100644 --- a/test/chemistry/test_adapt_vqe.py +++ b/test/chemistry/test_adapt_vqe.py @@ -20,7 +20,7 @@ from qiskit.aqua.algorithms import VQE from qiskit.chemistry import QiskitChemistryError from qiskit.chemistry.components.variational_forms import UCCSD -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.aqua.components.optimizers import L_BFGS_B from qiskit.chemistry.algorithms.ground_state_solvers import AdaptVQE, VQEUCCSDFactory from qiskit.chemistry.transformations import FermionicTransformation diff --git a/test/chemistry/test_app_mgse.py b/test/chemistry/test_app_mgse.py index ed6823210f..1e1b08ea9c 100644 --- a/test/chemistry/test_app_mgse.py +++ b/test/chemistry/test_app_mgse.py @@ -25,7 +25,7 @@ from qiskit.aqua.components.optimizers import SLSQP from qiskit.chemistry import QiskitChemistryError from qiskit.chemistry.applications import MolecularGroundStateEnergy -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.core import QubitMappingType from qiskit.chemistry.drivers import PySCFDriver, UnitsType diff --git a/test/chemistry/test_bopes_sampler.py b/test/chemistry/test_bopes_sampler.py index 97a7ec183e..1ee2538a33 100644 --- a/test/chemistry/test_bopes_sampler.py +++ b/test/chemistry/test_bopes_sampler.py @@ -23,7 +23,7 @@ from qiskit.aqua.components.optimizers import AQGD from qiskit.aqua.operators import PauliExpectation from qiskit.chemistry.algorithms.pes_samplers.bopes_sampler import BOPESSampler -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.drivers import Molecule, PySCFDriver from qiskit.chemistry.algorithms.ground_state_solvers import GroundStateEigensolver from qiskit.chemistry.algorithms.pes_samplers.potentials.morse_potential import MorsePotential @@ -65,7 +65,8 @@ def test_h2_bopes_sampler(self): sq_list=f_t._molecule_info['z2_symmetries'].sq_list ) var_form = RealAmplitudes(qubitop.num_qubits, reps=1, entanglement='full', - initial_state=i_state, skip_unentangled_qubits=False) + skip_unentangled_qubits=False) + var_form.compose(i_state, front=True) # Classical optimizer: # Analytic Quantum Gradient Descent (AQGD) (with Epochs) diff --git a/test/chemistry/test_chc_vscf.py b/test/chemistry/test_chc_vscf.py index 7bdfa9f421..bf26ef4219 100644 --- a/test/chemistry/test_chc_vscf.py +++ b/test/chemistry/test_chc_vscf.py @@ -13,6 +13,7 @@ """ Test of CHC and VSCF Aqua extensions """ import unittest +import warnings from test.chemistry import QiskitChemistryTestCase @@ -62,7 +63,9 @@ def test_chc_vscf(self): bosonic_op = BosonicOperator(co2_2modes_2modals_2body, basis) qubit_op = bosonic_op.mapping('direct', threshold=1e-5) - init_state = VSCF(basis) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + init_state = VSCF(basis) num_qubits = sum(basis) uvcc_varform = UVCC(num_qubits, basis, [0, 1]) diff --git a/test/chemistry/test_core_hamiltonian.py b/test/chemistry/test_core_hamiltonian.py index 227ffa3f9c..23b3597a76 100644 --- a/test/chemistry/test_core_hamiltonian.py +++ b/test/chemistry/test_core_hamiltonian.py @@ -44,7 +44,7 @@ def _validate_vars(self, core, energy_shift=0.0, ph_energy_shift=0.0): def _validate_info(self, core, num_particles=None, num_orbitals=4, actual_two_qubit_reduction=False): - num_particles = num_particles if num_particles is not None else [1, 1] + num_particles = num_particles if num_particles is not None else (1, 1) z2symmetries = core.molecule_info.pop('z2symmetries') self.assertEqual(z2symmetries.is_empty(), True) self.assertEqual(core.molecule_info, {'num_particles': num_particles, diff --git a/test/chemistry/test_core_hamiltonian_orb_reduce.py b/test/chemistry/test_core_hamiltonian_orb_reduce.py index 8573c43d61..8bd066b97c 100644 --- a/test/chemistry/test_core_hamiltonian_orb_reduce.py +++ b/test/chemistry/test_core_hamiltonian_orb_reduce.py @@ -44,7 +44,7 @@ def _validate_vars(self, core, energy_shift=0.0, ph_energy_shift=0.0): def _validate_info(self, core, num_particles=None, num_orbitals=12, actual_two_qubit_reduction=False): - num_particles = num_particles if num_particles is not None else [2, 2] + num_particles = num_particles if num_particles is not None else (2, 2) z2symmetries = core.molecule_info.pop('z2symmetries') self.assertEqual(z2symmetries.is_empty(), True) self.assertEqual(core.molecule_info, {'num_particles': num_particles, @@ -96,7 +96,7 @@ def test_freeze_core(self): warnings.filterwarnings('always', category=DeprecationWarning) qubit_op, _ = core.run(self.qmolecule) self._validate_vars(core, energy_shift=-7.7962196) - self._validate_info(core, num_particles=[1, 1], num_orbitals=10) + self._validate_info(core, num_particles=(1, 1), num_orbitals=10) self._validate_input_object(qubit_op, num_qubits=10, num_paulis=276) def test_freeze_core_orb_reduction(self): @@ -110,7 +110,7 @@ def test_freeze_core_orb_reduction(self): warnings.filterwarnings('always', category=DeprecationWarning) qubit_op, _ = core.run(self.qmolecule) self._validate_vars(core, energy_shift=-7.7962196) - self._validate_info(core, num_particles=[1, 1], num_orbitals=6) + self._validate_info(core, num_particles=(1, 1), num_orbitals=6) self._validate_input_object(qubit_op, num_qubits=6, num_paulis=118) def test_freeze_core_all_reduction(self): @@ -124,7 +124,7 @@ def test_freeze_core_all_reduction(self): warnings.filterwarnings('always', category=DeprecationWarning) qubit_op, _ = core.run(self.qmolecule) self._validate_vars(core, energy_shift=-7.7962196) - self._validate_info(core, num_particles=[1, 1], num_orbitals=6, + self._validate_info(core, num_particles=(1, 1), num_orbitals=6, actual_two_qubit_reduction=True) self._validate_input_object(qubit_op, num_qubits=4, num_paulis=100) @@ -139,7 +139,7 @@ def test_freeze_core_all_reduction_ph(self): warnings.filterwarnings('always', category=DeprecationWarning) qubit_op, _ = core.run(self.qmolecule) self._validate_vars(core, energy_shift=-7.7962196, ph_energy_shift=-1.05785247) - self._validate_info(core, num_particles=[1, 1], num_orbitals=6, + self._validate_info(core, num_particles=(1, 1), num_orbitals=6, actual_two_qubit_reduction=True) self._validate_input_object(qubit_op, num_qubits=4, num_paulis=52) diff --git a/test/chemistry/test_end2end_with_iqpe.py b/test/chemistry/test_end2end_with_iqpe.py index 459224563e..9441e4fc18 100644 --- a/test/chemistry/test_end2end_with_iqpe.py +++ b/test/chemistry/test_end2end_with_iqpe.py @@ -23,7 +23,7 @@ from qiskit.aqua.operators import Z2Symmetries from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry import FermionicOperator, QiskitChemistryError -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock @ddt diff --git a/test/chemistry/test_end2end_with_qpe.py b/test/chemistry/test_end2end_with_qpe.py index f990dfdc50..0261d54691 100644 --- a/test/chemistry/test_end2end_with_qpe.py +++ b/test/chemistry/test_end2end_with_qpe.py @@ -24,7 +24,7 @@ from qiskit.aqua.operators import Z2Symmetries from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry import FermionicOperator, QiskitChemistryError -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock @ddt diff --git a/test/chemistry/test_fermionic_transformation.py b/test/chemistry/test_fermionic_transformation.py index 0c5345f826..82ad8663ba 100644 --- a/test/chemistry/test_fermionic_transformation.py +++ b/test/chemistry/test_fermionic_transformation.py @@ -44,7 +44,7 @@ def _validate_vars(self, fermionic_transformation, energy_shift=0.0, ph_energy_s def _validate_info(self, fermionic_transformation, num_particles=None, num_orbitals=4, actual_two_qubit_reduction=False): - num_particles = num_particles if num_particles is not None else [1, 1] + num_particles = num_particles if num_particles is not None else (1, 1) z2symmetries = fermionic_transformation.molecule_info.pop('z2_symmetries') self.assertEqual(z2symmetries.is_empty(), True) self.assertEqual(fermionic_transformation.molecule_info, diff --git a/test/chemistry/test_fermionic_transformation_orb_reduce.py b/test/chemistry/test_fermionic_transformation_orb_reduce.py index 8a95edea1f..4d7f7ea635 100644 --- a/test/chemistry/test_fermionic_transformation_orb_reduce.py +++ b/test/chemistry/test_fermionic_transformation_orb_reduce.py @@ -43,7 +43,7 @@ def _validate_vars(self, fermionic_transformation, energy_shift=0.0, ph_energy_s def _validate_info(self, fermionic_transformation, num_particles=None, num_orbitals=12, actual_two_qubit_reduction=False): - num_particles = num_particles if num_particles is not None else [2, 2] + num_particles = num_particles if num_particles is not None else (2, 2) z2symmetries = fermionic_transformation.molecule_info.pop('z2_symmetries') self.assertEqual(z2symmetries.is_empty(), True) self.assertEqual(fermionic_transformation.molecule_info, @@ -96,7 +96,7 @@ def test_freeze_core(self): qubit_op, _ = fermionic_transformation.transform(self.driver) self._validate_vars(fermionic_transformation, energy_shift=-7.7962196) - self._validate_info(fermionic_transformation, num_particles=[1, 1], num_orbitals=10) + self._validate_info(fermionic_transformation, num_particles=(1, 1), num_orbitals=10) self._validate_input_object(qubit_op, num_qubits=10, num_paulis=276) def test_freeze_core_orb_reduction(self): @@ -110,7 +110,7 @@ def test_freeze_core_orb_reduction(self): qubit_op, _ = fermionic_transformation.transform(self.driver) self._validate_vars(fermionic_transformation, energy_shift=-7.7962196) - self._validate_info(fermionic_transformation, num_particles=[1, 1], num_orbitals=6) + self._validate_info(fermionic_transformation, num_particles=(1, 1), num_orbitals=6) self._validate_input_object(qubit_op, num_qubits=6, num_paulis=118) def test_freeze_core_all_reduction(self): @@ -124,7 +124,7 @@ def test_freeze_core_all_reduction(self): qubit_op, _ = fermionic_transformation.transform(self.driver) self._validate_vars(fermionic_transformation, energy_shift=-7.7962196) - self._validate_info(fermionic_transformation, num_particles=[1, 1], num_orbitals=6, + self._validate_info(fermionic_transformation, num_particles=(1, 1), num_orbitals=6, actual_two_qubit_reduction=True) self._validate_input_object(qubit_op, num_qubits=4, num_paulis=100) @@ -140,7 +140,7 @@ def test_freeze_core_all_reduction_ph(self): qubit_op, _ = fermionic_transformation.transform(self.driver) self._validate_vars(fermionic_transformation, energy_shift=-7.7962196, ph_energy_shift=-1.05785247) - self._validate_info(fermionic_transformation, num_particles=[1, 1], num_orbitals=6, + self._validate_info(fermionic_transformation, num_particles=(1, 1), num_orbitals=6, actual_two_qubit_reduction=True) self._validate_input_object(qubit_op, num_qubits=4, num_paulis=52) diff --git a/test/chemistry/test_initial_state_hartree_fock.py b/test/chemistry/test_initial_state_hartree_fock.py index 4186d3854b..df8e9dccaa 100644 --- a/test/chemistry/test_initial_state_hartree_fock.py +++ b/test/chemistry/test_initial_state_hartree_fock.py @@ -18,7 +18,6 @@ import numpy as np from ddt import ddt, idata, unpack -from qiskit import QuantumCircuit from qiskit.chemistry.components.initial_states import HartreeFock from qiskit.aqua.operators import StateFn from qiskit.chemistry import QiskitChemistryError @@ -126,45 +125,5 @@ def test_hf_value(self, mapping): self.assertAlmostEqual(fermionic_transformation._hf_energy, hf_energy, places=6) -@ddt -class TestHartreeFock(QiskitChemistryTestCase): - """ Initial State HartreeFock tests """ - - def test_qubits_4_jw_h2(self): - """ qubits 4 jw h2 test """ - state = HartreeFock(4, (1, 1), 'jordan_wigner', False) - ref = QuantumCircuit(4) - ref.x([0, 2]) - self.assertEqual(state, ref) - - def test_qubits_4_py_h2(self): - """ qubits 4 py h2 test """ - state = HartreeFock(4, (1, 1), 'parity', False) - ref = QuantumCircuit(4) - ref.x([0, 1]) - self.assertEqual(state, ref) - - def test_qubits_4_bk_h2(self): - """ qubits 4 bk h2 test """ - state = HartreeFock(4, (1, 1), 'bravyi_kitaev', False) - ref = QuantumCircuit(4) - ref.x([0, 1, 2]) - self.assertEqual(state, ref) - - def test_qubits_2_py_h2(self): - """ qubits 2 py h2 test """ - state = HartreeFock(4, 2, 'parity', True) - ref = QuantumCircuit(2) - ref.x(0) - self.assertEqual(state, ref) - - def test_qubits_6_py_lih(self): - """ qubits 6 py lih test """ - state = HartreeFock(10, (1, 1), 'parity', True, [1, 2]) - ref = QuantumCircuit(6) - ref.x([0, 1]) - self.assertEqual(state, ref) - - if __name__ == '__main__': unittest.main() diff --git a/test/chemistry/test_initial_state_vscf.py b/test/chemistry/test_initial_state_vscf.py index 0d579135d0..8e51ddaa58 100644 --- a/test/chemistry/test_initial_state_vscf.py +++ b/test/chemistry/test_initial_state_vscf.py @@ -10,13 +10,12 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -""" Test Initial State HartreeFock """ +""" Test Initial State VSCF """ import unittest import warnings from test.chemistry import QiskitChemistryTestCase import numpy as np -from qiskit import QuantumCircuit from qiskit.chemistry.components.initial_states import VSCF @@ -50,27 +49,5 @@ def test_qubits_5(self): 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) -class TestVSCF(QiskitChemistryTestCase): - """ Initial State vscf tests """ - - def test_qubits_4(self): - """ 2 modes 2 modals - test """ - basis = [2, 2] - vscf = VSCF(basis) - ref = QuantumCircuit(4) - ref.x([0, 2]) - - self.assertEqual(ref, vscf) - - def test_qubits_5(self): - """ 2 modes 2 modals for the first mode and 3 modals for the second - test """ - basis = [2, 3] - vscf = VSCF(basis) - ref = QuantumCircuit(5) - ref.x([0, 2]) - - self.assertEqual(ref, vscf) - - if __name__ == '__main__': unittest.main() diff --git a/test/chemistry/test_qeom_vqe.py b/test/chemistry/test_qeom_vqe.py index d17cfc147a..ae0777fdf8 100644 --- a/test/chemistry/test_qeom_vqe.py +++ b/test/chemistry/test_qeom_vqe.py @@ -29,7 +29,7 @@ from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry.core import Hamiltonian, TransformationType, QubitMappingType from qiskit.chemistry.components.variational_forms import UCCSD -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock class TestEomVQE(QiskitAquaTestCase): diff --git a/test/chemistry/test_readme_sample.py b/test/chemistry/test_readme_sample.py index 485aec03e0..6840b0fc49 100644 --- a/test/chemistry/test_readme_sample.py +++ b/test/chemistry/test_readme_sample.py @@ -79,12 +79,15 @@ def print(*args): optimizer = L_BFGS_B() # setup the initial state for the variational form - from qiskit.chemistry.components.initial_states import HartreeFock + from qiskit.chemistry.circuit.library import HartreeFock init_state = HartreeFock(num_spin_orbitals, num_particles) # setup the variational form for VQE from qiskit.circuit.library import TwoLocal - var_form = TwoLocal(num_qubits, ['ry', 'rz'], 'cz', initial_state=init_state) + var_form = TwoLocal(num_qubits, ['ry', 'rz'], 'cz') + + # add the initial state + var_form.compose(init_state, front=True) # setup and run VQE from qiskit.aqua.algorithms import VQE diff --git a/test/chemistry/test_swaprz.py b/test/chemistry/test_swaprz.py index 76febe3a42..199d35fe52 100644 --- a/test/chemistry/test_swaprz.py +++ b/test/chemistry/test_swaprz.py @@ -19,7 +19,7 @@ from qiskit.aqua import QuantumInstance, aqua_globals from qiskit.aqua.algorithms import VQE from qiskit.aqua.components.optimizers import SLSQP -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.core import QubitMappingType from qiskit.chemistry.drivers import HDF5Driver from qiskit.chemistry.algorithms.ground_state_solvers import GroundStateEigensolver @@ -57,7 +57,8 @@ def test_excitation_preserving(self): qubit_mapping=fermionic_transformation._qubit_mapping, two_qubit_reduction=fermionic_transformation._two_qubit_reduction) - wavefunction = ExcitationPreserving(qubit_op.num_qubits, initial_state=initial_state) + wavefunction = ExcitationPreserving(qubit_op.num_qubits) + wavefunction.compose(initial_state, front=True, inplace=True) solver = VQE(var_form=wavefunction, optimizer=optimizer, quantum_instance=QuantumInstance(BasicAer.get_backend('statevector_simulator'), diff --git a/test/chemistry/test_symmetries.py b/test/chemistry/test_symmetries.py index 930907aaf0..a4c2513349 100644 --- a/test/chemistry/test_symmetries.py +++ b/test/chemistry/test_symmetries.py @@ -22,7 +22,7 @@ from qiskit.chemistry import QiskitChemistryError from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry.components.variational_forms import UCCSD -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.algorithms.ground_state_solvers import GroundStateEigensolver from qiskit.chemistry.core import TransformationType, QubitMappingType from qiskit.chemistry.transformations import FermionicTransformation diff --git a/test/chemistry/test_uccsd_advanced.py b/test/chemistry/test_uccsd_advanced.py index e85699c9c9..ad03a0e29a 100644 --- a/test/chemistry/test_uccsd_advanced.py +++ b/test/chemistry/test_uccsd_advanced.py @@ -20,7 +20,7 @@ from qiskit.aqua.algorithms import VQE from qiskit.aqua.components.optimizers import SLSQP from qiskit.chemistry import QiskitChemistryError -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry.algorithms.ground_state_solvers import GroundStateEigensolver diff --git a/test/chemistry/test_uccsd_hartree_fock.py b/test/chemistry/test_uccsd_hartree_fock.py index 426658b55c..90fc260955 100644 --- a/test/chemistry/test_uccsd_hartree_fock.py +++ b/test/chemistry/test_uccsd_hartree_fock.py @@ -19,7 +19,8 @@ from qiskit.aqua.algorithms import VQE from qiskit.aqua.components.optimizers import SLSQP, SPSA from qiskit.aqua.operators import AerPauliExpectation, PauliExpectation -from qiskit.chemistry.components.initial_states import HartreeFock + +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.core import QubitMappingType from qiskit.chemistry.drivers import HDF5Driver @@ -48,7 +49,7 @@ def setUp(self): self.optimizer = SLSQP(maxiter=100) initial_state = HartreeFock( fermionic_transformation.molecule_info['num_orbitals'], - tuple(fermionic_transformation.molecule_info['num_particles']), + fermionic_transformation.molecule_info['num_particles'], qubit_mapping=fermionic_transformation._qubit_mapping, two_qubit_reduction=fermionic_transformation._two_qubit_reduction) self.var_form = UCCSD( diff --git a/test/chemistry/test_uvcc_vscf.py b/test/chemistry/test_uvcc_vscf.py index 8f75f31e3d..b723a428ef 100644 --- a/test/chemistry/test_uvcc_vscf.py +++ b/test/chemistry/test_uvcc_vscf.py @@ -12,6 +12,7 @@ """ Test of UVCC and VSCF Aqua extensions """ +import warnings from test.chemistry import QiskitChemistryTestCase from qiskit import BasicAer @@ -61,7 +62,9 @@ def test_uvcc_vscf(self): bosonic_op = BosonicOperator(co2_2modes_2modals_2body, basis) qubit_op = bosonic_op.mapping('direct', threshold=1e-5) - init_state = VSCF(basis) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=DeprecationWarning) + init_state = VSCF(basis) num_qubits = sum(basis) uvcc_varform = UVCC(num_qubits, basis, [0, 1], initial_state=init_state) diff --git a/test/chemistry/test_vqe_uccsd_adapt.py b/test/chemistry/test_vqe_uccsd_adapt.py index af2eee5387..2fa846ab9f 100644 --- a/test/chemistry/test_vqe_uccsd_adapt.py +++ b/test/chemistry/test_vqe_uccsd_adapt.py @@ -22,7 +22,7 @@ from qiskit.aqua.operators.legacy.weighted_pauli_operator import Z2Symmetries from qiskit.chemistry import FermionicOperator from qiskit.chemistry.algorithms import VQEAdapt -from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.circuit.library import HartreeFock from qiskit.chemistry.components.variational_forms import UCCSD from qiskit.chemistry.drivers import PySCFDriver, UnitsType from qiskit.chemistry import QiskitChemistryError From 3dd1eb7cc3bf6e9fc2494ab4e85afe3ad670f193 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Tue, 27 Oct 2020 16:44:56 +0100 Subject: [PATCH 20/22] fix mypy --- qiskit/chemistry/components/initial_states/hartree_fock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index 74579f0e00..d1ae8cb6ad 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -62,7 +62,7 @@ def __init__(self, # get the bitstring encoding the Hartree Fock state if isinstance(num_particles, list): - num_particles = tuple(num_particles) + num_particles = tuple(num_particles) # type: ignore bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction, sq_list) From aeb35de7731a40d6cbb0a9200bc5f4bc8048558d Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Wed, 28 Oct 2020 21:41:29 +0100 Subject: [PATCH 21/22] make _build_bitstr public functions --- .../library/initial_states/hartree_fock.py | 67 ++++++++++++------- .../circuit/library/initial_states/vscf.py | 13 +++- .../components/initial_states/hartree_fock.py | 6 +- .../components/initial_states/vscf.py | 4 +- qiskit/chemistry/core/hamiltonian.py | 10 +-- .../fermionic_transformation.py | 10 +-- .../circuit/library/test_hartree_fock.py | 22 ++++++ test/chemistry/circuit/library/test_vscf.py | 8 +++ 8 files changed, 97 insertions(+), 43 deletions(-) diff --git a/qiskit/chemistry/circuit/library/initial_states/hartree_fock.py b/qiskit/chemistry/circuit/library/initial_states/hartree_fock.py index c279a0f089..29c4796dd9 100644 --- a/qiskit/chemistry/circuit/library/initial_states/hartree_fock.py +++ b/qiskit/chemistry/circuit/library/initial_states/hartree_fock.py @@ -33,32 +33,17 @@ def __init__(self, sq_list: Optional[List[int]] = None) -> None: """ Args: - num_orbitals: number of spin orbitals, has a min. value of 1. - num_particles: number of particles, if it is a list, the first number - is alpha and the second number if beta. - qubit_mapping: mapping type for qubit operator - two_qubit_reduction: flag indicating whether or not two qubit is reduced - sq_list: position of the single-qubit operators that - anticommute with the cliffords - - Raises: - ValueError: wrong setting in num_particles and num_orbitals. - ValueError: wrong setting for computed num_qubits and supplied num_qubits. + num_orbitals: The number of spin orbitals, has a min. value of 1. + num_particles: The number of particles. If this is an integer, it is the total (even) + number of particles. If a tuple, the first number is alpha and the second number is + beta. + qubit_mapping: The mapping type for qubit operator. + two_qubit_reduction: A flag indicating whether or not two qubit is reduced. + sq_list: The position of the single-qubit operators that anticommute with the cliffords. """ - # validate the input - validate_min('num_orbitals', num_orbitals, 1) - validate_in_set('qubit_mapping', qubit_mapping, - {'jordan_wigner', 'parity', 'bravyi_kitaev'}) - - if qubit_mapping != 'parity' and two_qubit_reduction: - warnings.warn('two_qubit_reduction only works with parity qubit mapping ' - 'but you have %s. We switch two_qubit_reduction ' - 'to False.' % qubit_mapping) - two_qubit_reduction = False - # get the bitstring encoding the Hartree Fock state - bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, - two_qubit_reduction, sq_list) + bitstr = hartree_fock_bitstring(num_orbitals, num_particles, qubit_mapping, + two_qubit_reduction, sq_list) # construct the circuit qr = QuantumRegister(len(bitstr), 'q') @@ -70,8 +55,38 @@ def __init__(self, self.x(i) -def _build_bitstr(num_orbitals, num_particles, qubit_mapping, two_qubit_reduction=True, - sq_list=None): +def hartree_fock_bitstring(num_orbitals: int, + num_particles: Union[Tuple[int, int], int], + qubit_mapping: str = 'parity', + two_qubit_reduction: bool = True, + sq_list: Optional[List[int]] = None) -> np.ndarray: + """Compute the bitstring representing the Hartree-Fock state for the specified system. + + Args: + num_orbitals: The number of spin orbitals, has a min. value of 1. + num_particles: The number of particles. If this is an integer, it is the total (even) number + of particles. If a tuple, the first number is alpha and the second number is beta. + qubit_mapping: The mapping type for qubit operator. + two_qubit_reduction: A flag indicating whether or not two qubit is reduced. + sq_list: The position of the single-qubit operators that anticommute with the cliffords. + + Returns: + The bitstring representing the state of the Hartee-Fock state as array of bools. + + Raises: + ValueError: If the total number of particles is larger than the number of orbitals. + """ + # validate the input + validate_min('num_orbitals', num_orbitals, 1) + validate_in_set('qubit_mapping', qubit_mapping, + {'jordan_wigner', 'parity', 'bravyi_kitaev'}) + + if qubit_mapping != 'parity' and two_qubit_reduction: + warnings.warn('two_qubit_reduction only works with parity qubit mapping ' + 'but you have %s. We switch two_qubit_reduction ' + 'to False.' % qubit_mapping) + two_qubit_reduction = False + if isinstance(num_particles, tuple): num_alpha, num_beta = num_particles else: diff --git a/qiskit/chemistry/circuit/library/initial_states/vscf.py b/qiskit/chemistry/circuit/library/initial_states/vscf.py index 8a877e6edc..5bf3a07fb1 100644 --- a/qiskit/chemistry/circuit/library/initial_states/vscf.py +++ b/qiskit/chemistry/circuit/library/initial_states/vscf.py @@ -37,7 +37,7 @@ def __init__(self, basis: List[int]) -> None: with 4 modals per mode basis = [4,4,4] """ # get the bitstring encoding initial state - bitstr = _build_bitstr(basis) + bitstr = vscf_bitstring(basis) # construct the circuit qr = QuantumRegister(len(bitstr), 'q') @@ -49,7 +49,16 @@ def __init__(self, basis: List[int]) -> None: self.x(i) -def _build_bitstr(basis): +def vscf_bitstring(basis: List[int]) -> np.ndarray: + """Compute the bitstring representing the VSCF initial state based on the modals per mode. + + Args: + basis: Is a list defining the number of modals per mode. E.g. for a 3 modes system + with 4 modals per mode basis = [4,4,4]. + + Returns: + The bitstring representing the state of the VSCF state as array of bools. + """ num_qubits = sum(basis) bitstr = np.zeros(num_qubits, np.bool) count = 0 diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index d1ae8cb6ad..3d143072c7 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -19,7 +19,7 @@ from qiskit import QuantumRegister, QuantumCircuit from qiskit.aqua.utils.validation import validate_min, validate_in_set from qiskit.aqua.components.initial_states import InitialState -from qiskit.chemistry.circuit.library.initial_states.hartree_fock import _build_bitstr +from qiskit.chemistry.circuit.library.initial_states.hartree_fock import hartree_fock_bitstringtr logger = logging.getLogger(__name__) @@ -64,8 +64,8 @@ def __init__(self, if isinstance(num_particles, list): num_particles = tuple(num_particles) # type: ignore - bitstr = _build_bitstr(num_orbitals, num_particles, qubit_mapping, - two_qubit_reduction, sq_list) + bitstr = hartree_fock_bitstringtr(num_orbitals, num_particles, qubit_mapping, + two_qubit_reduction, sq_list) self._bitstr = bitstr def construct_circuit(self, mode='circuit', register=None): diff --git a/qiskit/chemistry/components/initial_states/vscf.py b/qiskit/chemistry/components/initial_states/vscf.py index 8a0b73b5ad..b8d87a3767 100644 --- a/qiskit/chemistry/components/initial_states/vscf.py +++ b/qiskit/chemistry/components/initial_states/vscf.py @@ -20,7 +20,7 @@ from qiskit import QuantumRegister, QuantumCircuit from qiskit.aqua.components.initial_states import InitialState -from qiskit.chemistry.circuit.library.initial_states.vscf import _build_bitstr +from qiskit.chemistry.circuit.library.initial_states.vscf import vscf_bitstring logger = logging.getLogger(__name__) @@ -40,7 +40,7 @@ def __init__(self, basis: List[int]) -> None: with 4 modals per mode basis = [4,4,4] """ # get the bitstring encoding initial state - bitstr = _build_bitstr(basis) + bitstr = vscf_bitstring(basis) self._bitstr = bitstr super().__init__() diff --git a/qiskit/chemistry/core/hamiltonian.py b/qiskit/chemistry/core/hamiltonian.py index 9fe48891cd..bec494f2f2 100644 --- a/qiskit/chemistry/core/hamiltonian.py +++ b/qiskit/chemistry/core/hamiltonian.py @@ -305,11 +305,11 @@ def _process_z2symmetry_reduction(self, qubit_op, aux_ops): aux_ops[i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': - from ..circuit.library.initial_states.hartree_fock import _build_bitstr - hf_bitstr = _build_bitstr(num_orbitals=self._molecule_info['num_orbitals'], - qubit_mapping=self._qubit_mapping, - two_qubit_reduction=self._two_qubit_reduction, - num_particles=self._molecule_info['num_particles']) + from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstringtr + hf_bitstr = hartree_fock_bitstringtr(num_orbitals=self._molecule_info['num_orbitals'], + qubit_mapping=self._qubit_mapping, + two_qubit_reduction=self._two_qubit_reduction, + num_particles=self._molecule_info['num_particles']) z2_symmetries = Hamiltonian._pick_sector(z2_symmetries, hf_bitstr) else: if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries): diff --git a/qiskit/chemistry/transformations/fermionic_transformation.py b/qiskit/chemistry/transformations/fermionic_transformation.py index e16c04bc59..3760b41c0f 100644 --- a/qiskit/chemistry/transformations/fermionic_transformation.py +++ b/qiskit/chemistry/transformations/fermionic_transformation.py @@ -424,11 +424,11 @@ def _process_z2symmetry_reduction(self, aux_ops[i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': - from ..circuit.library.initial_states.hartree_fock import _build_bitstr - hf_bitstr = _build_bitstr(num_orbitals=self._molecule_info['num_orbitals'], - qubit_mapping=self._qubit_mapping, - two_qubit_reduction=self._two_qubit_reduction, - num_particles=self._molecule_info['num_particles']) + from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstringtr + hf_bitstr = hartree_fock_bitstringtr(num_orbitals=self._molecule_info['num_orbitals'], + qubit_mapping=self._qubit_mapping, + two_qubit_reduction=self._two_qubit_reduction, + num_particles=self._molecule_info['num_particles']) z2_symmetries = FermionicTransformation._pick_sector(z2_symmetries, hf_bitstr) else: if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries): diff --git a/test/chemistry/circuit/library/test_hartree_fock.py b/test/chemistry/circuit/library/test_hartree_fock.py index c91aa3dc86..7fc4ba7fa9 100644 --- a/test/chemistry/circuit/library/test_hartree_fock.py +++ b/test/chemistry/circuit/library/test_hartree_fock.py @@ -14,14 +14,36 @@ import unittest from test.chemistry import QiskitChemistryTestCase +import numpy as np from qiskit import QuantumCircuit from qiskit.chemistry.circuit.library import HartreeFock +from qiskit.chemistry.circuit.library.initial_states.hartree_fock import hartree_fock_bitstring class TestHartreeFock(QiskitChemistryTestCase): """ Initial State HartreeFock tests """ + def test_bitstring(self): + """Simple test for the bitstring function.""" + bitstr = hartree_fock_bitstring(4, 2, 'parity', True) + self.assertTrue(all(bitstr[::-1] == np.array([True, False]))) # big endian notation + + def test_bitstring_invalid_input(self): + """Test passing invalid input raises.""" + + with self.subTest('too many particles'): + with self.assertRaises(ValueError): + _ = hartree_fock_bitstring(4, 4, 'jordan-wigner') + + with self.subTest('too few orbitals'): + with self.assertRaises(ValueError): + _ = hartree_fock_bitstring(-1, 4, 'parity', True) + + with self.subTest('invalid qubit mapping'): + with self.assertRaises(ValueError): + _ = hartree_fock_bitstring(4, 2, 'parit', True) + def test_qubits_4_jw_h2(self): """ qubits 4 jw h2 test """ state = HartreeFock(4, (1, 1), 'jordan_wigner', False) diff --git a/test/chemistry/circuit/library/test_vscf.py b/test/chemistry/circuit/library/test_vscf.py index dbc4e38a30..1a1104815e 100644 --- a/test/chemistry/circuit/library/test_vscf.py +++ b/test/chemistry/circuit/library/test_vscf.py @@ -14,13 +14,21 @@ import unittest from test.chemistry import QiskitChemistryTestCase +import numpy as np + from qiskit import QuantumCircuit from qiskit.chemistry.circuit.library import VSCF +from qiskit.chemistry.circuit.library.initial_states.vscf import vscf_bitstring class TestVSCF(QiskitChemistryTestCase): """ Initial State vscf tests """ + def test_bitstring(self): + """Test the vscf_bitstring method.""" + bitstr = vscf_bitstring([2, 2]) + self.assertTrue(all(bitstr[::-1] == np.array([True, False, True, False]))) # big endian + def test_qubits_4(self): """Test 2 modes 2 modals.""" basis = [2, 2] From 174c88ea7405851a91d23b63799571af69d9ad33 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Thu, 29 Oct 2020 10:45:36 +0100 Subject: [PATCH 22/22] fix misspelling --- .../components/initial_states/hartree_fock.py | 6 +++--- qiskit/chemistry/core/hamiltonian.py | 12 +++++++----- .../transformations/fermionic_transformation.py | 12 +++++++----- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/qiskit/chemistry/components/initial_states/hartree_fock.py b/qiskit/chemistry/components/initial_states/hartree_fock.py index 3d143072c7..bbb4befc35 100644 --- a/qiskit/chemistry/components/initial_states/hartree_fock.py +++ b/qiskit/chemistry/components/initial_states/hartree_fock.py @@ -19,7 +19,7 @@ from qiskit import QuantumRegister, QuantumCircuit from qiskit.aqua.utils.validation import validate_min, validate_in_set from qiskit.aqua.components.initial_states import InitialState -from qiskit.chemistry.circuit.library.initial_states.hartree_fock import hartree_fock_bitstringtr +from qiskit.chemistry.circuit.library.initial_states.hartree_fock import hartree_fock_bitstring logger = logging.getLogger(__name__) @@ -64,8 +64,8 @@ def __init__(self, if isinstance(num_particles, list): num_particles = tuple(num_particles) # type: ignore - bitstr = hartree_fock_bitstringtr(num_orbitals, num_particles, qubit_mapping, - two_qubit_reduction, sq_list) + bitstr = hartree_fock_bitstring(num_orbitals, num_particles, qubit_mapping, + two_qubit_reduction, sq_list) self._bitstr = bitstr def construct_circuit(self, mode='circuit', register=None): diff --git a/qiskit/chemistry/core/hamiltonian.py b/qiskit/chemistry/core/hamiltonian.py index bec494f2f2..6235128f33 100644 --- a/qiskit/chemistry/core/hamiltonian.py +++ b/qiskit/chemistry/core/hamiltonian.py @@ -305,11 +305,13 @@ def _process_z2symmetry_reduction(self, qubit_op, aux_ops): aux_ops[i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': - from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstringtr - hf_bitstr = hartree_fock_bitstringtr(num_orbitals=self._molecule_info['num_orbitals'], - qubit_mapping=self._qubit_mapping, - two_qubit_reduction=self._two_qubit_reduction, - num_particles=self._molecule_info['num_particles']) + from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstring + hf_bitstr = hartree_fock_bitstring( + num_orbitals=self._molecule_info['num_orbitals'], + qubit_mapping=self._qubit_mapping, + two_qubit_reduction=self._two_qubit_reduction, + num_particles=self._molecule_info['num_particles'] + ) z2_symmetries = Hamiltonian._pick_sector(z2_symmetries, hf_bitstr) else: if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries): diff --git a/qiskit/chemistry/transformations/fermionic_transformation.py b/qiskit/chemistry/transformations/fermionic_transformation.py index 3760b41c0f..3edb68d306 100644 --- a/qiskit/chemistry/transformations/fermionic_transformation.py +++ b/qiskit/chemistry/transformations/fermionic_transformation.py @@ -424,11 +424,13 @@ def _process_z2symmetry_reduction(self, aux_ops[i] = None # Discard since no meaningful measurement can be done if self._z2symmetry_reduction == 'auto': - from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstringtr - hf_bitstr = hartree_fock_bitstringtr(num_orbitals=self._molecule_info['num_orbitals'], - qubit_mapping=self._qubit_mapping, - two_qubit_reduction=self._two_qubit_reduction, - num_particles=self._molecule_info['num_particles']) + from ..circuit.library.initial_states.hartree_fock import hartree_fock_bitstring + hf_bitstr = hartree_fock_bitstring( + num_orbitals=self._molecule_info['num_orbitals'], + qubit_mapping=self._qubit_mapping, + two_qubit_reduction=self._two_qubit_reduction, + num_particles=self._molecule_info['num_particles'] + ) z2_symmetries = FermionicTransformation._pick_sector(z2_symmetries, hf_bitstr) else: if len(self._z2symmetry_reduction) != len(z2_symmetries.symmetries):