Repository: Qiskit/qiskit

Issue:
QPY fails to serialize `MCXGrayCode` gate
### Environment

- **Qiskit Terra version**: 0.22.4
- **Python version**: 3.9
- **Operating system**: macOS Monterey 12.6


### What is happening?

When you try to serialize a circuit with an `MCXGrayCode` gate using qpy, you get `TypeError: __init__() missing 1 required positional argument: 'num_ctrl_qubits'`. As far as I have seen, other mcx gates do not run into this issue.

I discovered this while trying to run iterative amplitude estimation using the runtime `Sampler`, which relies on `qpy` for serialization.

### How can we reproduce the issue?

```
  from qiskit import QuantumCircuit, qpy
  circuit = QuantumCircuit(11)
  circuit.mcx(list(range(0,9)), 10)
  print('gate name:', circuit.data[0][0].name)

  with open('test.qpy', 'wb') as fd:
      qpy.dump(circuit, fd)

  with open('test.qpy', 'rb') as fd:
      new_qc = qpy.load(fd)[0]
```
This snippet will fail with a similar traceback to:

```
gate name: mcx_gray
  File "/Users/ept/Downloads/ExamplePEO.py", line 131, in <module>
    new_qc = qpy.load(fd)[0]
  File "/Users/ept/Desktop/qgt/qiskit/qpy/interface.py", line 269, in load
    loader(
  File "/Users/ept/Desktop/qgt/qiskit/qpy/binary_io/circuits.py", line 864, in read_circuit
    _read_instruction(file_obj, circ, out_registers, custom_operations, version, vectors)
  File "/Users/ept/Desktop/qgt/qiskit/qpy/binary_io/circuits.py", line 258, in _read_instruction
    gate = gate_class(*params)
TypeError: __init__() missing 1 required positional argument: 'num_ctrl_qubits'
```

### What should happen?

It should not have failed.

### Any suggestions?

I would modify [the following line](https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qpy/binary_io/circuits.py#L255) of `qpy.binary_io.circuits.py` to add "MCXGrayCode". There seem to be other gates that have been already accounted for this same issue, and adding "MCXGrayCode" to the list fixes it:

```
        if gate_name in {"MCPhaseGate", "MCU1Gate", "MCXGrayCode"}:
            gate = gate_class(*params, instruction.num_ctrl_qubits)
```

I'm happy to open a bugfix PR, but because I'm not that familiar with qpy, I wanted to document the problem in this issue first.


Discussion:

Resolving patch:
diff --git a/qiskit/qpy/binary_io/circuits.py b/qiskit/qpy/binary_io/circuits.py
--- a/qiskit/qpy/binary_io/circuits.py
+++ b/qiskit/qpy/binary_io/circuits.py
@@ -252,7 +252,14 @@ def _read_instruction(file_obj, circuit, registers, custom_operations, version,
     if gate_name in {"IfElseOp", "WhileLoopOp"}:
         gate = gate_class(condition_tuple, *params)
     elif version >= 5 and issubclass(gate_class, ControlledGate):
-        if gate_name in {"MCPhaseGate", "MCU1Gate"}:
+        if gate_name in {
+            "MCPhaseGate",
+            "MCU1Gate",
+            "MCXGrayCode",
+            "MCXGate",
+            "MCXRecursive",
+            "MCXVChain",
+        }:
             gate = gate_class(*params, instruction.num_ctrl_qubits)
         else:
             gate = gate_class(*params)


Test patch:
diff --git a/test/python/circuit/test_circuit_load_from_qpy.py b/test/python/circuit/test_circuit_load_from_qpy.py
--- a/test/python/circuit/test_circuit_load_from_qpy.py
+++ b/test/python/circuit/test_circuit_load_from_qpy.py
@@ -24,7 +24,18 @@
 from qiskit.circuit.quantumregister import Qubit
 from qiskit.circuit.random import random_circuit
 from qiskit.circuit.gate import Gate
-from qiskit.circuit.library import XGate, QFT, QAOAAnsatz, PauliEvolutionGate, DCXGate, MCU1Gate
+from qiskit.circuit.library import (
+    XGate,
+    QFT,
+    QAOAAnsatz,
+    PauliEvolutionGate,
+    DCXGate,
+    MCU1Gate,
+    MCXGate,
+    MCXGrayCode,
+    MCXRecursive,
+    MCXVChain,
+)
 from qiskit.circuit.instruction import Instruction
 from qiskit.circuit.parameter import Parameter
 from qiskit.circuit.parametervector import ParameterVector
@@ -1043,9 +1054,17 @@ def test_open_controlled_gate(self):
 
     def test_standard_control_gates(self):
         """Test standard library controlled gates."""
-        qc = QuantumCircuit(3)
+        qc = QuantumCircuit(6)
         mcu1_gate = MCU1Gate(np.pi, 2)
+        mcx_gate = MCXGate(5)
+        mcx_gray_gate = MCXGrayCode(5)
+        mcx_recursive_gate = MCXRecursive(4)
+        mcx_vchain_gate = MCXVChain(3)
         qc.append(mcu1_gate, [0, 2, 1])
+        qc.append(mcx_gate, list(range(0, 6)))
+        qc.append(mcx_gray_gate, list(range(0, 6)))
+        qc.append(mcx_recursive_gate, list(range(0, 5)))
+        qc.append(mcx_vchain_gate, list(range(0, 5)))
         qc.mcp(np.pi, [0, 2], 1)
         qc.mct([0, 2], 1)
         qc.mcx([0, 2], 1)