Exemplo n.º 1
0
class TestUVCC(QiskitNatureTestCase):
    """Tests for the UVCC Ansatz."""

    @unpack
    @data(
        ("s", [2], [VibrationalOp([("+-", 1j), ("-+", -1j)], 1, 2)]),
        (
            "s",
            [2, 2],
            [
                VibrationalOp([("+-II", 1j), ("-+II", -1j)], 2, 2),
                VibrationalOp([("II+-", 1j), ("II-+", -1j)], 2, 2),
            ],
        ),
    )
    def test_ucc_ansatz(self, excitations, num_modals, expect):
        """Tests the UVCC Ansatz."""
        converter = QubitConverter(DirectMapper())

        ansatz = UVCC(qubit_converter=converter, num_modals=num_modals, excitations=excitations)

        assert_ucc_like_ansatz(self, ansatz, num_modals, expect)

    def test_transpile_no_parameters(self):
        """Test transpilation without parameters"""

        qubit_converter = QubitConverter(mapper=DirectMapper())

        ansatz = UVCC(qubit_converter=qubit_converter, num_modals=[2], excitations="s")
        ansatz = transpile(ansatz, optimization_level=3)
        self.assertEqual(ansatz.num_qubits, 2)
Exemplo n.º 2
0
    def _build_vibration_excitation_ops(
            self, excitations: Sequence) -> List[VibrationalOp]:
        """Builds all possible excitation operators with the given number of excitations for the
        specified number of particles distributed in the number of orbitals.

        Args:
            excitations: the list of excitations.

        Returns:
            The list of excitation operators in the second quantized formalism.
        """
        operators = []

        sum_modes = sum(self.num_modals)

        for exc in excitations:
            label = ["I"] * sum_modes
            for occ in exc[0]:
                label[occ] = "+"
            for unocc in exc[1]:
                label[unocc] = "-"
            op = VibrationalOp("".join(label), len(self.num_modals),
                               self.num_modals)
            op -= op.adjoint()
            # we need to account for an additional imaginary phase in the exponent (see also
            # `PauliTrotterEvolution.convert`)
            op *= 1j  # type: ignore
            operators.append(op)

        return operators
Exemplo n.º 3
0
 def test_simplify(self):
     """Test simplify"""
     test_op = (
         1j * VibrationalOp("+-", 2, 1)
         + 1j * VibrationalOp("+-", 2, 1)
         - 1j * VibrationalOp("-+", 2, 1)
         - 1j * VibrationalOp("-+", 2, 1)
     )
     expected = [("+-", 2j), ("-+", -2j)]
     self.assertEqual(test_op.simplify().to_list(), expected)
Exemplo n.º 4
0
 def test_reduce(self):
     """Test reduce"""
     test_op = (
         1j * VibrationalOp("+-", 2, 1)
         + 1j * VibrationalOp("+-", 2, 1)
         - 1j * VibrationalOp("-+", 2, 1)
         - 1j * VibrationalOp("-+", 2, 1)
     )
     expected = [("+-", 2j), ("-+", -2j)]
     with self.assertWarns(DeprecationWarning):
         self.assertEqual(test_op.reduce().to_list(), expected)
Exemplo n.º 5
0
    def test_chc_vscf(self):
        """ chc vscf test """

        co2_2modes_2modals_2body = [
            [[[[0, 0, 0]], 320.8467332810141], [[[0, 1, 1]],
                                                1760.878530705873],
             [[[1, 0, 0]], 342.8218290247543], [[[1, 1, 1]],
                                                1032.396323618631]],
            [[[[0, 0, 0], [1, 0, 0]], -57.34003649795117],
             [[[0, 0, 1], [1, 0, 0]], -56.33205925807966],
             [[[0, 1, 0], [1, 0, 0]], -56.33205925807966],
             [[[0, 1, 1], [1, 0, 0]], -60.13032761856809],
             [[[0, 0, 0], [1, 0, 1]], -65.09576309934431],
             [[[0, 0, 1], [1, 0, 1]], -62.2363839133389],
             [[[0, 1, 0], [1, 0, 1]], -62.2363839133389],
             [[[0, 1, 1], [1, 0, 1]], -121.5533969109279],
             [[[0, 0, 0], [1, 1, 0]], -65.09576309934431],
             [[[0, 0, 1], [1, 1, 0]], -62.2363839133389],
             [[[0, 1, 0], [1, 1, 0]], -62.2363839133389],
             [[[0, 1, 1], [1, 1, 0]], -121.5533969109279],
             [[[0, 0, 0], [1, 1, 1]], -170.744837386338],
             [[[0, 0, 1], [1, 1, 1]], -167.7433236025723],
             [[[0, 1, 0], [1, 1, 1]], -167.7433236025723],
             [[[0, 1, 1], [1, 1, 1]], -179.0536532281924]]
        ]
        num_modes = 2
        num_modals = [2, 2]

        vibrational_op_labels = _create_labels(co2_2modes_2modals_2body)
        vibr_op = VibrationalOp(vibrational_op_labels, num_modes, num_modals)

        converter = QubitConverter(DirectMapper())

        qubit_op = converter.convert_match(vibr_op)

        init_state = VSCF(num_modals)

        num_qubits = sum(num_modals)
        excitations = []
        excitations += generate_vibration_excitations(num_excitations=1,
                                                      num_modals=num_modals)
        excitations += generate_vibration_excitations(num_excitations=2,
                                                      num_modals=num_modals)
        chc_ansatz = CHC(num_qubits,
                         ladder=False,
                         excitations=excitations,
                         initial_state=init_state)

        backend = QuantumInstance(
            BasicAer.get_backend('statevector_simulator'),
            seed_transpiler=2,
            seed_simulator=2)
        optimizer = COBYLA(maxiter=1000)

        algo = VQE(chc_ansatz, optimizer=optimizer, quantum_instance=backend)
        vqe_result = algo.compute_minimum_eigenvalue(qubit_op)
        energy = vqe_result.optimal_value

        self.assertAlmostEqual(energy, self.reference_energy, places=4)
Exemplo n.º 6
0
class TestUVCC(QiskitNatureTestCase):
    """Tests for the UVCC Ansatz."""
    @unpack
    @data(
        ('s', [2], [VibrationalOp([('+-', 1j), ('-+', -1j)], 1, 2)]),
        ('s', [2, 2], [
            VibrationalOp([('+-II', 1j), ('-+II', -1j)], 2, 2),
            VibrationalOp([('II+-', 1j), ('II-+', -1j)], 2, 2)
        ]),
    )
    def test_ucc_ansatz(self, excitations, num_modals, expect):
        """Tests the UVCC Ansatz."""
        converter = QubitConverter(DirectMapper())

        ansatz = UVCC(qubit_converter=converter,
                      num_modals=num_modals,
                      excitations=excitations)

        assert_ucc_like_ansatz(self, ansatz, num_modals, expect)
Exemplo n.º 7
0
    def test_init_pm_label(self):
        """Test __init__ with plus and minus label"""
        with self.subTest("minus plus"):
            result = VibrationalOp([("+_0*0 -_0*1", 2)], 1, 2)
            desired = [("+-", (2 + 0j))]
            self.assertEqual(result.to_list(), desired)

        with self.subTest("plus minus"):
            result = VibrationalOp([("-_0*0 +_0*1", 2)], 1, 2)
            desired = [("-+", (2 + 0j))]
            self.assertEqual(result.to_list(), desired)

        with self.subTest("plus minus minus plus"):
            result = VibrationalOp([("+_0*0 -_0*1 -_1*0 +_1*1", 3)], 2, 2)
            desired = [("+--+", (3 + 0j))]

            # Note: the order of list is irrelevant.
            self.assertSetEqual(frozenset(result.to_list()), frozenset(desired))
Exemplo n.º 8
0
def _build_single_hopping_operator(
        excitation: Tuple[Tuple[int, ...], Tuple[int, ...]],
        num_modals: List[int], qubit_converter: QubitConverter) -> PauliSumOp:
    sum_modes = sum(num_modals)

    label = ['I'] * sum_modes
    for occ in excitation[0]:
        label[occ] = '+'
    for unocc in excitation[1]:
        label[unocc] = '-'
    vibrational_op = VibrationalOp(''.join(label), len(num_modals), num_modals)
    qubit_op: PauliSumOp = qubit_converter.convert_match(vibrational_op)

    return qubit_op
Exemplo n.º 9
0
 def setUp(self):
     super().setUp()
     self.labels = [("+_1*0 -_1*1", 1215.375),
                    ("+_2*0 -_2*1 +_3*0 -_3*0", -6.385)]
     self.labels_double = [
         ("+_1*0 -_1*1", 2 * 1215.375),
         ("+_2*0 -_2*1 +_3*0 -_3*0", -2 * 6.385),
     ]
     self.labels_divided_3 = [
         ("+_1*0 -_1*1", 1215.375 / 3),
         ("+_2*0 -_2*1 +_3*0 -_3*0", -6.385 / 3),
     ]
     self.labels_neg = [("+_1*0 -_1*1", -1215.375),
                        ("+_2*0 -_2*1 +_3*0 -_3*0", 6.385)]
     self.vibr_spin_op = VibrationalOp(self.labels, 4, 2)
    def to_second_q_op(self) -> VibrationalOp:
        """Creates the operator representing the Hamiltonian defined by these vibrational integrals.

        Returns:
            The :class:`~qiskit_nature.operators.second_quantization.VibrationalOp` given by these
            vibrational integrals.

        Raises:
            QiskitNatureError: if no basis has been set yet.
        """
        try:
            matrix = self.to_basis()
        except QiskitNatureError as exc:
            raise QiskitNatureError() from exc

        num_modals_per_mode = self.basis._num_modals_per_mode
        num_modes = len(num_modals_per_mode)

        nonzero = np.nonzero(matrix)

        if not np.any(np.asarray(nonzero)):
            return VibrationalOp.zero(num_modes, num_modals_per_mode)

        labels = []

        for coeff, indices in zip(matrix[nonzero], zip(*nonzero)):
            # the indices need to be grouped into triplets of the form: (mode, modal_1, modal_2)
            grouped_indices = [
                tuple(int(j) for j in indices[i:i + 3])
                for i in range(0, len(indices), 3)
            ]
            # the index groups need to processed in sorted order to produce a valid label
            coeff_label = self._create_label_for_coeff(sorted(grouped_indices))
            labels.append((coeff_label, coeff))

        return VibrationalOp(labels, num_modes, num_modals_per_mode)
Exemplo n.º 11
0
    def _get_mode_op(self, mode: int) -> VibrationalOp:
        """Constructs an operator to evaluate which modal of a given mode is occupied.

        Args:
            mode: the mode index.

        Returns:
            The operator to evaluate which modal of the given mode is occupied.
        """
        num_modals_per_mode = self.basis._num_modals_per_mode

        labels: list[tuple[str, complex]] = []

        for modal in range(num_modals_per_mode[mode]):
            labels.append((f"+_{mode}*{modal} -_{mode}*{modal}", 1.0))

        return VibrationalOp(labels, len(num_modals_per_mode), num_modals_per_mode)
Exemplo n.º 12
0
def build_vibrational_op_from_ints(h_mat: List[List[Tuple[List[List[int]], complex]]],
                                   num_modes: int,
                                   num_modals: List[int],
                                   ) -> VibrationalOp:
    """
    Builds a :class:`VibrationalOp` based on an integral list as produced by
    :meth:`HarmonicBasis.convert()`.

    Args:
        h_mat: integral list.
        num_modes: the number of modes.
        num_modals: the number of modals.

    Returns:
        The constructed VibrationalOp.
    """
    all_labels = _create_labels(h_mat)

    return VibrationalOp(all_labels, num_modes, num_modals)
Exemplo n.º 13
0
    def __init__(
        self,
        num_modals: list[int],
        qubit_converter: QubitConverter | None = None,
    ) -> None:
        """
        Args:
            num_modals: Is a list defining the number of modals per mode. E.g. for a 3 modes system
                with 4 modals per mode num_modals = [4,4,4]
            qubit_converter: a QubitConverter instance. This argument is currently being ignored
                             because only a single use-case is supported at the time of release:
                             that of the :class:`DirectMapper`. However, for future-compatibility of
                             this functions signature, the argument has already been inserted.
        """
        # get the bitstring encoding initial state
        bitstr = vscf_bitstring(num_modals)

        # encode the bitstring in a `VibrationalOp`
        label = ["+" if bit else "I" for bit in bitstr]
        bitstr_op = VibrationalOp("".join(label),
                                  num_modes=len(num_modals),
                                  num_modals=num_modals)

        # map the `VibrationalOp` to a qubit operator
        if qubit_converter is not None:
            logger.warning(
                "The only supported `QubitConverter` is one with a `DirectMapper` as the mapper "
                "instance. However you specified %s as an input, which will be ignored until more "
                "variants will be supported.",
                str(qubit_converter),
            )
        qubit_converter = QubitConverter(DirectMapper())
        qubit_op: PauliSumOp = qubit_converter.convert_match(bitstr_op)

        # construct the circuit
        qr = QuantumRegister(qubit_op.num_qubits, "q")
        super().__init__(qr, name="VSCF")

        # add gates in the right positions
        for i, bit in enumerate(qubit_op.primitive.paulis.x[0]):
            if bit:
                self.x(i)
Exemplo n.º 14
0
    def test_hermiticity(self):
        """test is_hermitian"""
        with self.subTest("operator hermitian"):
            # deliberately define test operator with duplicate terms in case .adjoint() simplifies terms
            test_op = (
                1j * VibrationalOp("+-", 2, 1)
                + 1j * VibrationalOp("+-", 2, 1)
                - 1j * VibrationalOp("-+", 2, 1)
                - 1j * VibrationalOp("-+", 2, 1)
            )
            self.assertTrue(test_op.is_hermitian())

        with self.subTest("operator not hermitian"):
            test_op = (
                1j * VibrationalOp("+-", 2, 1)
                + 1j * VibrationalOp("+-", 2, 1)
                - 1j * VibrationalOp("-+", 2, 1)
            )
            self.assertFalse(test_op.is_hermitian())
Exemplo n.º 15
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.
"""Some expected VibrationalOps."""

from qiskit_nature.operators.second_quantization import VibrationalOp

_truncation_order_1_op = VibrationalOp(
    [
        ("NIIIIIII", 1268.0676746875001),
        ("INIIIIII", 3813.8767834375008),
        ("IINIIIII", 705.8633818750001),
        ("II+-IIII", -46.025705898886045),
        ("II-+IIII", -46.025705898886045),
        ("IIINIIII", 2120.1145593750007),
        ("IIIINIII", 238.31540750000005),
        ("IIIIINII", 728.9613775000003),
        ("IIIIIINI", 238.31540750000005),
        ("IIIIIIIN", 728.9613775000003),
    ],
    num_modes=4,
    num_modals=2,
)

_truncation_order_2_op = VibrationalOp(
    [
        ("NIIIIIII", 1268.0676746875001),
        ("INIIIIII", 3813.8767834375008),
        ("IINIIIII", 705.8633818750001),
        ("II+-IIII", -46.025705898886045),
        ("II-+IIII", -46.025705898886045),
Exemplo n.º 16
0
 def test_add(self):
     """Test __add__"""
     actual = (self.vibr_spin_op + self.vibr_spin_op).reduce()
     desired = VibrationalOp(self.labels_double, 4, 2)
     self.assertSpinEqual(actual, desired)
Exemplo n.º 17
0
 def test_div(self):
     """Test __truediv__"""
     actual = self.vibr_spin_op / 3
     desired = VibrationalOp(self.labels_divided_3, 4, 2)
     self.assertSpinEqual(actual, desired)
Exemplo n.º 18
0
 def test_mul(self):
     """Test __mul__, and __rmul__"""
     actual = self.vibr_spin_op * 2
     desired = VibrationalOp(self.labels_double, 4, 2)
     self.assertSpinEqual(actual, desired)
Exemplo n.º 19
0
 def test_neg(self):
     """Test __neg__"""
     actual = -self.vibr_spin_op
     desired = VibrationalOp(self.labels_neg, 4, 2)
     self.assertSpinEqual(actual, desired)
Exemplo n.º 20
0
 def test_init_invalid_label(self, label):
     """Test __init__ for invalid label"""
     with self.assertRaises(ValueError):
         VibrationalOp(label, 1, 1)