Repository: Qiskit/qiskit

Issue:
Parameter assignment has a bug
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: commit c06f50c028638161153909e10fcefe7c4f2eef06 of master.
- **Python version**: 3.7.3
- **Operating system**: Ubuntu

### What is the current behavior?
Assigning a parameter to another parameter in the circuit overwrites the `_parameter_table` when there already is an entry.

### Steps to reproduce the problem
The following code illustrates the problem:
```
a = Parameter('a')
b = Parameter('b')

qc1 = QuantumCircuit(1)
qc1.rx(a, 0)
qc1.ry(b, 0)
print(qc1._parameter_table)
qc1.assign_parameters({a: -b}, inplace=True)
print(qc1._parameter_table)
```
The first print statement yields:
```
ParameterTable({
Parameter(a): [(<qiskit.[...].RXGate object at 0x7ff79fcc6668>, 0)], 
Parameter(b): [(<qiskit.[...].RYGate object at 0x7ff79fcc66d8>, 0)]
})
```
And the second print statement gives
```
ParameterTable({
Parameter(b): [(<qiskit.[...].RXGate object at 0x7ff79fcc6668>, 0)]
})
```

### What is the expected behavior?
We should see the `RYGate` in the second print output under `Parameter(b)`.

### Suggested solutions
The issue appears to be in `QuantumCircuit._assign_parameter(self, parameter, value)` at the lines
```
    if isinstance(value, ParameterExpression):
        entry = self._parameter_table.pop(parameter)
        for new_parameter in value.parameters:
            self._parameter_table[new_parameter] = entry
```




Discussion:

Resolving patch:
diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py
--- a/qiskit/circuit/quantumcircuit.py
+++ b/qiskit/circuit/quantumcircuit.py
@@ -2043,7 +2043,10 @@ def _assign_parameter(self, parameter, value):
         if isinstance(value, ParameterExpression):
             entry = self._parameter_table.pop(parameter)
             for new_parameter in value.parameters:
-                self._parameter_table[new_parameter] = entry
+                if new_parameter in self._parameter_table:
+                    self._parameter_table[new_parameter].extend(entry)
+                else:
+                    self._parameter_table[new_parameter] = entry
         else:
             del self._parameter_table[parameter]  # clear evaluated expressions
 


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
@@ -252,6 +252,24 @@ def test_expression_partial_binding(self):
                 self.assertTrue(isinstance(fbqc.data[0][0].params[0], ParameterExpression))
                 self.assertEqual(float(fbqc.data[0][0].params[0]), 3)
 
+    def test_two_parameter_expression_binding(self):
+        """Verify that for a circuit with parameters theta and phi that
+        we can correctly assign theta to -phi.
+        """
+        theta = Parameter('theta')
+        phi = Parameter('phi')
+
+        qc = QuantumCircuit(1)
+        qc.rx(theta, 0)
+        qc.ry(phi, 0)
+
+        self.assertEqual(len(qc._parameter_table[theta]), 1)
+        self.assertEqual(len(qc._parameter_table[phi]), 1)
+
+        qc.assign_parameters({theta: -phi}, inplace=True)
+
+        self.assertEqual(len(qc._parameter_table[phi]), 2)
+
     def test_expression_partial_binding_zero(self):
         """Verify that binding remains possible even if a previous partial bind
         would reduce the expression to zero.