Repository: Qiskit/qiskit (python)

Issue:
EvolvedOperatorAnsatz with an empty list of operators
### Environment

- **Qiskit version**: 0.45.2
- **Python version**: 3.11.6
- **Operating system**: GNU/Linux


### What is happening?

If we set `operators` in [EvolvedOperatorAnsatz](https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.EvolvedOperatorAnsatz) to an empty list, it raises an unhandled exception and fails to create an object.

This case can happen when we use [UCCSD](https://qiskit-community.github.io/qiskit-nature/stubs/qiskit_nature.second_q.circuit.library.UCCSD.html) ansatz from qiskit_nature with a molecule that has no electrons.

### How can we reproduce the issue?

Running the following code
```python
from qiskit.circuit.library import EvolvedOperatorAnsatz
from qiskit import QuantumCircuit

e = EvolvedOperatorAnsatz(operators=[])
e == QuantumCircuit()
```
raises the following error:
```  
File "/..../site-packages/qiskit/circuit/library/evolved_operator_ansatz.py", line 109, in num_qubits
    return self.operators.num_qubits
           ^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'num_qubits'
```

### What should happen?

It was expected to return `True` as the case with no qubit is handled well in `QuantumCircuit` and its subclasses. It was partially handled in the `EvolvedOperatorAnsatz` too. For example
https://github.com/Qiskit/qiskit/blob/d033e8a4185c0299b644f0bdf4e8ed1d17d2bb08/qiskit/circuit/library/n_local/evolved_operator_ansatz.py#L109
  shows the previous intention to handle this case. But it is not completely done so it raises an unhandled exception.

### Any suggestions?

I'll create a pull request to discuss the proposed solution.

Pull request:
Fix evolved operator ansatz (backport #11682)


### Summary

This resolves #11680, which pertains to a bug encountered when creating an EvolvedOperatorAnsatz with an empty list of operators.

### Details and comments

The changes implemented ensure that EvolvedOperatorAnsatz.num_qubits returns a sensible result (specifically zero) when operators is an empty list, rather than throwing an error. This adjustment alone enables the following code to function correctly:

```python
e = EvolvedOperatorAnsatz(operators=[])
```


By solely doing this, in the above code, e.qregs contains a QuantumRegister with zero qubits. While its base class, QuantumCircuit, handles the case with no qubits by setting qregs to an empty list.

https://github.com/Qiskit/qiskit/blob/d033e8a4185c0299b644f0bdf4e8ed1d17d2bb08/qiskit/circuit/quantumcircuit.py#L1454

We have mirrored this behavior in EvolvedOperatorAnsatz to ensure that `EvolvedOperatorAnsatz(operators=[])` behaves the same as `QuantumCircuit()`. This equivalence is also asserted in a test.

Please note that a brief release note has been added to the branch.
<hr>This is an automatic backport of pull request #11682 done by [Mergify](https://mergify.com).

Patch:
diff --git a/qiskit/circuit/library/evolved_operator_ansatz.py b/qiskit/circuit/library/evolved_operator_ansatz.py
index a3832bfb7..ac0b1fb2e 100644
--- a/qiskit/circuit/library/evolved_operator_ansatz.py
+++ b/qiskit/circuit/library/evolved_operator_ansatz.py
@@ -103,7 +103,9 @@ class EvolvedOperatorAnsatz(NLocal):
         if self.operators is None:
             return 0
 
-        if isinstance(self.operators, list) and len(self.operators) > 0:
+        if isinstance(self.operators, list):
+            if len(self.operators) == 0:
+                return 0
             return self.operators[0].num_qubits
 
         return self.operators.num_qubits
@@ -155,7 +157,10 @@ class EvolvedOperatorAnsatz(NLocal):
         operators = _validate_operators(operators)
         self._invalidate()
         self._operators = operators
-        self.qregs = [QuantumRegister(self.num_qubits, name="q")]
+        if self.num_qubits == 0:
+            self.qregs = []
+        else:
+            self.qregs = [QuantumRegister(self.num_qubits, name="q")]
 
     # TODO: the `preferred_init_points`-implementation can (and should!) be improved!
     @property
diff --git a/qiskit/qobj/converters/pulse_instruction.py b/qiskit/qobj/converters/pulse_instruction.py
index 08aa0a27f..4377139f3 100644
--- a/qiskit/qobj/converters/pulse_instruction.py
+++ b/qiskit/qobj/converters/pulse_instruction.py
@@ -243,7 +243,7 @@ class InstructionToQobjConverter:
             "name": "setf",
             "t0": time_offset + instruction.start_time,
             "ch": instruction.channel.name,
-            "frequency": instruction.frequency / 1e9,
+            "frequency": instruction.frequency / 10**9,
         }
         return self._qobj_model(**command_dict)
 
@@ -266,7 +266,7 @@ class InstructionToQobjConverter:
             "name": "shiftf",
             "t0": time_offset + instruction.start_time,
             "ch": instruction.channel.name,
-            "frequency": instruction.frequency / 1e9,
+            "frequency": instruction.frequency / 10**9,
         }
         return self._qobj_model(**command_dict)
 
@@ -836,7 +836,7 @@ class QobjToInstructionConverter:
         .. note::
 
             We assume frequency value is expressed in string with "GHz".
-            Operand value is thus scaled by a factor of 1e9.
+            Operand value is thus scaled by a factor of 10^9.
 
         Args:
             instruction: SetFrequency qobj instruction
@@ -845,7 +845,7 @@ class QobjToInstructionConverter:
             Qiskit Pulse set frequency instructions
         """
         channel = self.get_channel(instruction.ch)
-        frequency = self.disassemble_value(instruction.frequency) * 1e9
+        frequency = self.disassemble_value(instruction.frequency) * 10**9
 
         yield instructions.SetFrequency(frequency, channel)
 
@@ -858,7 +858,7 @@ class QobjToInstructionConverter:
         .. note::
 
             We assume frequency value is expressed in string with "GHz".
-            Operand value is thus scaled by a factor of 1e9.
+            Operand value is thus scaled by a factor of 10^9.
 
         Args:
             instruction: ShiftFrequency qobj instruction
@@ -867,7 +867,7 @@ class QobjToInstructionConverter:
             Qiskit Pulse shift frequency schedule instructions
         """
         channel = self.get_channel(instruction.ch)
-        frequency = self.disassemble_value(instruction.frequency) * 1e9
+        frequency = self.disassemble_value(instruction.frequency) * 10**9
 
         yield instructions.ShiftFrequency(frequency, channel)
 
diff --git a/releasenotes/notes/fix-evolved-operator-ansatz-empty-ops-bf8ecfae8f1e1001.yaml b/releasenotes/notes/fix-evolved-operator-ansatz-empty-ops-bf8ecfae8f1e1001.yaml
new file mode 100644
index 000000000..2f941d42a
--- /dev/null
+++ b/releasenotes/notes/fix-evolved-operator-ansatz-empty-ops-bf8ecfae8f1e1001.yaml
@@ -0,0 +1,11 @@
+---
+fixes:
+  - |
+    The :class:`.EvolvedOperatorAnsatz` now correctly handles the case where the
+    `operators` argument is an empty list. Previously, this would result in an
+    error.
+  - |
+    From now on, :class:`.EvolvedOperatorAnsatz` will not have any `qregs` when
+    thera are zero qubits, instead of having a :class:`.QuantumRegister` instance
+    with zero qubits. This behavior aligns more consistently with its superclass 
+    :class:`.QuantumCircuit`.
diff --git a/releasenotes/notes/fix-symbolic-unit-scaling-c3eb4d9be674dfd6.yaml b/releasenotes/notes/fix-symbolic-unit-scaling-c3eb4d9be674dfd6.yaml
new file mode 100644
index 000000000..5ca00904a
--- /dev/null
+++ b/releasenotes/notes/fix-symbolic-unit-scaling-c3eb4d9be674dfd6.yaml
@@ -0,0 +1,8 @@
+---
+fixes:
+  - |
+    Fixed a floating-point imprecision when scaling certain pulse units
+    between seconds and nanoseconds.  If the pulse was symbolically defined,
+    an unnecessary floating-point error could be introduced by the scaling
+    for certain builds of ``symengine``, which could manifest in unexpected
+    results once the symbols were fully bound.  See `#12392 <https://github.com/Qiskit/qiskit/pull/12392>`__.


Test patch:
diff --git a/test/python/circuit/library/test_evolved_op_ansatz.py b/test/python/circuit/library/test_evolved_op_ansatz.py
index 06bcc206d..e6cebe163 100644
--- a/test/python/circuit/library/test_evolved_op_ansatz.py
+++ b/test/python/circuit/library/test_evolved_op_ansatz.py
@@ -113,6 +113,11 @@ class TestEvolvedOperatorAnsatz(QiskitTestCase):
         with self.assertRaises(ValueError):
             _ = evo.draw()
 
+    def test_empty_operator_list(self):
+        """Test setting an empty list of operators to be equal to an empty circuit."""
+        evo = EvolvedOperatorAnsatz([])
+        self.assertEqual(evo, QuantumCircuit())
+
     def test_matrix_operator(self):
         """Test passing a quantum_info.Operator uses the HamiltonianGate."""
         unitary = Operator([[0, 1], [1, 0]])