Skip to content

Commit

Permalink
New support for other to other.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfleury-sb committed Aug 18, 2022
1 parent 359e3c5 commit 038c500
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 2 deletions.
16 changes: 16 additions & 0 deletions tangelo/linq/tests/data/H2_JW_occfirst.data
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
QubitOperator:
(-0.10973055606700678+0j) [] +
(-0.0454428841443262+0j) [X0 X1 Y2 Y3] +
(0.0454428841443262+0j) [X0 Y1 Y2 X3] +
(0.0454428841443262+0j) [Y0 X1 X2 Y3] +
(-0.0454428841443262+0j) [Y0 Y1 X2 X3] +
(0.16988452027940382+0j) [Z0] +
(0.16821198673715723+0j) [Z0 Z1] +
(0.12005143072546026+0j) [Z0 Z2] +
(0.16549431486978647+0j) [Z0 Z3] +
(0.16988452027940382+0j) [Z1] +
(0.16549431486978647+0j) [Z1 Z2] +
(0.12005143072546026+0j) [Z1 Z3] +
(-0.21886306781219628+0j) [Z2] +
(0.17395378776494128+0j) [Z2 Z3] +
(-0.21886306781219633+0j) [Z3]
90 changes: 90 additions & 0 deletions tangelo/linq/tests/test_translator_qubitop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2021 Good Chemistry Company.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import unittest

import numpy as np
from openfermion.utils import load_operator
from openfermion.linalg import eigenspectrum

from tangelo.helpers.utils import installed_backends
from tangelo.linq.translator.translate_qubitop import translate_operator
from tangelo.toolboxes.operators import QubitOperator

# For openfermion.load_operator function.
pwd_this_test = os.path.dirname(os.path.abspath(__file__))

tangelo_op = QubitOperator("X0 Y1 Z2", 1.)


class TranslateOperatorTest(unittest.TestCase):

def test_unsupported_source(self):
"""Test error with an unsuported source."""

with self.assertRaises(NotImplementedError):
translate_operator(tangelo_op, source="sourcenotsupported", target="tangelo")

def test_unsupported_target(self):
"""Test error with an unsuported target."""

with self.assertRaises(NotImplementedError):
translate_operator(tangelo_op, source="tangelo", target="targetnotsupported")

def test_tangelo_not_involved(self):
"""Test error if tangelo is not the source nor the target."""

with self.assertRaises(NotImplementedError):
translate_operator(tangelo_op, source="nottangelo", target="nottangeloeither")

@unittest.skipIf("qiskit" not in installed_backends, "Test Skipped: Qiskit not available \n")
def test_qiskit_to_tangelo(self):
"""Test translation from a qiskit to a tangelo operator."""

from qiskit.opflow.primitive_ops import PauliSumOp
qiskit_op = PauliSumOp.from_list([("ZYX", 1.)])

test_op = translate_operator(qiskit_op, source="qiskit", target="tangelo")
self.assertEqual(test_op, tangelo_op)

@unittest.skipIf("qiskit" not in installed_backends, "Test Skipped: Qiskit not available \n")
def test_tangelo_to_qiskit(self):
"""Test translation from a tangelo to a qiskit operator."""

from qiskit.opflow.primitive_ops import PauliSumOp
qiskit_op = PauliSumOp.from_list([("ZYX", 1.)])

test_op = translate_operator(tangelo_op, source="tangelo", target="qiskit")
self.assertEqual(qiskit_op, test_op)

@unittest.skipIf("qiskit" not in installed_backends, "Test Skipped: Qiskit not available \n")
def test_tangelo_to_qiskit_H2_eigenvalues(self):
"""Test eigenvalues resulting from a tangelo to qiskit translation."""

from qiskit.algorithms import NumPyEigensolver

qu_op = load_operator("H2_JW_occfirst.data", data_directory=pwd_this_test+"/data", plain_text=True)
test_op = translate_operator(qu_op, source="tangelo", target="qiskit")

eigenvalues_tangelo = eigenspectrum(qu_op)

qiskit_solver = NumPyEigensolver(2**4)
eigenvalues_qiskit = qiskit_solver.compute_eigenvalues(test_op)

np.testing.assert_array_almost_equal(eigenvalues_tangelo, eigenvalues_qiskit.eigenvalues)


if __name__ == "__main__":
unittest.main()
62 changes: 60 additions & 2 deletions tangelo/linq/translator/translate_qiskit.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""Functions helping with quantum circuit format conversion between abstract
format and qiskit format.
"""Functions helping with quantum circuit and operator format conversion between
Tangelo format and qiskit format.
In order to produce an equivalent circuit for the target backend, it is
necessary to account for:
Expand All @@ -22,6 +22,9 @@
may also differ.
"""

from tangelo.toolboxes.operators import QubitOperator
from tangelo.linq.helpers import pauli_of_to_string, pauli_string_to_of


def get_qiskit_gates():
"""Map gate name of the abstract format to the equivalent add_gate method of
Expand Down Expand Up @@ -98,3 +101,58 @@ def translate_qiskit(source_circuit):
else:
raise ValueError(f"Gate '{gate.name}' not supported on backend qiskit")
return target_circuit


def quop_tangelo_to_qiskit(qubit_operator, n_qubits):
"""Helper function to translate a Tangelo QubitOperator to a qiskit
PauliSumOp. Qiskit must be installed for the function to work.
Args:
qubit_operator (tangelo.toolboxes.operators.QubitOperator): Self-explanatory.
n_qubits (int): Number of qubits relevant to the operator.
Returns:
(qiskit.opflow.primitive_ops.PauliSumOp): Qiskit qubit operator.
"""

# Import qiskit qubit operator.
from qiskit.opflow.primitive_ops import PauliSumOp

# Convert each term sequencially.
term_list = list()
for term_tuple, coeff in qubit_operator.terms.items():
term_string = pauli_of_to_string(term_tuple, n_qubits)

# Reverse the string because of qiskit convention.
term_list += [(term_string[::-1], coeff)]

return PauliSumOp.from_list(term_list)


def quop_qiskit_to_tangelo(qubit_operator):
"""Helper function to translate a a qiskit PauliSumOp to a Tangelo
QubitOperator.
Args:
qubit_operator (qiskit.opflow.primitive_ops.PauliSumOp): Self-explanatory.
Returns:
(tangelo.toolboxes.operators.QubitOperator): Tangelo qubit operator.
"""

# Create a dictionary to append all terms at once.
terms_dict = dict()
for pauli_word in qubit_operator:
# Inversion of the string because of qiskit ordering.
term_string = pauli_word.to_pauli_op().primitive.to_label()[::-1]
term_tuple = pauli_string_to_of(term_string)
terms_dict[tuple(term_tuple)] = pauli_word.coeff

# Create and copy the information into a new QubitOperator.
tangelo_op = QubitOperator()
tangelo_op.terms = terms_dict

# Clean the QubitOperator.
tangelo_op.compress()

return tangelo_op
58 changes: 58 additions & 0 deletions tangelo/linq/translator/translate_qubitop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2021 Good Chemistry Company.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Module to convert qubit operators to different formats."""

from tangelo.toolboxes.operators import count_qubits
from tangelo.linq.translator.translate_qiskit import quop_qiskit_to_tangelo, quop_tangelo_to_qiskit


FROM_TANGELO = {
"qiskit": quop_tangelo_to_qiskit
}

TO_TANGELO = {
"qiskit": quop_qiskit_to_tangelo
}


def translate_operator(qubit_operator, source, target, n_qubits=None):
"""Function to convert a qubit operator defined within the "source" format
to another format. Only the translation from and to tangelo are currently
supported.
Args:
qubit_operator (source format): Self-explanatory.
source (string): Identifier for the source format.
target (string): Identifier for the target format.
n_qubits (int): Number of qubits relevant to the operator.
Returns:
(target format): Translated qubit operator.
"""

source = source.lower()
target = target.lower()

if source != "tangelo":
if source not in TO_TANGELO:
raise NotImplementedError(f"Source {source} is not supported.")
qubit_operator = TO_TANGELO[source](qubit_operator)
if target != "tangelo":
if target not in FROM_TANGELO:
raise NotImplementedError(f"Target {target} is not supported.")
n_qubits = count_qubits(qubit_operator) if n_qubits is None else n_qubits
qubit_operator = FROM_TANGELO[target](qubit_operator, n_qubits)

return qubit_operator

0 comments on commit 038c500

Please sign in to comment.