Repository: Qiskit/qiskit

Issue:
Framechange instruction being converted to string with `as_dict`
<!-- ⚠️ 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**:
- **Python version**:
- **Operating system**:

### What is the current behavior?
Currently, frame change instructions are being converted to a string with as_dict.

### Steps to reproduce the problem
Assemble a pulse qobj with a framechange instruction.
call `qobj.as_dict()` and examine the `phase` parameter of the framechange instruction.


### What is the expected behavior?
Phase parameter should be a float.


### Suggested solutions





Discussion:

Resolving patch:
diff --git a/qiskit/qobj/models/pulse.py b/qiskit/qobj/models/pulse.py
--- a/qiskit/qobj/models/pulse.py
+++ b/qiskit/qobj/models/pulse.py
@@ -53,7 +53,7 @@ class PulseQobjInstructionSchema(QobjInstructionSchema):
     ch = String(validate=Regexp('[dum]([0-9])+'))
     conditional = Integer(validate=Range(min=0))
     val = ByType([Complex(), String()])
-    phase = ByType([String(), Number()])
+    phase = ByType([Number(), String()])
     duration = Integer(validate=Range(min=1))
     qubits = List(Integer(validate=Range(min=0)), validate=Length(min=1))
     memory_slot = List(Integer(validate=Range(min=0)), validate=Length(min=1))


Test patch:
diff --git a/test/python/qobj/test_qobj.py b/test/python/qobj/test_qobj.py
--- a/test/python/qobj/test_qobj.py
+++ b/test/python/qobj/test_qobj.py
@@ -158,7 +158,9 @@ def setUp(self):
                 PulseQobjExperiment(instructions=[
                     PulseQobjInstruction(name='pulse0', t0=0, ch='d0'),
                     PulseQobjInstruction(name='fc', t0=5, ch='d0', phase=1.57),
+                    PulseQobjInstruction(name='fc', t0=5, ch='d0', phase='P1'),
                     PulseQobjInstruction(name='pv', t0=10, ch='d0', val=0.1 + 0.0j),
+                    PulseQobjInstruction(name='pv', t0=10, ch='d0', val='P1'),
                     PulseQobjInstruction(name='acquire', t0=15, duration=5,
                                          qubits=[0], memory_slot=[0],
                                          kernels=[
@@ -190,7 +192,9 @@ def setUp(self):
                 {'instructions': [
                     {'name': 'pulse0', 't0': 0, 'ch': 'd0'},
                     {'name': 'fc', 't0': 5, 'ch': 'd0', 'phase': 1.57},
+                    {'name': 'fc', 't0': 5, 'ch': 'd0', 'phase': 'P1'},
                     {'name': 'pv', 't0': 10, 'ch': 'd0', 'val': [0.1, 0.0]},
+                    {'name': 'pv', 't0': 10, 'ch': 'd0', 'val': 'P1'},
                     {'name': 'acquire', 't0': 15, 'duration': 5,
                      'qubits': [0], 'memory_slot': [0],
                      'kernels': [{'name': 'boxcar',
@@ -210,7 +214,7 @@ def test_as_dict_against_schema(self):
             self.fail(str(validation_error))
 
     def test_from_dict_per_class(self):
-        """Test Qobj and its subclass representations given a dictionary."""
+        """Test converting to Qobj and its subclass representations given a dictionary."""
         test_parameters = {
             PulseQobj: (
                 self.valid_qobj,
@@ -252,6 +256,49 @@ def test_from_dict_per_class(self):
             with self.subTest(msg=str(qobj_class)):
                 self.assertEqual(qobj_item, qobj_class.from_dict(expected_dict))
 
+    def test_as_dict_per_class(self):
+        """Test converting from Qobj and its subclass representations given a dictionary."""
+        test_parameters = {
+            PulseQobj: (
+                self.valid_qobj,
+                self.valid_dict
+            ),
+            PulseQobjConfig: (
+                PulseQobjConfig(meas_level=1,
+                                memory_slot_size=8192,
+                                meas_return='avg',
+                                pulse_library=[
+                                    PulseLibraryItem(name='pulse0', samples=[0.1 + 0.0j])
+                                ],
+                                qubit_lo_freq=[4.9], meas_lo_freq=[6.9],
+                                rep_time=1000),
+                {'meas_level': 1,
+                 'memory_slot_size': 8192,
+                 'meas_return': 'avg',
+                 'pulse_library': [{'name': 'pulse0', 'samples': [[0.1, 0.0]]}],
+                 'qubit_lo_freq': [4.9],
+                 'meas_lo_freq': [6.9],
+                 'rep_time': 1000},
+            ),
+            PulseLibraryItem: (
+                PulseLibraryItem(name='pulse0', samples=[0.1 + 0.0j]),
+                {'name': 'pulse0', 'samples': [[0.1, 0.0]]}
+            ),
+            PulseQobjExperiment: (
+                PulseQobjExperiment(
+                    instructions=[PulseQobjInstruction(name='pulse0', t0=0, ch='d0')]),
+                {'instructions': [{'name': 'pulse0', 't0': 0, 'ch': 'd0'}]}
+            ),
+            PulseQobjInstruction: (
+                PulseQobjInstruction(name='pulse0', t0=0, ch='d0'),
+                {'name': 'pulse0', 't0': 0, 'ch': 'd0'}
+            )
+        }
+
+        for qobj_class, (qobj_item, expected_dict) in test_parameters.items():
+            with self.subTest(msg=str(qobj_class)):
+                self.assertEqual(qobj_item.as_dict(), expected_dict)
+
 
 def _nop():
     pass