Repository: Qiskit/qiskit

Issue:
QASM version of a controlled gate
<!-- ⚠️ 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**: 0.16.0
- **Python version**: 3.8.5
- **Operating system**: MacOS 10.15.7

### What is the current behavior?

Consider the following code snippet. Both gates have the same qasm representation. 

```
from qiskit.circuit.library import RYGate
gate_ctrl_0 = RYGate(1).control(num_ctrl_qubits=1, ctrl_state='0')
gate_ctrl_1 = RYGate(1).control(num_ctrl_qubits=1, ctrl_state='1')
print(gate_ctrl_0.qasm())
print(gate_ctrl_1.qasm())
```

```
cry(1)
cry(1)
```

### Steps to reproduce the problem

### What is the expected behavior?
A controlled gate, with control state equals to 0 will be represented with additional X gates.


### Suggested solutions





Discussion:

Resolving patch:
diff --git a/qiskit/circuit/controlledgate.py b/qiskit/circuit/controlledgate.py
--- a/qiskit/circuit/controlledgate.py
+++ b/qiskit/circuit/controlledgate.py
@@ -92,6 +92,7 @@ def __init__(self, name: str, num_qubits: int, params: List,
         self.definition = copy.deepcopy(definition)
         self._ctrl_state = None
         self.ctrl_state = ctrl_state
+        self._name = name
 
     @property
     def definition(self) -> List:
@@ -125,6 +126,29 @@ def definition(self, excited_def: 'QuantumCircuit'):
             excited_def: The circuit with all closed controls."""
         super(Gate, self.__class__).definition.fset(self, excited_def)
 
+    @property
+    def name(self) -> str:
+        """Get name of gate. If the gate has open controls the gate name
+        will become:
+
+           <original_name_o<ctrl_state>
+
+        where <original_name> is the gate name for the default case of
+        closed control qubits and <ctrl_state> is the integer value of
+        the control state for the gate.
+        """
+        if self._open_ctrl:
+            return f'{self._name}_o{self.ctrl_state}'
+        else:
+            return self._name
+
+    @name.setter
+    def name(self, name_str):
+        """Set the name of the gate. Note the reported name may differ
+        from the set name if the gate has open controls.
+        """
+        self._name = name_str
+
     @property
     def num_ctrl_qubits(self):
         """Get number of control qubits.
diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py
--- a/qiskit/circuit/quantumcircuit.py
+++ b/qiskit/circuit/quantumcircuit.py
@@ -1172,8 +1172,11 @@ def qasm(self, formatted=False, filename=None):
                 ``True``.
             QasmError: If circuit has free parameters.
         """
+        from qiskit.circuit.controlledgate import ControlledGate
+
         if self.num_parameters > 0:
             raise QasmError('Cannot represent circuits with unbound parameters in OpenQASM 2.')
+
         existing_gate_names = ['ch', 'cp', 'cx', 'cy', 'cz', 'crx', 'cry', 'crz', 'ccx', 'cswap',
                                'csx', 'cu', 'cu1', 'cu3', 'dcx', 'h', 'i', 'id', 'iden', 'iswap',
                                'ms', 'p', 'r', 'rx', 'rxx', 'ry', 'ryy', 'rz', 'rzx', 'rzz', 's',
@@ -1197,7 +1200,10 @@ def qasm(self, formatted=False, filename=None):
                                                            qubit.register.name, qubit.index,
                                                            clbit.register.name, clbit.index)
             # If instruction is a root gate or a root instruction (in that case, compositive)
-            elif type(instruction) in [Gate, Instruction]:  # pylint: disable=unidiomatic-typecheck
+
+            elif (type(instruction) in  # pylint: disable=unidiomatic-typecheck
+                  [Gate, Instruction] or
+                  (isinstance(instruction, ControlledGate) and instruction._open_ctrl)):
                 if instruction not in existing_composite_circuits:
                     if instruction.name in existing_gate_names:
                         old_name = instruction.name


Test patch:
diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py
--- a/test/python/circuit/test_circuit_qasm.py
+++ b/test/python/circuit/test_circuit_qasm.py
@@ -220,3 +220,11 @@ def test_unbound_circuit_raises(self):
         qc.rz(theta, 0)
         with self.assertRaises(QasmError):
             qc.qasm()
+
+    def test_gate_qasm_with_ctrl_state(self):
+        """Test gate qasm() with controlled gate that has ctrl_state setting."""
+        from qiskit.quantum_info import Operator
+        qc = QuantumCircuit(2)
+        qc.ch(0, 1, ctrl_state=0)
+        qasm_str = qc.qasm()
+        self.assertEqual(Operator(qc), Operator(QuantumCircuit.from_qasm_str(qasm_str)))