Skip to content

Commit

Permalink
Don't require Tweedledum for qiskit.circuit.classicalfunction on im…
Browse files Browse the repository at this point in the history
…port (#9754)

* Don't require Tweedledum for `qiskit.circuit.classicalfunction` on import

* Review feedback
  • Loading branch information
Eric-Arellano committed Mar 8, 2023
1 parent 9d33618 commit fa7ac68
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 18 deletions.
6 changes: 0 additions & 6 deletions qiskit/circuit/classicalfunction/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,6 @@ def grover_oracle(a: Int1, b: Int1, c: Int1, d: Int1) -> Int1:
"""

from qiskit.utils.optionals import HAS_TWEEDLEDUM

HAS_TWEEDLEDUM.require_now("classical function oracles")

# pylint: disable=wrong-import-position

from .classicalfunction import ClassicalFunction
from .exceptions import (
ClassicalFunctionParseError,
Expand Down
12 changes: 9 additions & 3 deletions qiskit/circuit/classicalfunction/boolean_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
from os.path import basename, isfile
from typing import Callable, Optional

from tweedledum import BitVec, BoolFunction # pylint: disable=import-error
from tweedledum.synthesis import pkrm_synth # pylint: disable=import-error

from qiskit.circuit import QuantumCircuit
from qiskit.utils.optionals import HAS_TWEEDLEDUM
from .classical_element import ClassicalElement


@HAS_TWEEDLEDUM.require_in_instance
class BooleanExpression(ClassicalElement):
"""The Boolean Expression gate."""

Expand All @@ -35,6 +34,8 @@ def __init__(self, expression: str, name: str = None, var_order: list = None) ->
(default: by appearance)
"""

from tweedledum import BoolFunction # pylint: disable=import-error

self._tweedledum_bool_expression = BoolFunction.from_expression(
expression, var_order=var_order
)
Expand All @@ -57,6 +58,8 @@ def simulate(self, bitstring: str) -> bool:
Returns:
bool: result of the evaluation.
"""
from tweedledum import BitVec # pylint: disable=import-error

bits = []
for bit in bitstring:
bits.append(BitVec(1, bit))
Expand Down Expand Up @@ -85,6 +88,7 @@ def synth(

if synthesizer is None:
from .utils import tweedledum2qiskit # Avoid an import cycle
from tweedledum.synthesis import pkrm_synth # pylint: disable=import-error

truth_table = self._tweedledum_bool_expression.truth_table(output_bit=0)
return tweedledum2qiskit(pkrm_synth(truth_table), name=self.name, qregs=qregs)
Expand All @@ -107,6 +111,8 @@ def from_dimacs_file(cls, filename: str):
FileNotFoundError: If filename is not found.
"""

from tweedledum import BoolFunction # pylint: disable=import-error

expr_obj = cls.__new__(cls)
if not isfile(filename):
raise FileNotFoundError("The file %s does not exists." % filename)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
import ast
import _ast

from tweedledum.classical import LogicNetwork # pylint: disable=import-error

from qiskit.utils.optionals import HAS_TWEEDLEDUM
from .exceptions import ClassicalFunctionParseError, ClassicalFunctionCompilerTypeError


@HAS_TWEEDLEDUM.require_in_instance
class ClassicalFunctionVisitor(ast.NodeVisitor):
"""Node visitor as defined in https://docs.python.org/3/library/ast.html#ast.NodeVisitor"""

Expand Down Expand Up @@ -58,6 +58,8 @@ def visit_FunctionDef(self, node):
# Extend scope with the decorator's names
scope.update({decorator.id: ("decorator", None) for decorator in node.decorator_list})

from tweedledum.classical import LogicNetwork # pylint: disable=import-error

self.scopes.append(scope)
self._network = LogicNetwork()
self.extend_scope(node.args)
Expand Down
13 changes: 9 additions & 4 deletions qiskit/circuit/classicalfunction/classicalfunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@
import ast
from typing import Callable, Optional

from tweedledum.classical import simulate # pylint: disable=import-error
from tweedledum.synthesis import pkrm_synth # pylint: disable=import-error

from qiskit.circuit import QuantumCircuit, QuantumRegister
from qiskit.exceptions import QiskitError
from qiskit.utils.optionals import HAS_TWEEDLEDUM
from .classical_element import ClassicalElement
from .classical_function_visitor import ClassicalFunctionVisitor
from .utils import tweedledum2qiskit


@HAS_TWEEDLEDUM.require_in_instance
class ClassicalFunction(ClassicalElement):
"""Represent a classical function function and its logic network."""
"""Represent a classical function and its logic network."""

def __init__(self, source, name=None):
"""Creates a ``ClassicalFunction`` from Python source code in ``source``.
Expand Down Expand Up @@ -107,6 +106,8 @@ def simulate(self, bitstring: str) -> bool:
Returns:
bool: result of the evaluation.
"""
from tweedledum.classical import simulate # pylint: disable=import-error

return simulate(self._network, bitstring)

def simulate_all(self):
Expand All @@ -126,6 +127,8 @@ def simulate_all(self):
@property
def truth_table(self):
"""Returns (and computes) the truth table"""
from tweedledum.classical import simulate # pylint: disable=import-error

if self._truth_table is None:
self._truth_table = simulate(self._network)
return self._truth_table
Expand Down Expand Up @@ -153,6 +156,8 @@ def synth(
if synthesizer:
return synthesizer(self)

from tweedledum.synthesis import pkrm_synth # pylint: disable=import-error

return tweedledum2qiskit(pkrm_synth(self.truth_table[0]), name=self.name, qregs=qregs)

def _define(self):
Expand Down
10 changes: 7 additions & 3 deletions qiskit/circuit/classicalfunction/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@

"""Internal utils for Classical Function Compiler"""

from tweedledum.ir import Qubit # pylint: disable=import-error
from tweedledum.passes import parity_decomp # pylint: disable=import-error

from qiskit.utils.optionals import HAS_TWEEDLEDUM

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library.standard_gates import (
Expand Down Expand Up @@ -42,6 +40,7 @@
}


@HAS_TWEEDLEDUM.require_in_call
def _convert_tweedledum_operator(op):
base_gate = _QISKIT_OPS.get(op.kind())
if base_gate is None:
Expand All @@ -52,6 +51,8 @@ def _convert_tweedledum_operator(op):

# TODO: need to deal with cbits too!
if op.num_controls() > 0:
from tweedledum.ir import Qubit # pylint: disable=import-error

qubits = op.qubits()
ctrl_state = ""
for qubit in qubits[: op.num_controls()]:
Expand All @@ -60,6 +61,7 @@ def _convert_tweedledum_operator(op):
return base_gate()


@HAS_TWEEDLEDUM.require_in_call
def tweedledum2qiskit(tweedledum_circuit, name=None, qregs=None):
"""Converts a `Tweedledum <https://github.com/boschmitt/tweedledum>`_
circuit into a Qiskit circuit.
Expand All @@ -81,6 +83,8 @@ def tweedledum2qiskit(tweedledum_circuit, name=None, qregs=None):
else:
qiskit_qc = QuantumCircuit(tweedledum_circuit.num_qubits(), name=name)

from tweedledum.passes import parity_decomp # pylint: disable=import-error

for instruction in parity_decomp(tweedledum_circuit):
gate = _convert_tweedledum_operator(instruction)
qubits = [qubit.uid() for qubit in instruction.qubits()]
Expand Down

0 comments on commit fa7ac68

Please sign in to comment.