Task: Fixes for dimacs-related boolean expression code (Qiskit/qiskit#14636)

org: Qiskit
repo: qiskit
pr_number: 14636
issue_title: Fixes for dimacs-related boolean expression code
issue_body: <!--\r\n⚠️ If you do not respect this template, your pull request will be closed.\r\n⚠️ Your pull request title should be short detailed and understandable for all.\r\n⚠️ Also, please add a release note file using reno if the change needs to be\r\n  documented in the release notes.\r\n⚠️ If your pull request fixes an open issue, please link to the issue.\r\n\r\n- [ ] I have added the tests to cover my changes.\r\n- [ ] I have updated the documentation accordingly.\r\n- [ ] I have read the CONTRIBUTING document.\r\n-->\r\n\r\n### Summary\r\nThis PR fixes a bug in the code for creating phase and bit-flip oracles from DIMACS files.\r\n\r\nFixes #14634\r\n\r\n\r\n### Details and comments\r\nCurrently, oracles are generated from DIMACS files by using `BooleanExpression.from_dimacs` to generate an expression and pass it to the init of the oracle. However, the init currently expects a string representing a boolean expression, not the expression itself.\r\n\r\nThis PR changes the behavior such that the oracles can be initialized from a `BooleanExpression` object, and slightly improves DIMACS parsing.\r\n\r\n
resolved_issues: number: 14634
title: `PhaseOracle` fails to instantiate from a Dimacs file
body: ### Environment\n\n- **Qiskit version**: 2.0.2 (can't reproduce with 1.4.1)\n- **Python version**: 3.13.3\n- **Operating system**: Arch Linux\n\n\n### What is happening?\n\nTrying to instantiate a `PhaseOracle` using a Dimacs file via the `PhaseOracle.from_dimacs_file` method results in a `TypeError`.\n\n### How can we reproduce the issue?\n\n```python\nimport os\nimport tempfile\nfrom qiskit.circuit.library.phase_oracle import PhaseOracle\n\ninput_3sat_instance = """\nc DIMACS CNF file with 3 satisfying assignments: 1 -2 3, -1 -2 -3, 1 2 -3.\np cnf 3 5\n-1 -2 -3 0\n1 -2 3 0\n1 2 -3 0\n1 -2 -3 0\n-1 2 3 0\n"""\n\nwith open("tmpfile", 'w') as f:\n    f.write(input_3sat_instance)\n\noracle = PhaseOracle.from_dimacs_file("tmpfile")\n```\n\n### What should happen?\n\nThe `PhaseOracle` should be instantiated without error.\n\n### Any suggestions?\n\n_No response_

Reference solution:
fix_patch: diff --git a/qiskit/circuit/library/bit_flip_oracle.py b/qiskit/circuit/library/bit_flip_oracle.py\nindex fbd45c11a4c2..c342a6e27ed1 100644\n--- a/qiskit/circuit/library/bit_flip_oracle.py\n+++ b/qiskit/circuit/library/bit_flip_oracle.py\n@@ -52,23 +52,27 @@ class BitFlipOracleGate(Gate):\n \n     def __init__(\n         self,\n-        expression: str,\n+        expression: str | BooleanExpression,\n         var_order: list[str] | None = None,\n         label: str | None = None,\n     ) -> None:\n         """\n         Args:\n-            expression: A Python-like boolean expression.\n+            expression: A Python-like boolean expression string or a `BooleanExpression` object.\n             var_order: A list with the order in which variables will be created.\n                (default: by appearance)\n             label: A label for the gate to display in visualizations. Per default, the label is\n                 set to display the textual represntation of the boolean expression (truncated if needed)\n         """\n-        self.boolean_expression = BooleanExpression(expression, var_order=var_order)\n-\n         if label is None:\n-            short_expr_for_name = (expression[:15] + "...") if len(expression) > 15 else expression\n-            label = short_expr_for_name\n+            if isinstance(expression, str):\n+                label = (expression[:15] + "...") if len(expression) > 15 else expression\n+            else:\n+                label = "Boolean Expression"\n+\n+        if isinstance(expression, str):\n+            expression = BooleanExpression(expression, var_order=var_order)\n+        self.boolean_expression = expression\n \n         super().__init__(\n             name="Bit-flip Oracle",\ndiff --git a/qiskit/circuit/library/phase_oracle.py b/qiskit/circuit/library/phase_oracle.py\nindex 4b687976b296..96ccc58a798e 100644\n--- a/qiskit/circuit/library/phase_oracle.py\n+++ b/qiskit/circuit/library/phase_oracle.py\n@@ -57,17 +57,19 @@ class PhaseOracle(QuantumCircuit):\n     )\n     def __init__(\n         self,\n-        expression: str,\n+        expression: str | BooleanExpression,\n         var_order: list[str] | None = None,\n     ) -> None:\n         """\n         Args:\n-            expression: A Python-like boolean expression.\n+            expression: A Python-like boolean expression string or a `BooleanExpression` object.\n             var_order: A list with the order in which variables will be created.\n                (default: by appearance)\n         """\n \n-        self.boolean_expression = BooleanExpression(expression, var_order=var_order)\n+        if isinstance(expression, str):\n+            expression = BooleanExpression(expression, var_order=var_order)\n+        self.boolean_expression = expression\n         oracle = self.boolean_expression.synth(circuit_type="phase")\n \n         super().__init__(oracle.num_qubits, name="Phase Oracle")\n@@ -168,23 +170,27 @@ class PhaseOracleGate(Gate):\n \n     def __init__(\n         self,\n-        expression: str,\n+        expression: str | BooleanExpression,\n         var_order: list[str] | None = None,\n         label: str | None = None,\n     ) -> None:\n         """\n         Args:\n-            expression: A Python-like boolean expression.\n+            expression: A Python-like boolean expression string or a `BooleanExpression` object.\n             var_order: A list with the order in which variables will be created.\n                (default: by appearance)\n             label: A label for the gate to display in visualizations. Per default, the label is\n                 set to display the textual represntation of the boolean expression (truncated if needed)\n         """\n-        self.boolean_expression = BooleanExpression(expression, var_order=var_order)\n-\n         if label is None:\n-            short_expr_for_name = (expression[:15] + "...") if len(expression) > 15 else expression\n-            label = short_expr_for_name\n+            if isinstance(expression, str):\n+                label = (expression[:15] + "...") if len(expression) > 15 else expression\n+            else:\n+                label = "Boolean Expression"\n+\n+        if isinstance(expression, str):\n+            expression = BooleanExpression(expression, var_order=var_order)\n+        self.boolean_expression = expression\n \n         super().__init__(\n             name="Phase Oracle",\ndiff --git a/qiskit/synthesis/boolean/boolean_expression.py b/qiskit/synthesis/boolean/boolean_expression.py\nindex 5122dbf9637d..1aaa348d16e8 100644\n--- a/qiskit/synthesis/boolean/boolean_expression.py\n+++ b/qiskit/synthesis/boolean/boolean_expression.py\n@@ -191,8 +191,9 @@ def from_dimacs(dimacs: str):\n         """\n         header_regex = re.compile(r"p\\s+cnf\\s+(\\d+)\\s+(\\d+)")\n         clause_regex = re.compile(r"(-?\\d+)")\n+        lines = [line.strip() for line in dimacs.split("\\n")]\n         lines = [\n-            line for line in dimacs.split("\\n") if not line.startswith("c") and line != ""\n+            line for line in lines if not line.startswith("c") and line != ""\n         ]  # DIMACS comment line start with c\n         header_match = header_regex.match(lines[0])\n         if not header_match:\ndiff --git a/releasenotes/notes/fix-dimacs-load-c48f4d08062ade74.yaml b/releasenotes/notes/fix-dimacs-load-c48f4d08062ade74.yaml\nnew file mode 100644\nindex 000000000000..98a708d5f0c1\n--- /dev/null\n+++ b/releasenotes/notes/fix-dimacs-load-c48f4d08062ade74.yaml\n@@ -0,0 +1,5 @@\n+---\n+fixes:\n+  - |\n+    Fixed a bug in :class:`.PhaseOracle`, :class:`.PhaseOracleGate` and :class:`.BitFlipOracleGate`\n+    where trying to load from dimacs file raised a TypeError.\n\\ No newline at end of file\n