Repository: Qiskit/qiskit

Issue:
Circuit parameters are not cleared via `global_phase` setter
### Environment

- **Qiskit Terra version**: 1.0
- **Python version**: 3.11
- **Operating system**: MacOS


### What is happening?

I've run into a bug when working with parameteric circuits and think I have tracked it down to the `global_phase` setter. The issue is that if a circuit has a parametric global phase, and then this is set to a numeric value (in my case 0), while the circuit parameter table is updated to remove the phase parameter, the `circuit.parameters` is not.

### How can we reproduce the issue?

```python
# Make a circuit with parametric global phase
qc = QuantumCircuit(1)
qc.global_phase = Parameter("a")

# Print parameters and parameter table
print(qc.parameters)
print(qc._parameter_table)

ParameterView([Parameter(a)])
ParameterTable({Parameter(a): ParameterReferences([(<global-phase sentinel>, None)])})
```


```python
# Now zero phase and print again
qc.global_phase = 0
print(qc.parameters)
print(qc._parameter_table)

ParameterView([Parameter(a)])
ParameterTable({})
```

### What should happen?

I would expect after setting `globla_phase = 0` `Parameter("a")` should no longer appear in `circuit.parameters`, since it is not present in the circuit any longer.

### Any suggestions?

Circuit.parameters is cached the first time it is called, so likely the globla_phase setter in the first case should also clear the cache by setting `self._parameters = None` when re-assigning a parametric circuit global phase.


Discussion:
This issue seems to be present in early versions too (<=0.46), though in those cases the parameter doesn't seem to appear in the parameter table mapping, and the two cases above both print
```
ParameterView([Parameter(a)])
ParameterTable({})
```
when the second should print
```
ParameterView([])
ParameterTable({})
```
Yeah, looks like a straight bug in the `global_phase` setter thanks - it touches the `ParameterTable` but doesn't invalidate the cached value.

Resolving patch:
diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py
--- a/qiskit/circuit/quantumcircuit.py
+++ b/qiskit/circuit/quantumcircuit.py
@@ -2932,6 +2932,7 @@ def global_phase(self, angle: ParameterValueType):
         # called by some subclasses before the inner `_global_phase` is initialised.
         global_phase_reference = (ParameterTable.GLOBAL_PHASE, None)
         if isinstance(previous := getattr(self, "_global_phase", None), ParameterExpression):
+            self._parameters = None
             self._parameter_table.discard_references(previous, global_phase_reference)
 
         if isinstance(angle, ParameterExpression) and angle.parameters:


Test patch:
diff --git a/test/python/circuit/test_parameters.py b/test/python/circuit/test_parameters.py
--- a/test/python/circuit/test_parameters.py
+++ b/test/python/circuit/test_parameters.py
@@ -192,6 +192,24 @@ def test_get_parameter_global_phase(self):
         self.assertIs(qc.get_parameter("x"), x)
         self.assertIsNone(qc.get_parameter("y", None), None)
 
+    def test_setting_global_phase_invalidates_cache(self):
+        """Test that setting the global phase to a non-parametric value invalidates the `parameters`
+        cache of the circuit."""
+        x = Parameter("x")
+        qc = QuantumCircuit(0, global_phase=x)
+        self.assertEqual(qc.global_phase, x)
+        self.assertEqual(set(qc.parameters), {x})
+        qc.global_phase = 0
+        self.assertEqual(qc.global_phase, 0)
+        self.assertEqual(set(qc.parameters), set())
+
+        qc = QuantumCircuit(0, global_phase=0)
+        self.assertEqual(qc.global_phase, 0)
+        self.assertEqual(set(qc.parameters), set())
+        qc.global_phase = x
+        self.assertEqual(qc.global_phase, x)
+        self.assertEqual(set(qc.parameters), {x})
+
     def test_has_parameter(self):
         """Test the `has_parameter` method."""
         x = Parameter("x")