import sys
from io import BytesIO
from qiskit import pulse, circuit, qpy

my_pulse = pulse.Gaussian(
    circuit.Parameter("duration"),
    circuit.Parameter("amp"), 
    circuit.Parameter("sigma"),
)

with pulse.build(name="my_gate") as my_gate:
    pulse.shift_phase(1.57, pulse.DriveChannel(0))
    pulse.play(my_pulse, pulse.DriveChannel(0))

file_like = BytesIO()

qpy.dump(my_gate, file_like)
file_like.seek(0)
load_gate = qpy.load(file_like)[0]

assert my_gate == load_gate

print(sys.getsizeof(file_like.getvalue()))

my_gate_op = circuit.Gate("my_gate", 1, my_gate.parameters)

my_circ = circuit.QuantumCircuit(1)
my_circ.append(my_gate_op, [0])
my_circ.measure_active()
my_circ.add_calibration(my_gate_op, (0,), my_gate)

file_like = BytesIO()

qpy.dump(my_circ, file_like)
file_like.seek(0)
load_circ = qpy.load(file_like)[0]

assert my_circ == load_circ

print(sys.getsizeof(file_like.getvalue()))

from qiskit.pulse.schedule import ScheduleBlock
from qiskit.pulse.transforms import AlignLeft
from qiskit.pulse.instructions import ShiftPhase, Play
from qiskit.pulse.channels import DriveChannel

context = AlignLeft()
channel = DriveChannel(0)

inst1 = ShiftPhase(1.57, channel)
inst2 = Play(my_pulse, channel)

sched_obj = ScheduleBlock(alignment_context=context)
sched_obj.append(inst1)
sched_obj.append(inst2)

import numpy as np

from qiskit.pulse.library.samplers.decorators import functional_pulse

@functional_pulse
def my_pulse(duration, amp, sigma):
    center = duration / 2
    return amp * np.exp(-((np.arange(duration)-center) / sigma) ** 2 / 2)

my_pulse(16, 0.1, 4)

from qiskit.pulse.library.parametric_pulses import Gaussian as ParametricGaussian

my_pulse_parametric = ParametricGaussian(16, 0.1, 4)
my_pulse_parametric

my_pulse_parametric_unassigned = ParametricGaussian(circuit.Parameter("duration"), 0.1, 4)
my_pulse_parametric_unassigned

from qiskit.pulse.library.discrete import gaussian

gaussian(16, 0.1, 4) == my_pulse_parametric.get_waveform()

from qiskit.pulse.library.symbolic_pulses import Gaussian as SymbolicGaussian

my_pulse_symbolic = SymbolicGaussian(16, 0.1, 4)
my_pulse_symbolic

my_pulse_parametric.get_waveform() == my_pulse_symbolic.get_waveform()

my_pulse_symbolic.envelope

my_pulse_symbolic._envelope_lam

from qiskit.pulse.library.symbolic_pulses import SymbolicPulse
from sympy import symbols, tanh

t, duration, sigma, amp = symbols("t duration sigma amp")
expr = amp * (tanh(t/sigma) + tanh((duration-t)/sigma) - 1)
constraints = duration > sigma

expr, constraints

my_tan_pulse = SymbolicPulse(
    pulse_type="Tangential", 
    duration=160, 
    parameters={"amp": 0.1, "sigma": 40},
    envelope=expr,
    constraints=constraints,
    valid_amp_conditions=amp < 1,
    name="my_tan_pulse",
)
my_tan_pulse.draw()

%%timeit
SymbolicGaussian(160, 0.1, 40).get_waveform()

%%timeit
ParametricGaussian(160, 0.1, 40).get_waveform()

