diff --git a/qchem/CHANGELOG.md b/qchem/CHANGELOG.md index 22026d52959..3733b221fc0 100644 --- a/qchem/CHANGELOG.md +++ b/qchem/CHANGELOG.md @@ -6,12 +6,19 @@

Bug fixes

+* An error message is raised if a QubitOperator with complex coefficients is passed + to the ``convert_observable`` function. At present, the ``vqe.Hamiltonian`` class does not + support complex coefficients. + [(#1277)](https://github.com/PennyLaneAI/pennylane/pull/1277) +

Breaking changes

Contributors

This release contains contributions from (in alphabetical order): +Alain Delgado Gran + # Release 0.15.1

Bug fixes

diff --git a/qchem/pennylane_qchem/qchem/structure.py b/qchem/pennylane_qchem/qchem/structure.py index 6de2e8d3a95..98a68b5600f 100644 --- a/qchem/pennylane_qchem/qchem/structure.py +++ b/qchem/pennylane_qchem/qchem/structure.py @@ -98,7 +98,7 @@ def _process_wires(wires, n_wires=None): elif isinstance(wires, dict): - if all([isinstance(w, int) for w in wires.keys()]): + if all(isinstance(w, int) for w in wires.keys()): # Assuming keys are taken from consecutive int wires. Allows for partial mapping. n_wires = max(wires) + 1 labels = list(range(n_wires)) # used for completing potential partial mapping. @@ -616,7 +616,9 @@ def _terms_to_qubit_operator(coeffs, ops, wires=None): all_wires = Wires.all_wires([op.wires for op in ops], sort=True) if wires is not None: - qubit_indexed_wires = _process_wires(wires,) + qubit_indexed_wires = _process_wires( + wires, + ) if not set(all_wires).issubset(set(qubit_indexed_wires)): raise ValueError("Supplied `wires` does not cover all wires defined in `ops`.") else: @@ -705,6 +707,12 @@ def convert_observable(qubit_observable, wires=None): 0.16768319 0.12293305 0.17627641] """ + if any(np.iscomplex(np.array(coef)) for coef in qubit_observable.terms.values()): + raise TypeError( + "The coefficients entering the QubitOperator must be real;" + " got complex coefficients in the operator {}".format(qubit_observable) + ) + return Hamiltonian(*_qubit_operator_to_terms(qubit_observable, wires=wires)) diff --git a/qchem/tests/test_convert_observable.py b/qchem/tests/test_convert_observable.py index f51194022bd..f3d1d5f2c1f 100644 --- a/qchem/tests/test_convert_observable.py +++ b/qchem/tests/test_convert_observable.py @@ -322,6 +322,20 @@ def test_not_xyz_terms_to_qubit_operator(): ) +def test_exception_convert_observable(): + r"""Test that an error is raised if the QubitOperator contains complex coefficients. + Currently the vqe.Hamiltonian class does not support complex coefficients. + """ + qubit_op = ( + QubitOperator("Y0 Y1", 1 + 0j) + + QubitOperator("Z0 X1", 4.5 + 1.5j) + + QubitOperator("Y0 X1", 2) + ) + + with pytest.raises(TypeError, match="The coefficients entering the QubitOperator must be real"): + qchem.convert_observable(qubit_op) + + def test_identities_terms_to_qubit_operator(): """Test that tensor products that contain Identity instances are handled correctly by the _terms_to_qubit_operator function. @@ -333,14 +347,16 @@ def test_identities_terms_to_qubit_operator(): [0 0 0 4]] """ coeffs = [2.5, -0.5, -1.0] - obs_list = [qml.Identity(wires=[0]) @ qml.Identity(wires=[1]), - qml.Identity(wires=[0]) @ qml.PauliZ(wires=[1]), - qml.PauliZ(wires=[0]) @ qml.Identity(wires=[1])] + obs_list = [ + qml.Identity(wires=[0]) @ qml.Identity(wires=[1]), + qml.Identity(wires=[0]) @ qml.PauliZ(wires=[1]), + qml.PauliZ(wires=[0]) @ qml.Identity(wires=[1]), + ] op_str = str(qchem._terms_to_qubit_operator(coeffs, obs_list)) # Remove new line characters - op_str = op_str.replace('\n','') + op_str = op_str.replace("\n", "") assert op_str == "2.5 [] +-1.0 [Z0] +-0.5 [Z1]" @@ -348,14 +364,16 @@ def test_terms_to_qubit_operator_no_decomp(): """Test the _terms_to_qubit_operator function with custom wires.""" coeffs = np.array([0.1, 0.2]) ops = [ - qml.operation.Tensor(qml.PauliX(wires=['w0'])), - qml.operation.Tensor(qml.PauliY(wires=['w0']), qml.PauliZ(wires=['w2'])) + qml.operation.Tensor(qml.PauliX(wires=["w0"])), + qml.operation.Tensor(qml.PauliY(wires=["w0"]), qml.PauliZ(wires=["w2"])), ] - op_str = str(qchem._terms_to_qubit_operator(coeffs, ops, wires=qml.wires.Wires(['w0', 'w1', 'w2']))) + op_str = str( + qchem._terms_to_qubit_operator(coeffs, ops, wires=qml.wires.Wires(["w0", "w1", "w2"])) + ) # Remove new line characters - op_str = op_str.replace('\n','') - expected = '0.1 [X0] +0.2 [Y0 Z2]' + op_str = op_str.replace("\n", "") + expected = "0.1 [X0] +0.2 [Y0 Z2]" assert op_str == expected @@ -438,7 +456,12 @@ def test_integration_mol_file_to_vqe_cost( ref_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_ref_files") hf_file = os.path.join(ref_dir, name) - qubit_hamiltonian = qchem.decompose(hf_file, mapping=mapping, core=core, active=active,) + qubit_hamiltonian = qchem.decompose( + hf_file, + mapping=mapping, + core=core, + active=active, + ) vqe_hamiltonian = qchem.convert_observable(qubit_hamiltonian, custom_wires) assert len(vqe_hamiltonian.ops) > 1 # just to check if this runs