import%20marimo%0A%0A__generated_with%20%3D%20%220.25.1%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0Awith%20app.setup(hide_code%3DTrue)%3A%0A%20%20%20%20import%20json%0A%20%20%20%20import%20os%0A%20%20%20%20import%20shutil%0A%20%20%20%20import%20signal%0A%20%20%20%20import%20time%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20from%20qibocal%20import%20Executor%20as%20QibocalExecutor%0A%20%20%20%20from%20qibocal%20import%20create_calibration_platform%2C%20protocols%0A%0A%20%20%20%20from%20qibocal_widgets%20import%20(%0A%20%20%20%20%20%20%20%20Executor%2C%0A%20%20%20%20%20%20%20%20Middleware%2C%0A%20%20%20%20%20%20%20%20PlatformState%2C%0A%20%20%20%20%20%20%20%20data_frames%2C%0A%20%20%20%20%20%20%20%20reports%2C%0A%20%20%20%20%20%20%20%20reports_dir%2C%0A%20%20%20%20)%0A%20%20%20%20from%20qibocal_widgets.marimo%20import%20Marimo%2C%20display%2C%20show_data%2C%20show_reports%2C%20wrap%0A%0A%20%20%20%20HERE%20%3D%20Path(__file__).resolve().parent%0A%20%20%20%20os.environ%5B%22QIBOLAB_PLATFORMS%22%5D%20%3D%20str(HERE.parent%20%2F%20%22platforms%22)%0A%0A%20%20%20%20def%20qutrits()%3A%0A%20%20%20%20%20%20%20%20%22%22%22A%20fresh%20simulated%20platform%3A%20two%20coupled%20qutrits.%0A%0A%20%20%20%20%20%20%20%20qibolab%20replaces%20the%20termination%20handlers%2C%20which%20marimo%20needs%20to%20stop%0A%20%20%20%20%20%20%20%20its%20kernel%3A%20they%20are%20restored%20right%20after%20creating%20the%20platform.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20handlers%20%3D%20%7Bs%3A%20signal.getsignal(s)%20for%20s%20in%20(signal.SIGINT%2C%20signal.SIGTERM)%7D%0A%20%20%20%20%20%20%20%20platform%20%3D%20create_calibration_platform(%22qutrits%22)%0A%20%20%20%20%20%20%20%20for%20number%2C%20handler%20in%20handlers.items()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20signal.signal(number%2C%20handler)%0A%20%20%20%20%20%20%20%20return%20platform%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%20qibocal-widgets%20in%20Marimo%0A%0A%20%20%20%20A%20tour%20of%20the%20features%20of%20%60qibocal-widgets%60%2C%20on%20a%20simulated%20platform%3A%20the%0A%20%20%20%20%60qutrits%60%20platform%20of%20%5Bqibolab-simulator%5D(https%3A%2F%2Fgithub.com%2Fqiboteam%2Fqibolab-simulator)%2C%0A%20%20%20%20copied%20in%20the%20%60platforms%2F%60%20folder%20of%20the%20examples.%0A%0A%20%20%20%20The%20executor%20is%20a%20drop-in%20replacement%20of%20Qibocal's%2C%20composed%20of%0A%20%20%20%20**frontends**%20(displaying%20every%20output)%2C%20a%20**runner**%20(where%20the%20steps%20run)%2C%0A%20%20%20%20and%20**middleware**%20(wrapping%20every%20step).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%201.%20The%20executor%20and%20its%20session%0A%0A%20%20%20%20Create%20the%20executor%20once%2C%20at%20the%20beginning%20of%20the%20notebook.%20Every%20execution%0A%20%20%20%20is%20recorded%20in%20its%20*session*%20folder%2C%20in%20Qibocal's%20output%20layout.%20Within%20a%0A%20%20%20%20session%20started%20by%20the%20Qibocal%20application%20(or%20%60qibocal%20notebook%60)%2C%20the%0A%20%20%20%20folder%20defaults%20to%20a%20fresh%20subfolder%20of%20the%20session's%20reports%20folder%0A%20%20%20%20(%60QIBOCAMP_REPORTS_DIR%60)%2C%20so%20that%20calibrations%20show%20up%20in%20its%20dashboard%3B%0A%20%20%20%20otherwise%2C%20it%20is%20given%20explicitly.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20if%20reports_dir()%20is%20None%3A%0A%20%20%20%20%20%20%20%20path%20%3D%20HERE%20%2F%20%22var%22%20%2F%20%22session%22%0A%20%20%20%20%20%20%20%20if%20path.exists()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20shutil.rmtree(path)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20path%20%3D%20None%20%20%23%20a%20fresh%20folder%20under%20reports_dir()%0A%0A%20%20%20%20executor%20%3D%20Executor.create(%0A%20%20%20%20%20%20%20%20path%3Dpath%2C%0A%20%20%20%20%20%20%20%20platform%3Dqutrits()%2C%0A%20%20%20%20%20%20%20%20targets%3D%5B0%2C%201%5D%2C%0A%20%20%20%20%20%20%20%20update%3DFalse%2C%0A%20%20%20%20%20%20%20%20frontends%3D%5BMarimo()%5D%2C%0A%20%20%20%20)%0A%20%20%20%20executor.path%0A%20%20%20%20return%20(executor%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%202.%20Implicit%20display%2C%20step%20by%20step%0A%0A%20%20%20%20Every%20step%20returns%20an%20execution%20which%20displays%20itself%3A%20raw%20data%20after%20the%0A%20%20%20%20acquisition%2C%20then%20reports%20(selected%20by%20default)%2C%20with%20the%20fit%20table%20folded%0A%20%20%20%20above%20the%20plots.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(executor)%3A%0A%20%20%20%20bound%20%3D%20protocols.ramsey(delay%3D(10%2C%201000%2C%20100))%0A%20%20%20%20with%20executor%3A%0A%20%20%20%20%20%20%20%20acquired%20%3D%20executor.acquire(bound%2C%20nshots%3D500)%0A%20%20%20%20acquired%0A%20%20%20%20return%20(acquired%2C)%0A%0A%0A%40app.cell%0Adef%20_(acquired%2C%20executor)%3A%0A%20%20%20%20fitted%20%3D%20executor.fit(acquired)%0A%20%20%20%20ramsey%20%3D%20executor.report(fitted)%0A%20%20%20%20ramsey%0A%20%20%20%20return%20(ramsey%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20The%20execution%20is%20recorded%20in%20the%20session%2C%20where%20notes%20can%20be%20attached%20to%20it%0A%20%20%20%20(and%20to%20the%20session%20itself)%3A%20they%20are%20shown%2C%20and%20can%20be%20added%2C%20in%20the%0A%20%20%20%20report%20dashboard%20too.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(executor%2C%20ramsey)%3A%0A%20%20%20%20executor.note(%22Two%20coupled%20qutrits%2C%20simulated%22)%0A%20%20%20%20executor.note(%22Fringes%20as%20expected%22%2C%20ramsey)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22task%20folder%22%3A%20ramsey.path.relative_to(executor.path)%2C%0A%20%20%20%20%20%20%20%20%22notes%22%3A%20%5Bnote.content%20for%20note%20in%20executor.session.notes(ramsey)%5D%2C%0A%20%20%20%20%7D%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%203.%20Updating%20the%20platform%0A%0A%20%20%20%20A%20full%20execution%20(%60executor(bound)%60)%20acquires%2C%20fits%2C%20and%20reports.%20The%0A%20%20%20%20executor%20is%20created%20with%20%60update%3DFalse%60%3A%20the%20platform%20is%20updated%20once%20the%0A%20%20%20%20fit%20is%20validated%2C%20with%20the%20*Update*%20buttons%20above%20the%20reports%20(all%20targets%2C%0A%20%20%20%20or%20per%20target%2C%20inside%20each%20report)%2C%20or%20from%20code%20with%20%60rabi.update()%60.%0A%20%20%20%20(With%20%60update%3DTrue%60%2C%20it%20is%20updated%20right%20away%2C%20and%20the%20buttons%20show%20it.)%0A%20%20%20%20A%20snapshot%20of%20the%20platform%20state%20taken%20before%20shows%20what%20changed.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(executor%2C%20ramsey)%3A%0A%20%20%20%20%23%20after%20the%20previous%20section%2C%20to%20keep%20the%20session%20order%0A%20%20%20%20assert%20ramsey%20is%20not%20None%0A%20%20%20%20start%20%3D%20executor.platform_state.snapshot()%0A%20%20%20%20with%20executor%3A%0A%20%20%20%20%20%20%20%20rabi%20%3D%20executor(%0A%20%20%20%20%20%20%20%20%20%20%20%20protocols.rabi_amplitude_signal(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20min_amp%3D0.0%2C%20max_amp%3D0.6%2C%20step_amp%3D0.03%2C%20pulse_length%3D40%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20nshots%3D500%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20rabi%0A%20%20%20%20return%20rabi%2C%20start%0A%0A%0A%40app.cell%0Adef%20_(executor%2C%20rabi%2C%20start)%3A%0A%20%20%20%20rabi.update(%5B0%5D)%20%20%23%20the%20fit%20of%20target%200%20looks%20right%3A%20approve%20it%20alone%0A%20%20%20%20executor.platform_state.diff(start)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20Every%20change%20of%20the%20platform%20state%20is%20recorded%20in%20the%20history%20of%20the%0A%20%20%20%20session%3A%20compare%20any%20two%20entries%20(A%20and%20B)%2C%20and%20restore%20one%2C%20entirely%20or%0A%20%20%20%20for%20the%20selected%20paths.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(executor%2C%20rabi)%3A%0A%20%20%20%20assert%20rabi%20is%20not%20None%0A%20%20%20%20executor.history.explore()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%204.%20Exploring%20and%20editing%20the%20platform%20state%0A%0A%20%20%20%20The%20explorer%20shows%20parameters%20and%20calibration%20by%20path%2C%20highlighting%20the%0A%20%20%20%20differences%20with%20the%20snapshot.%20Its%20navigation%20bar%20accepts%20paths%2C%20or%20pasted%0A%20%20%20%20code%3B%20buttons%20copy%20paths%20and%20values%3B%20with%20%60editable%3DTrue%60%2C%20edits%20go%20through%0A%20%20%20%20the%20same%20API%2C%20and%20show%20the%20equivalent%20code.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(executor%2C%20rabi%2C%20start)%3A%0A%20%20%20%20assert%20rabi%20is%20not%20None%0A%20%20%20%20executor.platform_state.explore(%0A%20%20%20%20%20%20%20%20%22native_gates.single_qubit.0%22%2C%20editable%3DTrue%2C%20compare%3Dstart%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20The%20same%20paths%20work%20from%20code%2C%20in%20any%20of%20the%20forms%20the%20explorer%20accepts%3A%0A%20%20%20%20full%20paths%2C%20paths%20within%20a%20document%20(as%20copied%20from%20the%20dashboard)%2C%20or%0A%20%20%20%20pasted%20code.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(executor%2C%20rabi)%3A%0A%20%20%20%20assert%20rabi%20is%20not%20None%0A%20%20%20%20state%20%3D%20executor.platform_state%0A%20%20%20%20frequency%20%3D%20%22parameters.configs.0%2Fdrive.frequency%22%0A%20%20%20%20before%20%3D%20state%5Bfrequency%5D%0A%20%20%20%20state.update(%7B%22configs.0%2Fdrive.frequency%22%3A%20before%20%2B%201e6%7D)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22before%22%3A%20before%2C%0A%20%20%20%20%20%20%20%20%22after%22%3A%20state%5Bfrequency%5D%2C%0A%20%20%20%20%20%20%20%20%22resolved%22%3A%20state.resolve(f'executor.platform_state%5B%22%7Bfrequency%7D%22%5D')%2C%0A%20%20%20%20%20%20%20%20%22qubit%20frequencies%22%3A%20state.find(%22frequency_01%22)%2C%0A%20%20%20%20%20%20%20%20%22session%20start%22%3A%20PlatformState.load(executor.path%20%2F%20%22platform%22)%5Bfrequency%5D%2C%0A%20%20%20%20%7D%0A%20%20%20%20return%20(state%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%205.%20Explicit%20helpers%0A%0A%20%20%20%20For%20custom%20layouts%2C%20the%20views%20are%20available%20explicitly%2C%20as%20well%20as%20the%0A%20%20%20%20frontend-agnostic%20content%20(tables%20and%20normalized%20reports).%20Executions%20from%20a%0A%20%20%20%20plain%20Qibocal%20executor%20are%20made%20displayable%20with%20%60wrap%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ramsey)%3A%0A%20%20%20%20mo.ui.tabs(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22show_data%22%3A%20show_data(ramsey)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22show_reports%22%3A%20show_reports(ramsey)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22display%22%3A%20display(ramsey)%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ramsey)%3A%0A%20%20%20%20frames%20%3D%20data_frames(ramsey.data)%0A%20%20%20%20normalized%20%3D%20reports(ramsey)%0A%20%20%20%20mo.vstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22%60data_frames%60%3A%20%7Blen(frames)%7D%20tables%2C%20columns%20%7Blist(frames%5B0%5D.columns)%7D%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22%60reports%60%3A%20%7Blen(normalized%5B0%5D.figures)%7D%20figure(s)%20per%20target%2C%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22fit%20table%20of%20%7Blen(normalized%5B0%5D.table)%7D%20characters%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20_platform%20%3D%20qutrits()%0A%20%20%20%20_plain%20%3D%20QibocalExecutor(_platform%2C%20targets%3D%5B0%5D%2C%20update%3DFalse)%0A%20%20%20%20_platform.connect()%0A%20%20%20%20_completed%20%3D%20_plain(protocols.ramsey(delay%3D(10%2C%201000%2C%20100))%2C%20nshots%3D200)%0A%20%20%20%20_platform.disconnect()%0A%20%20%20%20wrap(_completed)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%206.%20Middleware%0A%0A%20%20%20%20Middleware%20wrap%20every%20step%2C%20like%20in%20web%20servers.%20A%20timer%2C%20around%20the%0A%20%20%20%20acquisition%2C%20on%20a%20second%20executor%20appending%20to%20the%20same%20session%20folder%0A%20%20%20%20(%60Executor.attach%60%2C%20e.g.%20after%20restarting%20the%20kernel)%3A%20it%20restores%20the%0A%20%20%20%20latest%20recorded%20platform%20state%2C%20so%20the%20calibration%20continues%20from%20there.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(executor%2C%20state)%3A%0A%20%20%20%20assert%20state%20is%20not%20None%0A%0A%20%20%20%20class%20Timer(Middleware)%3A%0A%20%20%20%20%20%20%20%20def%20__init__(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.times%20%3D%20%5B%5D%0A%0A%20%20%20%20%20%20%20%20def%20acquire(self%2C%20executor%2C%20call_next%2C%20*args%2C%20**kwargs)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20start%20%3D%20time.perf_counter()%0A%20%20%20%20%20%20%20%20%20%20%20%20completed%20%3D%20call_next(*args%2C%20**kwargs)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.times.append(time.perf_counter()%20-%20start)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20completed%0A%0A%20%20%20%20timer%20%3D%20Timer()%0A%20%20%20%20attached%20%3D%20Executor.attach(%0A%20%20%20%20%20%20%20%20executor.path%2C%0A%20%20%20%20%20%20%20%20platform%3Dqutrits()%2C%0A%20%20%20%20%20%20%20%20targets%3D%5B0%2C%201%5D%2C%0A%20%20%20%20%20%20%20%20update%3DFalse%2C%0A%20%20%20%20%20%20%20%20middleware%3D%5Btimer%5D%2C%0A%20%20%20%20%20%20%20%20frontends%3D%5BMarimo()%5D%2C%0A%20%20%20%20)%0A%20%20%20%20with%20attached%3A%0A%20%20%20%20%20%20%20%20attached(protocols.ramsey(delay%3D(10%2C%201000%2C%20100))%2C%20nshots%3D500)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22acquisition%20time%22%3A%20f%22%7Btimer.times%5B0%5D%3A.1f%7D%20s%22%2C%0A%20%20%20%20%20%20%20%20%22restored%20frequency%22%3A%20attached.platform_state%5B%22configs.0%2Fdrive.frequency%22%5D%2C%0A%20%20%20%20%20%20%20%20%22history%22%3A%20json.loads((attached.path%20%2F%20%22history.json%22).read_text())%2C%0A%20%20%20%20%7D%0A%20%20%20%20return%20(attached%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%207.%20Sessions%20on%20disk%0A%0A%20%20%20%20Recorded%20executions%20can%20be%20loaded%20back%2C%20displayed%2C%20and%20the%20executor%20can%0A%20%20%20%20move%20on%20to%20a%20new%20session%20folder%2C%20for%20instance%20for%20a%20new%20cooldown.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(attached)%3A%0A%20%20%20%20history%20%3D%20json.loads((attached.path%20%2F%20%22history.json%22).read_text())%0A%20%20%20%20loaded%20%3D%20attached.load(attached.path%20%2F%20%22data%22%20%2F%20history%5B0%5D)%0A%20%20%20%20loaded%0A%20%20%20%20return%20(loaded%2C)%0A%0A%0A%40app.cell%0Adef%20_(attached%2C%20loaded)%3A%0A%20%20%20%20assert%20loaded%20is%20not%20None%0A%20%20%20%20_first%20%3D%20attached.path%0A%20%20%20%20attached.new_session(_first.parent%20%2F%20%22next%22)%0A%20%20%20%20%7B%22previous%20session%22%3A%20_first.name%2C%20%22new%20session%22%3A%20attached.path.name%7D%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Next%3A%20remote%20execution%0A%0A%20%20%20%20To%20run%20the%20same%20protocols%20on%20a%20machine%20with%20access%20to%20the%20instruments%2C%0A%20%20%20%20from%20a%20laptop%20or%20an%20access%20node%2C%20see%20the%20%60remote%60%20notebook%20next%20to%20this%0A%20%20%20%20one.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
ef597270a175e7d27ea2efa47c564c0f