diff --git a/qiskit/circuit/classicalfunction/boolean_expression.py b/qiskit/circuit/classicalfunction/boolean_expression.py index 8ac4c8356f24..7a66f2a202bc 100644 --- a/qiskit/circuit/classicalfunction/boolean_expression.py +++ b/qiskit/circuit/classicalfunction/boolean_expression.py @@ -25,15 +25,19 @@ class BooleanExpression(ClassicalElement): """The Boolean Expression gate.""" - def __init__(self, expression: str, name: str = None) -> None: + def __init__(self, expression: str, name: str = None, var_order: list = None) -> None: """ Args: expression (str): The logical expression string. - name (str): Optional. Instruction gate name. Otherwise part of - the expression is going to be used. + name (str): Optional. Instruction gate name. Otherwise part of the expression is + going to be used. + var_order(list): A list with the order in which variables will be created. + (default: by appearance) """ - self._tweedledum_bool_expression = BoolFunction.from_expression(expression) + self._tweedledum_bool_expression = BoolFunction.from_expression( + expression, var_order=var_order + ) short_expr_for_name = (expression[:10] + "...") if len(expression) > 13 else expression num_qubits = ( diff --git a/qiskit/circuit/library/phase_oracle.py b/qiskit/circuit/library/phase_oracle.py index 699eddacbd1a..f00a8d56255a 100644 --- a/qiskit/circuit/library/phase_oracle.py +++ b/qiskit/circuit/library/phase_oracle.py @@ -52,6 +52,7 @@ def __init__( self, expression: Union[str, ClassicalElement], synthesizer: Optional[Callable[[BooleanExpression], QuantumCircuit]] = None, + var_order: list = None, ) -> None: """Creates a PhaseOracle object @@ -59,12 +60,14 @@ def __init__( expression: A Python-like boolean expression. synthesizer: Optional. A function to convert a BooleanExpression into a QuantumCircuit If None is provided, Tweedledum's `pkrm_synth` with `phase_esop` will be used. + var_order(list): A list with the order in which variables will be created. + (default: by appearance) """ from qiskit.circuit.classicalfunction.boolean_expression import BooleanExpression from qiskit.circuit.classicalfunction.classical_element import ClassicalElement if not isinstance(expression, ClassicalElement): - expression = BooleanExpression(expression) + expression = BooleanExpression(expression, var_order=var_order) self.boolean_expression = expression diff --git a/releasenotes/notes/expression-var-order-d87e9b04fb5d545c.yaml b/releasenotes/notes/expression-var-order-d87e9b04fb5d545c.yaml new file mode 100644 index 000000000000..24f5b47da3d6 --- /dev/null +++ b/releasenotes/notes/expression-var-order-d87e9b04fb5d545c.yaml @@ -0,0 +1,18 @@ +--- +features: + - | + Add the parameter `var_order` when defining a `PhaseOracle`. This allows for defining the order in which the variables in the logical expression are being considered. + + .. code-block::python + + from qiskit import * + from qiskit.tools.visualization import plot_histogram + from qiskit.circuit.library import PhaseOracle + from qiskit.algorithms import Grover, AmplificationProblem + + oracle = PhaseOracle('((A & C) | (B & D)) & ~(C & D)', var_order=['A', 'B', 'C', 'D']) + problem = AmplificationProblem(oracle=oracle, is_good_state=oracle.evaluate_bitstring) + backend = Aer.get_backend('qasm_simulator') + grover = Grover(quantum_instance=backend) + result = grover.amplify(problem) + print(result.circuit_results[0]) diff --git a/test/python/circuit/library/test_phase_oracle.py b/test/python/circuit/library/test_phase_oracle.py index 825a8c00a802..e15d6df8ee60 100644 --- a/test/python/circuit/library/test_phase_oracle.py +++ b/test/python/circuit/library/test_phase_oracle.py @@ -69,6 +69,32 @@ def test_statevector(self, expression, good_states): self.assertListEqual(expected_valid, result_valid) self.assertListEqual(expected_invalid, result_invalid) + @data( + ("((A & C) | (B & D)) & ~(C & D)", None, [3, 7, 12, 13]), + ("((A & C) | (B & D)) & ~(C & D)", ["A", "B", "C", "D"], [5, 7, 10, 11]), + ) + @unpack + def test_variable_order(self, expression, var_order, good_states): + """Circuit generation""" + oracle = PhaseOracle(expression, var_order=var_order) + num_qubits = oracle.num_qubits + circuit = QuantumCircuit(num_qubits) + circuit.h(range(num_qubits)) + circuit.compose(oracle, inplace=True) + statevector = Statevector.from_instruction(circuit) + + valid_state = -1 / sqrt(2**num_qubits) + invalid_state = 1 / sqrt(2**num_qubits) + + states = list(range(2**num_qubits)) + expected_valid = [state in good_states for state in states] + result_valid = [isclose(statevector.data[state], valid_state) for state in states] + + expected_invalid = [state not in good_states for state in states] + result_invalid = [isclose(statevector.data[state], invalid_state) for state in states] + self.assertListEqual(expected_valid, result_valid) + self.assertListEqual(expected_invalid, result_invalid) + if __name__ == "__main__": unittest.main()