Repository: Qiskit/qiskit

Issue:
Propagate limit_amplitude keyword argument to parametric pulses
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues to confirm this idea does not exist. -->

### What is the expected enhancement?
As described [here](https://github.com/Qiskit/qiskit-terra/pull/6345#pullrequestreview-666847848) the `limit_amplitude` keyword argument should be propagated to the constructor of existing parametric pulses. 

For example,

```python
from qiskit.pulse import Gaussian
amp = 10.0
Gaussian(100, amp, 1.0, limit_amplitude=False)
```




Discussion:
`class Pulse` defaults `limit_amplitude` property to `True`.

Should that `True` value be propagated as the default to `class ParametricPulse` and its specializations, or should it be as in this Issue's header, a default of `False`?
The default value should be `True`. The example in the issue was intended to demonstrate how to disable amplitude checking. 
Hi @taalexander, @jwoehr. May I work on this?
It's open source, go ahead, @dhruvbhq 

Resolving patch:
diff --git a/qiskit/pulse/library/parametric_pulses.py b/qiskit/pulse/library/parametric_pulses.py
--- a/qiskit/pulse/library/parametric_pulses.py
+++ b/qiskit/pulse/library/parametric_pulses.py
@@ -55,14 +55,22 @@ class ParametricPulse(Pulse):
     """The abstract superclass for parametric pulses."""
 
     @abstractmethod
-    def __init__(self, duration: Union[int, ParameterExpression], name: Optional[str] = None):
+    def __init__(
+        self,
+        duration: Union[int, ParameterExpression],
+        name: Optional[str] = None,
+        limit_amplitude: Optional[bool] = None,
+    ):
         """Create a parametric pulse and validate the input parameters.
 
         Args:
             duration: Pulse length in terms of the the sampling period `dt`.
             name: Display name for this pulse envelope.
+            limit_amplitude: If ``True``, then limit the amplitude of the
+                             waveform to 1. The default is ``True`` and the
+                             amplitude is constrained to 1.
         """
-        super().__init__(duration=duration, name=name)
+        super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)
         self.validate_parameters()
 
     @abstractmethod
@@ -141,6 +149,7 @@ def __init__(
         amp: Union[complex, ParameterExpression],
         sigma: Union[float, ParameterExpression],
         name: Optional[str] = None,
+        limit_amplitude: Optional[bool] = None,
     ):
         """Initialize the gaussian pulse.
 
@@ -150,12 +159,15 @@ def __init__(
             sigma: A measure of how wide or narrow the Gaussian peak is; described mathematically
                    in the class docstring.
             name: Display name for this pulse envelope.
+            limit_amplitude: If ``True``, then limit the amplitude of the
+                             waveform to 1. The default is ``True`` and the
+                             amplitude is constrained to 1.
         """
         if not _is_parameterized(amp):
             amp = complex(amp)
         self._amp = amp
         self._sigma = sigma
-        super().__init__(duration=duration, name=name)
+        super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)
 
     @property
     def amp(self) -> Union[complex, ParameterExpression]:
@@ -234,6 +246,7 @@ def __init__(
         width: Union[float, ParameterExpression] = None,
         risefall_sigma_ratio: Union[float, ParameterExpression] = None,
         name: Optional[str] = None,
+        limit_amplitude: Optional[bool] = None,
     ):
         """Initialize the gaussian square pulse.
 
@@ -245,6 +258,9 @@ def __init__(
             width: The duration of the embedded square pulse.
             risefall_sigma_ratio: The ratio of each risefall duration to sigma.
             name: Display name for this pulse envelope.
+            limit_amplitude: If ``True``, then limit the amplitude of the
+                             waveform to 1. The default is ``True`` and the
+                             amplitude is constrained to 1.
         """
         if not _is_parameterized(amp):
             amp = complex(amp)
@@ -252,7 +268,7 @@ def __init__(
         self._sigma = sigma
         self._risefall_sigma_ratio = risefall_sigma_ratio
         self._width = width
-        super().__init__(duration=duration, name=name)
+        super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)
 
     @property
     def amp(self) -> Union[complex, ParameterExpression]:
@@ -381,6 +397,7 @@ def __init__(
         sigma: Union[float, ParameterExpression],
         beta: Union[float, ParameterExpression],
         name: Optional[str] = None,
+        limit_amplitude: Optional[bool] = None,
     ):
         """Initialize the drag pulse.
 
@@ -391,13 +408,16 @@ def __init__(
                    in the class docstring.
             beta: The correction amplitude.
             name: Display name for this pulse envelope.
+            limit_amplitude: If ``True``, then limit the amplitude of the
+                             waveform to 1. The default is ``True`` and the
+                             amplitude is constrained to 1.
         """
         if not _is_parameterized(amp):
             amp = complex(amp)
         self._amp = amp
         self._sigma = sigma
         self._beta = beta
-        super().__init__(duration=duration, name=name)
+        super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)
 
     @property
     def amp(self) -> Union[complex, ParameterExpression]:
@@ -434,9 +454,10 @@ def validate_parameters(self) -> None:
             not _is_parameterized(self.beta)
             and not _is_parameterized(self.sigma)
             and self.beta > self.sigma
+            and self.limit_amplitude
         ):
             # If beta <= sigma, then the maximum amplitude is at duration / 2, which is
-            # already constrainted by self.amp <= 1
+            # already constrained by self.amp <= 1
 
             # 1. Find the first maxima associated with the beta * d/dx gaussian term
             #    This eq is derived from solving for the roots of the norm of the drag function.
@@ -489,6 +510,7 @@ def __init__(
         duration: Union[int, ParameterExpression],
         amp: Union[complex, ParameterExpression],
         name: Optional[str] = None,
+        limit_amplitude: Optional[bool] = None,
     ):
         """
         Initialize the constant-valued pulse.
@@ -497,11 +519,14 @@ def __init__(
             duration: Pulse length in terms of the the sampling period `dt`.
             amp: The amplitude of the constant square pulse.
             name: Display name for this pulse envelope.
+            limit_amplitude: If ``True``, then limit the amplitude of the
+                             waveform to 1. The default is ``True`` and the
+                             amplitude is constrained to 1.
         """
         if not _is_parameterized(amp):
             amp = complex(amp)
         self._amp = amp
-        super().__init__(duration=duration, name=name)
+        super().__init__(duration=duration, name=name, limit_amplitude=limit_amplitude)
 
     @property
     def amp(self) -> Union[complex, ParameterExpression]:


Test patch:
diff --git a/test/python/pulse/test_parameters.py b/test/python/pulse/test_parameters.py
--- a/test/python/pulse/test_parameters.py
+++ b/test/python/pulse/test_parameters.py
@@ -274,6 +274,40 @@ def test_parametric_pulses_parameter_assignment(self):
         self.assertEqual(waveform.amp, self.amp)
         self.assertEqual(waveform.sigma, 12.7)
 
+    def test_parametric_pulses_limit_amplitude(self):
+        """Test that the check for amplitude less than or equal to 1 can be disabled."""
+        waveform = pulse.library.Gaussian(
+            duration=100, sigma=1.0, amp=1.1 + 0.8j, limit_amplitude=False
+        )
+        self.assertGreater(np.abs(waveform.amp), 1.0)
+        with self.assertRaises(PulseError):
+            waveform = pulse.library.Gaussian(
+                duration=100, sigma=1.0, amp=1.1 + 0.8j, limit_amplitude=True
+            )
+
+        waveform = pulse.library.GaussianSquare(
+            duration=100, sigma=1.0, amp=1.1 + 0.8j, width=10, limit_amplitude=False
+        )
+        self.assertGreater(np.abs(waveform.amp), 1.0)
+        with self.assertRaises(PulseError):
+            waveform = pulse.library.GaussianSquare(
+                duration=100, sigma=1.0, amp=1.1 + 0.8j, width=10, limit_amplitude=True
+            )
+
+        waveform = pulse.library.Drag(
+            duration=100, sigma=1.0, beta=1.0, amp=1.1 + 0.8j, limit_amplitude=False
+        )
+        self.assertGreater(np.abs(waveform.amp), 1.0)
+        with self.assertRaises(PulseError):
+            waveform = pulse.library.Drag(
+                duration=100, sigma=1.0, beta=1.0, amp=1.1 + 0.8j, limit_amplitude=True
+            )
+
+        waveform = pulse.library.Constant(duration=100, amp=1.1 + 0.8j, limit_amplitude=False)
+        self.assertGreater(np.abs(waveform.amp), 1.0)
+        with self.assertRaises(PulseError):
+            waveform = pulse.library.Constant(duration=100, amp=1.1 + 0.8j, limit_amplitude=True)
+
     @unittest.skip("Not yet supported by ParameterExpression")
     def test_complex_value_assignment(self):
         """Test that complex values can be assigned to Parameters."""