From 9d5345c7125d62637af1d04375fd7b9f12bc6eac Mon Sep 17 00:00:00 2001 From: NazTM <103762441+NazTM@users.noreply.github.com> Date: Mon, 2 Jun 2025 21:25:52 +0600 Subject: [PATCH] Update QPIXL_demo.ipynb Added CircuitCombiner class for updated cFRQI_with_alg_demo function, with usage examples for demonstration --- QPIXL_demo.ipynb | 306 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 228 insertions(+), 78 deletions(-) diff --git a/QPIXL_demo.ipynb b/QPIXL_demo.ipynb index 2b79f10..d2f9a82 100644 --- a/QPIXL_demo.ipynb +++ b/QPIXL_demo.ipynb @@ -192,17 +192,14 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": { - "jupyter": { - "source_hidden": true - }, "tags": [] }, "outputs": [ { "data": { - "image/png": "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fuj13JXoBp+cLysbR47guCGHcKW80xhwyIaR6R999FFISGXaypUrA9PkXFyZJodunUO5QnoiZLrTYxP8ZiDn/zqkN0Z6euSL1f79+0N22pSUlFznEvfo0UO3bt06pMdI5iGBk/A75PCzzDc/hw8fDvSaFCRnSCWI8ncSAocETs5bljcrp3fDWYZzzz1XHzp0KFBWeo9kupw/XZgPR+nVkh6hnD744AMzD+fwudTjoosuMtPkIb02O3fuND1w8gYX/GYF98iXt/Mlp0xLT+3rr7+u58+fbz7ApfdYPly3b98eKCfLJfMMnhb8gRl8+vRbb71ltp+Uj4+P13/961/NdDldTY7WB1/jgNzInLczl9Nzzz1n/lauGwpG5iKL3Hk3d9J4lsuAevToETL9wIED5jumzOOLL76IidyV6FE609LSzE8ZJceNhQsXmp+jR48OmX733Xebnx988EHI9BYtWqguXboEfu/cubP5+atf/cqM3JNz+o8//pjrNW+77bbA/2UkLvldRpD88MMPQ8pdd911ZiRKx6FDh9RHH32krr/+enXs2DF14MAB8zh48KDq1auX2rx5s9q1a5cpW7FiRfXtt9+aaXkpXbq0SkxMVB9//LE6fPiwckvWV/Xq1dWQIUMC02QksTvuuMOMerl8+fKQ8oMGDTKjHzlkBKOc66VevXpmVE0ZIfBMZESspKSkXNNl5CTneWf7S11kHWzYsME8ZETOF154QaWnp6s//vGPZkQlGeFTpv/mN78J7DvIH/nydr5k2V977TV1ww03qGuuuUY98sgjavHixWYdTJw4MVDOyVl+WQweuU6WRdabjFgmP2Xbnzx5Ut13331mnuXKlTMj6soIeG3atFHz5893vb5iAZnzduZyklGjZR1dfvnlIdPJXGSRO+/mLi4uzoy6unTpUjV27FizbGvXrjXrwxnN3cmT13NXoht8MlyukJ3YjZ9//tls/EaNGoVMlx1RdnR5PlhwEEWFChXMz9q1a+c5PWcA5LVkYwdr0qSJ+ZlzONj69euH/L5lyxazM48bN86EN/ghQ8SKffv2mZ8PP/ywuX2BzLt169bqnnvuUV999VVgXrLzPv744+pf//qXqlatmurevbt64okn8hx6Pef6aty4sVmOYM2bNw88X9D6cgJr88aQ881FGmw5nT59OvC8Q+oob6pt27ZVCQkJ5g1t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m/kGk3JSXrz22mvm+ZyPZcuWFVj/+fPn65YtW+qkpCTzc968eXnWITs72yxPixYtTNmqVavqUaNG6UOHDuWqU9++ffXixYt127ZtTdnmzZvrd999N1DmTHV15vGf//xHn3/++WYe9evX16+//nqu+m/ZssU8Cqt///66UqVKZyyXlpZm6jh69Ogzln322WdN2a+++qrQ9YolZM77mdu/f795PVmneXHW9b59+/TRo0e13+/Ps5xsSyn3wgsvmN9PnTqlMzIyrOoCMkfmtHlNeeTUs2dP3bBhw5BpMp9bb71Vnzx50mQORYcsej+LwW677Tbt8/lMlgoiyyB1iDaeuobvH//4h/n529/+9qzm89prr6nnnnvOHJqX3rJKlSqZw/OdO3dWH330kRo5cqR65plnTMv+n//851nXW64ju+OOO8z/5fSMv//97+YhR7Dys2TJEnOKo5wnPGnSJFOX4cOH53ldm/Sq33PPPeZUKqm3lJOjXb169TKHqoNJr6FcAye9hTJf6Y2X0xTkcLbbum7ZssX09stpJLL+zjnnHHMo/Ntvvw15rR49ephHYe3du/eMRxSccqKoy4LMxVrmCiLXzVaoUMFc8yBHE6TXO9iHH35ofsr1SVIHOb1aHrLcJeE6kmhB5mI7c3L0R7ZTx44dcz0n1xlt3bpVHTt2LGT6jBkzzBkrkrcWLVqot956q8jqE8vIorezeOrUKXO0XT6f5Po92U5dunQJXBqUl/Xr16uNGzeqX//61yrqaA9p3769rlChguvy+fW2pKSkmN7qYN27d9fly5fXP//8c8j04N7swva2iHfeecdVD4ujXbt2ukaNGvrIkSOBaUuWLDHzCK6D9HrItJkzZ4b8/aJFi3JNl7+TacG9K9JjL68j69ZNXZ15rFixIjBN1qX0utx99925yua1vtyQ+UtPy7hx485YdsSIETo+Pl7/8MMPBZY7ePCg6Ynq1q1boeoUi8ic9zN3pqMNU6ZMMT2fslxz587Vd955p05ISNCNGzc2y+K44447zHzOPfdcfcUVV+jZs2ebnu1y5cqZoxInTpywqlesInOxnTnnuYcffjjXc1OnTjXPff/994FpXbt2NRldsGCBnjZtmm7VqlXIkXYUHln0dhYnTZoUclSxR48eevv27QX+jbymlP3uu+90tInz2khJ0rt8tqQXI/j8+f3796sVK1aY68bkAs5g0tsRaXv27DEXZst1adKj7pDeDem9C/bOO++YMvKc9FQ4D7muTa6JW7ZsWUh5GfDk2muvDfwuo3/Jxd7Sa+Ec/ToTqUO3bt0Cv8u6lNGOco4gJr0mhenZ37dvn+k9qV+/vrnWriDSkykXTstInQWNmCS9pnK+tYzmKT1tcIfMxUbmCnLnnXeazEgmZTvKRezSGyo9t3KtkcO5sF0Gpfjggw/MCINjxowxAxnIUQmOOrhD5mI7c3LUIb9rspyRcZ0y4tNPPzUZldE/ZaCktWvXmmv95GhJcDnYI4vezuKQIUPMkUb5bHKO2BWUGfke+fbbb5sBkQo6WlpcPNXgkx0l56kMhSENiWDOTiNvktFARgASeTVgZCcPJl+6ZCSvqlWrmhAEP+QLmDSegjVq1CjXG4pc8C3cBiXnG5SQQ+yHDx9WZ+vEiRPmniuynRcsWBAykEtO//nPf8xw73IagVw8XZDbb7/djPgpI4LK0Mpwh8x5P3OFIR+O0rBzTuMUzmkw0tALHi1OTt+R03hWrlxZLHUtachcbGfOyVF6enqu506fPh1SJi8yGIgMQCGdm9L4Q+GRRW9nsW7dumYgP2n4ySmpctmC/J5fo2/58uXmdilRN1iLF0fpbNasmekVkKG/a9euXej5FPRmWZD8el6ys7NVcZEeBwme7Kx5cTP6nq28hmMXOe9fYisjI8OMiCXntsuQ1QW9GX755ZemR1PKyMid8oUyPzLcrxyJkPsSne25+LGGzHk7c2dD9odDhw6F9OQ61/DlrLuM2FlcjdOShszFdubk+i45uidHXXJypjlZy4+z3wTnE/bIYmxlccCAAeaMFDn6KgcScpJlls5MaSBGI081+GTI1FmzZqk333xTjR07tsjmK6168c033xRYTnoUct7gO7h3pCA2h+mdWwlIT0pOco+QYA0bNjS97HLxrJs3Fbn4VUISXB/nHjLO/U+K45QCeRORw/xLly5Vc+bMMfcbyo+cHnbFFVeYNx25/15BRwGnTp1qbu1w1113mZukwg6Z827mzoYsj/TOBt/rS07pEdIDmrMjx+2tH0DmYj1z8oWydevWeQ6WsXr1arMdz3SaoXMEicydHbIYW1k89f9H9uQIZk5yxF3u5Sy3BTtTh0tx8dQpndL6ljdCOX1Pbqydkxx6l5tt25I3RRkp6NVXXzU318yvB0F2dNkR5AhUcI+b3HjzTJx7vuUV3pxq1Kih2rVrZ66TCd7x5FxjuUFlMDl9Snp75L4hed3vJefryU2Qg+sr56i/8cYb5vXkFC3buhZEGmbycENOuZw9e7Y5EidH+fIj53zLzS7lQ1GOAhb0gSbzk9Gf5PD7U089VahliHVkzruZc0uuN8nrJuwyXTpeHPJB6PT8OqeeOSMIyvqSaz5wZmSOzMk+IPeyDG70yRdvGdFRTpEuKJuyf8h1tjIStdMJg8Ihi97M4v48ciNkPAhpfJ533nm5npODC1K/aD2d03NH+OSmlvPmzTPn2EpYZMeTXgaZLsOzyoWX0iNypuu58iI3W5SbasqGlqFz5Zxr6cGWwQfkYlYxePBgc5RILkCVhsTJkyfNFx85H3ndunUFzl92bjksLTfplEDJKRu/+tWvzBekvMjwtX379jV1kgt75dQMGThBbijuDI4g5EiYDJEr5aWe0hiS9SE9NXJxrQyZK29aDqmrXPcmHyZy6pW84cjw6jIcbWHrmh9neNwznactH07S0JPhcMuUKWN604LJ+nbeEOQLpvReymAun3zyiXk4ZHmcL5Vyw1o5Yiinkkk9cp5+0LVr10AvG/JH5ryZOSFDX0tPsaxTIaexODeUlVOfnV5f+SnDassXHxk0QjInF65LnWU9OKTOkydPNhf+y74i85AvM7I+5IL7gjpy8D9kjszdcsst5tQyWTcy8JEsq3RayrLIAGXBZ7C899575kiUXOckjQGnESGvVdQ39441ZNGbWZw4caIZ7Ei+T0puZFnl6J3UUQ4+yHWHOcl3SKmXDMATtbQHHT58WD/44IO6devWukyZMuaGlTIU8dixY/WePXtc3QQzL998842+9tprdcWKFc08mzZtmuu2ADJMrbxWYmKief7NN990NUSuePnll82NN+UWAm6Gy5WhbOUGjzL8rNzgMr+bYIqXXnpJd+jQQZcuXdoM9Svr5t5779W7d+/O8yaYbdq0MfNt1qyZGRI3p/zq6swjp4svvtg8CjNErixTXjfedB6y3RwFlQt+/fxu5uk85Hm4R+a8lTnn7/PLR/B6uvnmm826kGUsVaqUbtSokb7vvvt0WlpanvOdNWtW4Ca71apVM7d0yK8s8kfmYjdzYseOHXrAgAFmSH+5tcmVV16pN2/enGs7XX755bp69eomm7JN5ebsS5cudVUfuEMWvZXFJUuWmDylpqaa3Ej9L7zwQvO9MPi2GMG3kpDt079/fx3NfPJPcTc6ER3kfGkZ5OT9998v7qoAMYHMAZFF5oDoQBYjy1PX8AEAAAAA/ocGHwAAAAB4FA0+AAAAAPAoruEDAAAAAI/iCB8AAAAAeFRE78Pn9/vNTRbLly9vbl4IeJkcPJcbr6amppobwRcXcodYQeaA2MwdmUMs0YXIXEQbfBLG2rVrR/IlgWK3Y8cOVatWrWJ7fXKHWEPmgNjKHZlDLNphkbmINvik50VcpPqoBFWqyOc//4evrcpf26S1ihWsm8jLUpnqE7UwsN8Xl3Dn7u1N66zKD256nooW8Sl228Z/8pRV+XnfrQ9b7sJdd52VpcLFl5AQlrqU5MzZrJNx61db1efh1h1UtIhvWM+qfPaPP1uVn/v9BqvyA5q1c102vtI5VvPWJ07Ylc/KDltGbd8vstOOuS4bDblzXrt7iztVQnySq7/x/bzb9fzLzrX77DwxxKq4UhVTwpaLuFZNrOatN261Kr/10fZW5RuM/cJ12fjy5azmreumWpX3f73JqrxNjmwyZOZ9biXXZbP8GWr54ZlWmYtog885zC4fgAm+ov/imVLe7lSCcNQhWrFuisH/D4dU3KeXkLv8xfsSrcr7fVlRs27CXXcdxv3W50sIT11KcOZs1km5kpw5l1/GHT7Luoc1c3F2mdO+TMvy4cuo7fuF1XqPgtwFMhef5L7BZ7FOSpW12w8TbM9sDWMu4iznrS0zF5ecHDWfc9pyWf2Wy2pTH9v3Ltv3F9vMFepk66lTp6p69eqp5ORk1blzZ7VmzZrCzAaAS2QOiCwyB0QeuQPCw7rBN3v2bDV69Gg1fvx4tW7dOtW2bVvVq1cvtW/fvvDUEIhxZA6ILDIHRB65A6KowffUU0+pkSNHquHDh6sWLVqo6dOnqzJlyqhXX301V9n09HSVlpYW8gAQvswJcgecHTIHRB7fL4EoafBlZGSotWvXqssuu+x/M4iLM7+vWrUqV/lJkyapChUqBB6MoATYsc2cIHdA4ZE5IPL4fglEUYPvwIEDKjs7W1WrVi1kuvy+d+/eXOXHjh2rjh49GnjI8KEAwpc5Qe6AwiNzQOTx/RIIr7CO0pmUlGQeACKH3AGRReaAyCJzQBiP8FWuXFnFx8erX375JWS6/F69enXLlwZwJmQOiCwyB0QeuQOiqMGXmJioOnTooJYuXRqY5vf7ze9dunQJR/2AmEbmgMgic0DkkTsgyk7plCFzhw0bpjp27Kg6deqkpkyZok6cOGFGVQJQ9MgcEFlkDog8cgdEUYNv0KBBav/+/erBBx80F9K2a9dOLVq0KNeFtsWhV2o7q/KLd28I6/zDqSTXHcWTufiU8irel+iqbLbFENdX1Tw/rPtu3059rcpn7dzluqzNcooZ2z+xKt+30yCr8kqFr+7xKSkqnGzqo7OyVCxkzpeQoHy+or9U/s/XDLMq33ztZqvynz/Wwap8hWVbrMpbzfs/lazK96llV/c4i+vAsprajQTpW/mlXV3aNLMqr7612642EmrVdF/Yn27z1hXW3Pm/3qT8vlKuysYlJ7ue7/5HmyobZZJ3W5VXp9Ktimf06ui6bOmtB63mnXatXYaaPWk3YE52fLzrsjojw2revpN269GWbX1s+I8cdV9WZ1rPv1CfRLfddpt5AIgMMgdEFpkDIo/cAVFy43UAAAAAQMlAgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHpWgPGTx7g0lev7RVPdeqe3CVhcUj+y0Y8rnK1Xs+9ZR/ymr8m99NteqfDlfkgqX4zo+rHW/vnZXFS46I8OqvP/0aRUt4pKT3ZXTcUpFT7WVr3lD5Yt3tz/6v9zoer6L/jXLqh7pOtOqfNIzX4Qt0weys63mvTXzHKvyDX86bFX+9g5Xuy4bv/Z7q3n7VXjprCzXZf0nT1rNO71rU9dlszJPK7VLRYUfJ53v+v2i+irter5zn3zSqh4fnaprVb5Z4h6r8q0Sfa7L7sxKt5p3vYQyVuXv3tvJqvyCDe6/XzZ+1f0+LhI27bAqH+dyXynM52J8SorVvLPT0lyX1dpuvQiO8AEAAACAR9HgAwAAAACPosEHAAAAAB5Fgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHpWgotzi3RvCNu9eqe2ipi7RVneb8rZ1QTHx+f77cGHxrvWuZ5ut/VbVuL5Wl6jJnXXda3e1Km+zHm3L96rZ3mre/vR0q/Ju95UArcM2b//p0+7K6UwVTeIOpam4uCRXZd/b9bnFnEtZ1eOaPjdYlX9/4Uyr8qtPp7gu2zk5zWretzXtYFX+Xz9+ZlX+ubULXJe9vcPVVvNWlpnT3262Ku9LcP8VTmdlWc07ec9x12Wzsi3fW8LIn5KlVGl3y1p+vvvPljJPx1vV44npg6zKrxvzvFX549r9Oq+V4O49yJGlsq3K10w6bFW++WOHXJc91fBcq3nHHTlqV75MGavyyuVnkdAZGXbztvpc9Cll8ZErOMIHAAAAAB5Fgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8igYfAAAAAHiUT2utI/ViaWlpqkKFCurwDw1USnnamrGqV2o7FQuydKb6WC1QR48eVSkpKcVWDyd3ezfVdp27JF8p1/NP15lW9fkmw+4tp0NSogqXPVnHVTjVSCgXNXUf0aqPVXn/yZNW5XVWluuyvoQEq3nHV6/mqlyWP119uGt61GTO5rNu5rFzXc9/QLm9VvWxybPYmmm3b9VLKOO6bLzP7rN/8qGGVuXbJm+3Kt+zTGbY1sstdS+yKm+bi7gyZcKW5/TL2rsum5V5Wq38cHyx5s7J3O9WXKcSy7nb3xdscP9dZFvvV6zqc9R/yqp8OV+SChfbzNl+pu/MSrcqP+9YW9dlX53by2re1T+zq3vios+tysdb7N/ZaWlW845LTnZdNktnqI9Oz7HKHK0uAAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8igYfAAAAAHgUDT4AAAAA8CgafAAAAADgUTT4AAAAAMCjElSU65XaznXZxbs3hLUusYT17j1JvlIqyeeuj6dPs+6u57vw+xVW9eiQpMJqbXqG67IdksqpaNK3U1/XZT9Y84HVvLPT0lQ4xaekhK0uWTt3uSunM1U0WZ+eocolusvcWz0ucD3fAavfs6rHzGPnWpUfWt6quMrWftdlt2Yet5r36HM2q3BqOPsW12Wn9ftbWOsSX72aVXmddsx92awsq3mXXrnJddks7f49N9xqJB1RyUnuvto2f+yQ+xn3tqtHv29/bVX+6Sazrcp3SEp0XXbJyVJW8+5R2n2eRRmfVXE156merstmtLarS+LiL6zK6wvb2ZVf+73rsnFtm9vN+1v373VaZ1vN29TH+i8AAAAAACWCVYNvwoQJyufzhTyaNWsWvtoBMY7MAZFH7oDIInNAlJ3S2bJlS/Xhhx/+bwYJUX9WKFCikTkg8sgdEFlkDggf6zRJAKtXrx6e2gDIhcwBkUfugMgic0D4WF/Dt3nzZpWamqoaNGighg4dqrZv355v2fT0dJWWlhbyABC+zAlyB5w9PuuAyCJzQJQ0+Dp37qxmzJihFi1apKZNm6a2bdumunXrpo4dy3ukqEmTJqkKFSoEHrVr1y6qegMxwTZzgtwBZ4fPOiCyyBwQRQ2+3r17q4EDB6o2bdqoXr16qYULF6ojR46oOXPm5Fl+7Nix6ujRo4HHjh07iqreQEywzZwgd8DZ4bMOiCwyB4TXWV0RW7FiRdWkSRO1ZcuWPJ9PSkoyDwBF40yZE+QOKFp81gGRReaAonVW9+E7fvy42rp1q6pRo0bR1QhAvsgcEHnkDogsMgcUY4NvzJgxavny5eqnn35SK1euVNdee62Kj49XQ4YMKeJqARBkDog8cgdEFpkDouiUzp07d5rwHTx4UFWpUkVddNFF6rPPPjP/L4l6pbZTsWLx7g3FXQUUQnFlLttixLNs7bead59aHewqo7VdeZ/PddE4y1OC/OnpVuUX71pvVT5r127XZY/6T4VtvRRmvdvsM9Z1cT9jpSx3l3Dmrn1SokpJctevmrVzl+v5JvlKWdVj5vktrcq/UcCgUGcr/txKVuWzDxy0Kj9n5yqr8k3Guv9s7DzQciRIy/3cZh+wlVCrZtjqkq0zVbRkbvYbPVR8UrKrstU3r3Q937XpGVb1iH+6slX536feaVW+6pKCR+sOtnNgXat513x/r1X5Jm+7r4tt3c/ZZLf9bT/TfZvsrv3MPn3addn4bXZ59mdluS6rtfuyhWrwvf3229YvAKDwyBwQeeQOiCwyB0TxNXwAAAAAgOhFgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8KqE4XvTaJq1Vgq9Ukc+3V2o7q/KLd29Q4WRTn2iqSzTNG0VnQO9+KiE+yV1h3zbX8+1Tq4NVPRbvWm9Vfmvmcavyt9Tr5rrs+1tXqnDq0+Zyy7845Lrk9bW7qnCKb9zAqnz2Fvf7jDWti7ZchAy8tKdKiHOZObXL9XyvqNPRqh6Ltq+wKj/5UEOr8h+2Ku+67HNrF6hwGtzoMqvyvnJlXZe9vlYXy9rY7Y9xbZvbzf3bze7Lph1TsSD179+pBF+iq7LZFvO9fv4dVvWoXt5u2yce81uV//7u2q7LVvrari4b/1TJqvzRx6pYla9Qer/rsr5P7b4b6wS7Zo0vIzNsGdWbtoXtM1dnpyu11Wr2HOEDAAAAAK+iwQcAAAAAHkWDDwAAAAA8igYfAAAAAHgUDT4AAAAA8CgafAAAAADgUTT4AAAAAMCjaPABAAAAgEfR4AMAAAAAj6LBBwAAAAAelRDJF9Nam59ZKlOp//63WKUd84d1/lk6s0TWBUXD7OdB+31xCeTOn+76b7LDuL/Y7uvHM/0lN3f+DKvy4VzvtnS2+/0l7HV3maHoy1xGWPZbn+Xy2e7np49nWZW3qfvxsH/W2WXO5y8VNfmMs8yctqhPnOV6sVnWaMhdIHMWy2mzjP7Tp63qk5UZ3nXhP+1zXTY7w2c371N2+3lWZrxdeYv93DZztu+NcZa5sPpctH0vspi3833OJnM+HcGE7ty5U9WuXTtSLwdEhR07dqhatWoV2+uTO8QaMgfEVu7IHGLRDovMRbTB5/f71e7du1X58uWVz/e/Hoe0tDQTVKl4SkqK8jKWNXaWU6J17NgxlZqaquLiiu/s6VjPXawsp4j1ZSVz0SNWljVWljPaP+vIXOwsa6wsZ1FnLqKndEqlCmqJysJ4feM5WNbYWM4KFSqo4kbuYms5Y31ZyVx0iZVljZXljNbPOjIXe8saK8tZVJlj0BYAAAAA8CgafAAAAADgUVHR4EtKSlLjx483P72OZfWekrqcJbXetmJlOQXLGt1KYp0LK1aWNVaWs6Qua0msc2HFyrLGynIW9bJGdNAWAAAAAECMHeEDAAAAABQ9GnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+Kigbf1KlTVb169VRycrLq3LmzWrNmjfKaCRMmKJ/PF/Jo1qyZKulWrFih+vXrp1JTU80yvffeeyHPyyCwDz74oKpRo4YqXbq0uuyyy9TmzZuVF5f1xhtvzLWNr7jiChWNyFzJFiu5I3MlC5kr+ZkT5K7kIHNkrsQ0+GbPnq1Gjx5t7jOxbt061bZtW9WrVy+1b98+5TUtW7ZUe/bsCTw++eQTVdKdOHHCbDN5U83LE088oZ599lk1ffp0tXr1alW2bFmzfU+fPq28tqxCAhi8jWfNmqWiDZkr+WIld2Su5CFzJTtzgtyVLGSOzLmii1mnTp30rbfeGvg9Oztbp6am6kmTJmkvGT9+vG7btq32Mtmd5s+fH/jd7/fr6tWr68mTJwemHTlyRCclJelZs2ZpLy2rGDZsmL766qt1tCNz3hIruSNz0Y/MeStzgtxFNzJH5twq1iN8GRkZau3ateYwrCMuLs78vmrVKuU1cqhZDtc2aNBADR06VG3fvl152bZt29TevXtDtm+FChXMaRVe3L7i448/VlWrVlVNmzZVf/jDH9TBgwdVNCFz3s5cLOaOzEUXMuf9zAlyFz3I3H+RuYIVa4PvwIEDKjs7W1WrVi1kuvwuG9JLZCecMWOGWrRokZo2bZrZWbt166aOHTumvMrZhrGwfZ3D7W+88YZaunSpevzxx9Xy5ctV7969zT4eLcictzMXa7kjc9GFzHl/GwtyFz3InLe3b1FmLsF1SZwV2TCONm3amJDWrVtXzZkzR40YMaJY64aiMXjw4MD/W7dubbZzw4YNTa9Mjx49irVusYjMeR+Ziy5kLjaQu+hB5mLD4CLIXLEe4atcubKKj49Xv/zyS8h0+b169erKyypWrKiaNGmitmzZorzK2YaxuH2FnF4h+3g0bWMy5+3MxXruyFx0IXPe38aC3EUPMuft7Xs2mSvWBl9iYqLq0KGDOUTp8Pv95vcuXbooLzt+/LjaunWrGU7Wq+rXr2+CF7x909LSzGhKXt++YufOneYc62jaxmTO25mL9dyRuehC5ryfOUHuogeZI3NRe0qnDJk7bNgw1bFjR9WpUyc1ZcoUMzzp8OHDlZeMGTPG3GNDDrXv3r3bDBMsvU9DhgxRJf3NJbiHQc4f37Bhg6pUqZKqU6eOuuuuu9Sjjz6qGjdubAI6btw4c3HxNddco7y0rPJ46KGH1HXXXWfehOQN995771WNGjUywwRHEzJXsjMXS7kjcyULmSv5mRPkruQgc2TONR0FnnvuOV2nTh2dmJhohtH97LPPtNcMGjRI16hRwyxjzZo1ze9btmzRJd2yZcvMELI5HzKErDN07rhx43S1atXMcLk9evTQmzZt0l5b1pMnT+qePXvqKlWq6FKlSum6devqkSNH6r179+poROZKtljJHZkrWchcyc+cIHclB5kjc2755B/3zUMAAAAAQElRrNfwAQAAAADChwYfAAAAAHgUDT4AAAAA8CgafAAAAADgUTT4AAAAAMCjaPABAAAAgEfR4AMAAAAAj6LBBwAAAAAeRYMPAAAAADyKBh8AAAAAeBQNPgAAAABQ3vR/++vEQCTua0wAAAAASUVORK5CYII=", + "image/png": "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fuj13JXoBp+cLysbR47guCGHcKW80xhwyIaR6R999FFISGXaypUrA9PkXFyZJodunUO5QnoiZLrTYxP8ZiDn/zqkN0Z6euSL1f79+0N22pSUlFznEvfo0UO3bt06pMdI5iGBk/A75PCzzDc/hw8fDvSaFCRnSCWI8ncSAocETs5bljcrp3fDWYZzzz1XHzp0KFBWeo9kupw/XZgPR+nVkh6hnD744AMzD+fwudTjoosuMtPkIb02O3fuND1w8gYX/GYF98iXt/Mlp0xLT+3rr7+u58+fbz7ApfdYPly3b98eKCfLJfMMnhb8gRl8+vRbb71ltp+Uj4+P13/961/NdDldTY7WB1/jgNzInLczl9Nzzz1n/lauGwpG5iKL3Hk3d9J4lsuAevToETL9wIED5jumzOOLL76IidyV6FE609LSzE8ZJceNhQsXmp+jR48OmX733Xebnx988EHI9BYtWqguXboEfu/cubP5+atf/cqM3JNz+o8//pjrNW+77bbA/2UkLvldRpD88MMPQ8pdd911ZiRKx6FDh9RHH32krr/+enXs2DF14MAB8zh48KDq1auX2rx5s9q1a5cpW7FiRfXtt9+aaXkpXbq0SkxMVB9//LE6fPiwckvWV/Xq1dWQIUMC02QksTvuuMOMerl8+fKQ8oMGDTKjHzlkBKOc66VevXpmVE0ZIfBMZESspKSkXNNl5CTneWf7S11kHWzYsME8ZETOF154QaWnp6s//vGPZkQlGeFTpv/mN78J7DvIH/nydr5k2V977TV1ww03qGuuuUY98sgjavHixWYdTJw4MVDOyVl+WQweuU6WRdabjFgmP2Xbnzx5Ut13331mnuXKlTMj6soIeG3atFHz5893vb5iAZnzduZyklGjZR1dfvnlIdPJXGSRO+/mLi4uzoy6unTpUjV27FizbGvXrjXrwxnN3cmT13NXoht8MlyukJ3YjZ9//tls/EaNGoVMlx1RdnR5PlhwEEWFChXMz9q1a+c5PWcA5LVkYwdr0qSJ+ZlzONj69euH/L5lyxazM48bN86EN/ghQ8SKffv2mZ8PP/ywuX2BzLt169bqnnvuUV999VVgXrLzPv744+pf//qXqlatmurevbt64okn8hx6Pef6aty4sVmOYM2bNw88X9D6cgJr88aQ881FGmw5nT59OvC8Q+oob6pt27ZVCQkJ5g1twoQJ6q9//at5c7zyyivNulmwYIHavn27uv322wtVp1hCvrydr7zIsNXypSP4S4STs/yyGJxDp14XXHCBWRdi0qRJ5nYpw4cPV6+++qqaPn26euWVV8ztU+SDXbYF/ovMxU7m5MurfFmUDMhnVjAyF1nkztu5k+UaMWKEqassm9xGQTIn04Q0zmIhdyW+wZeamqq++eYbq7+TBoAb8fHxVtMlVIWVc0fy+/3m55gxY8z9Q/J6OG82Ejq5d4zsYK1atTI7mNxDRH46ZIf74YcfzA4pPRUSfgnb+vXrVVEp6vVSo0YNtWfPnlzTnWmy7fMjyyfrQI5cfPbZZ+ZvJOwSdOl1efvttwPrGHkjX97OV37kS4j0CgfnUOSXxYJyKF9GnnzySXMPK/mwnzVrlultlZ7tm266yfR6SxbxX2QudjLn3BN26NChuZ4jc5FF7rydOzkq+corr6jdu3erFStWqE2bNpmzWY4ePRrScPd67kp0g0/IkRvZQfO66WFOdevWNTt/zsPVv/zyi+nVkOeLkrxWzkPzEhTncHRBnN4cOex92WWX5fkIPv2gUqVKpldBdrIdO3aYQ8hyhCtYw4YNzWHnJUuWmDc2OZwtO2h+ZH3IusrZMPr+++8Dz4dTu3btzE3Wc77+6tWrzc0znR6unL788kvzhjVlyhTzu4RcemKcU0EltLLs+/fvD2v9vYB8eTdf+ZF1GnxKkORQfPHFFyHlJFc7d+4MPJ8X+ZJx1VVXmSOHzt8Ef2jK/53TifBfZC42MicNPqm/HCHIicxFHrnzfu6qVatmTg+V747Z2dnm1FQ5o8U5wuf13JX4Bt+9996rypYtq26++WYTtpwkwNLiFn369DE/nYaA46mnnjI/+/btW+T1e/7550N6J+R3CV6PHj0K/Ds5LHzJJZeoF198Mc/ehuDGipyLHUx2XumxcA5Ly3nFzmmQwYGVkOd16Noh60sO1c+ePTswLSsrSz333HPmNS6++GJlKzMz04Q8r2XKacCAAWabzps3LzBNTtV85513VL9+/fI8z1rceeedZn+QHion5LK+nKMWGzduNIfzK1eubF3/WEO+vJuvvDo85FoLub7hiiuuCExr2bKlatasmXrppZfMh6Rj2rRppodbcpqXZcuWmfnJkXWHZNH5kHeyKKdB4X/InHcz55CjIbLv//rXv87zeTIXeeTO+7kLJpf7yN86113GQu5CTxwvgWRnk54yOT9WDivLAATyRV96HFauXGkaBzfeeKMpK9d3DRs2zGxM6YWRnWzNmjXq9ddfN6f+yaAeRUmOKC1atMi8pvQiyHnPcjHv/fffH9KDnp+pU6ea3gI5l3rkyJGmp0beiKQHSnob5EiWkGvXJNAdOnQwvTPSOzF37tzARb7SEyRvCnKRqpSVxo5cQCrzGjx4cL6vP2rUKPMmIetPvgRKT5LM99NPPzVvdG4vcA4mPRyynWSdnOliWwmX9H5Kb5MMuiINNBmIRYIop2XmRba3nHP+7rvvBqbJoXQJ38CBA1X//v1N0OVnfqcN4H/Il3fz1bVrV9W+fXtzmrNcOyJH0+XIuJzSKesw2OTJk03vZc+ePc0ySa+ufOGQL0fOdRjBJKNy6o9cAxJ8PYZkWr5YyfaR6za+/vprNXPmTOvl9DIy593MOZx9Pq/TOR1kLrLInXdz9+abb5rvhHLKqjQw5Rr1OXPmmCzJIDcxkzvtEXLvKLl3SL169cxQtXLvNbkXhgx7HDwUrQzVLzesrF+/vrknSO3atQu8WWZOsspuvfXWfG8WWdDNMmWo1vHjx4fcYyWvvw0mfy/3d5GbW0p95f4tcg+WuXPnBso8+uijulOnTmboWRkmtlmzZnrixImBe5bI8LNSZ5kudZL7h3Tu3FnPmTMn5LXyu1mm3LRchmqX9SpD+8r9u860/MHrS5a5sENYy9C8I0aMMMP0yjqU+smNovMi93qR7Sb3eMlJ/kZuair7hdxrLOewxSgY+fJevh544AHdrl07U19Zdrkf1B/+8Ae9d+/ePMvLrRukvNw0V+5JJLdxCL4vUjC5L5WUOXHiRMh02T/k3kWyvLIPyC0hkDcy573MCVlXsszyeXQmZC7yyJ33cif31evevbu56bzc01BuPzF9+vSQG9fHQu588k/xNjm9SXoypAdDhpwFULTIFxBZZA6IPHKHolLir+EDAAAAAOSNBh8AAAAAeBQNPgAAAADwKK7hAwAAAACP4ggfAAAAAHgUDT4AAAAA8Ki4WB/uVm4AWRzkdZ2beHplmYS89pVXXllsr4/oRuaKHplDQchc0SNzKAyyWPTIYow3+NLS0tRDDz2k2rZtq8qVK6dKly6tWrVqpe677z61e/duFY2+++47NWHCBPXTTz+paBfpun7//ffq3nvvVe3atVPly5dXNWrUUH379lVffPFFrrLz5s1TgwYNUg0aNFBlypRRTZs2VXfffbc6cuRISLmDBw+qyZMnq+7du6sqVaqoihUrqgsuuEDNnj07IsvkNWTOe3WdOHGiuuqqq1S1atWUz+czr58XmS7P53wkJyfnWf6XX35Rv/vd71TNmjVNGfnAHjFiRJiXxnvIXOxmTuzatUtdf/315rMrJSVFXX311erHH3/MVS6vbMrjscceC/PSxA6y6K267t69W/3mN78x3x/lO6dkrFOnTur1119XOYc9kc+v/DLWuHFjFU0SlMfIG95ll12mtm/frgYOHKhGjRqlEhMT1VdffaX+9re/qfnz56sffvjBlH355ZeV3+8vlnpu2rRJxcXFhezQ8oZxySWXFGtviRuRrusrr7xitt11112nbrnlFnX06FH14osvmgbaokWLzPZ2yPZOTU01Ya1Tp476+uuv1fPPP68WLlyo1q1bZ96IxapVq9QDDzyg+vTpo/785z+rhIQE9e6776rBgwcHlg/ukLnwK466Si6qV6+u2rdvrxYvXnzG8tOmTTNfdhzx8fG5yuzYsUNdeOGF5v+///3vTaNPPlzXrFlTxLX3NjIX25mTm3Bfeuml5rPw/vvvV6VKlVJPP/20uvjii9WGDRvUueeeG1L+8ssvVzfccEPINHkNnD2yGH6RruuBAwfUzp071YABA8z3yMzMTPXvf//bHM2U9fiXv/wlUHbKlCkmj8F+/vlnk+WePXuqaOKpBl9WVpbq37+/6UH++OOP1UUXXZSr9+zxxx8P/C5vkm7mKQGVABelpKSkIp2flw0ZMsT07gR/mbzppptU8+bNzfTgBt/cuXPNm0KwDh06qGHDhqmZM2eqm2++2Uxr2bKl2rx5s6pbt26gnDQmZV6yj8gRxbJly0Zk+UoyMudd27ZtMx+u8uEnR8HPRD4cK1euXGAZObInnSuff/55ri+lcIfMeZfbzL3wwgvm80s6Ss4//3wzrXfv3uao0pNPPhnyhVQ0adLEdIKiaJFFb2rTpo3ZnsFuu+021a9fP/Xss8+qRx55JNChec011+T6+0cffdT8HDp0qIoq2kPefvttOdaqJ06c6Kr8sGHDdN26dQO/b9u2zfz95MmT9dNPP60bNGig4+Li9Pr1683zGzdu1AMHDtSVK1fWycnJukmTJvr+++/Pd36O8ePHm/kGk3JSXrz22mvm+ZyPZcuWFVj/+fPn65YtW+qkpCTzc968eXnWITs72yxPixYtTNmqVavqUaNG6UOHDuWqU9++ffXixYt127ZtTdnmzZvrd999N1DmTHV15vGf//xHn3/++WYe9evX16+//nqu+m/ZssU8Cqt///66UqVKZyyXlpZm6jh69Ogzln322WdN2a+++qrQ9YolZM77mdu/f795PVmneXHW9b59+/TRo0e13+/Ps5xsSyn3wgsvmN9PnTqlMzIyrOoCMkfmtHlNeeTUs2dP3bBhw5BpMp9bb71Vnzx50mQORYcsej+LwW677Tbt8/lMlgoiyyB1iDaeuobvH//4h/n529/+9qzm89prr6nnnnvOHJqX3rJKlSqZw/OdO3dWH330kRo5cqR65plnTMv+n//851nXW64ju+OOO8z/5fSMv//97+YhR7Dys2TJEnOKo5wnPGnSJFOX4cOH53ldm/Sq33PPPeZUKqm3lJOjXb169TKHqoNJr6FcAye9hTJf6Y2X0xTkcLbbum7ZssX09stpJLL+zjnnHHMo/Ntvvw15rR49ephHYe3du/eMRxSccqKoy4LMxVrmCiLXzVaoUMFc8yBHE6TXO9iHH35ofsr1SVIHOb1aHrLcJeE6kmhB5mI7c3L0R7ZTx44dcz0n1xlt3bpVHTt2LGT6jBkzzBkrkrcWLVqot956q8jqE8vIorezeOrUKXO0XT6f5Po92U5dunQJXBqUl/Xr16uNGzeqX//61yrqaA9p3769rlChguvy+fW2pKSkmN7qYN27d9fly5fXP//8c8j04N7swva2iHfeecdVD4ujXbt2ukaNGvrIkSOBaUuWLDHzCK6D9HrItJkzZ4b8/aJFi3JNl7+TacG9K9JjL68j69ZNXZ15rFixIjBN1qX0utx99925yua1vtyQ+UtPy7hx485YdsSIETo+Pl7/8MMPBZY7ePCg6Ynq1q1boeoUi8ic9zN3pqMNU6ZMMT2fslxz587Vd955p05ISNCNGzc2y+K44447zHzOPfdcfcUVV+jZs2ebnu1y5cqZoxInTpywqlesInOxnTnnuYcffjjXc1OnTjXPff/994FpXbt2NRldsGCBnjZtmm7VqlXIkXYUHln0dhYnTZoUclSxR48eevv27QX+jbymlP3uu+90tInz2khJ0rt8tqQXI/j8+f3796sVK1aY68bkAs5g0tsRaXv27DEXZst1adKj7pDeDem9C/bOO++YMvKc9FQ4D7muTa6JW7ZsWUh5GfDk2muvDfwuo3/Jxd7Sa+Ec/ToTqUO3bt0Cv8u6lNGOco4gJr0mhenZ37dvn+k9qV+/vrnWriDSkykXTstInQWNmCS9pnK+tYzmKT1tcIfMxUbmCnLnnXeazEgmZTvKRezSGyo9t3KtkcO5sF0Gpfjggw/MCINjxowxAxnIUQmOOrhD5mI7c3LUIb9rspyRcZ0y4tNPPzUZldE/ZaCktWvXmmv95GhJcDnYI4vezuKQIUPMkUb5bHKO2BWUGfke+fbbb5sBkQo6WlpcPNXgkx0l56kMhSENiWDOTiNvktFARgASeTVgZCcPJl+6ZCSvqlWrmhAEP+QLmDSegjVq1CjXG4pc8C3cBiXnG5SQQ+yHDx9WZ+vEiRPmniuynRcsWBAykEtO//nPf8xw73IagVw8XZDbb7/djPgpI4LK0Mpwh8x5P3OFIR+O0rBzTuMUzmkw0tALHi1OTt+R03hWrlxZLHUtachcbGfOyVF6enqu506fPh1SJi8yGIgMQCGdm9L4Q+GRRW9nsW7dumYgP2n4ySmpctmC/J5fo2/58uXmdilRN1iLF0fpbNasmekVkKG/a9euXej5FPRmWZD8el6ys7NVcZEeBwme7Kx5cTP6nq28hmMXOe9fYisjI8OMiCXntsuQ1QW9GX755ZemR1PKyMid8oUyPzLcrxyJkPsSne25+LGGzHk7c2dD9odDhw6F9OQ61/DlrLuM2FlcjdOShszFdubk+i45uidHXXJypjlZy4+z3wTnE/bIYmxlccCAAeaMFDn6KgcScpJlls5MaSBGI081+GTI1FmzZqk333xTjR07tsjmK6168c033xRYTnoUct7gO7h3pCA2h+mdWwlIT0pOco+QYA0bNjS97HLxrJs3Fbn4VUISXB/nHjLO/U+K45QCeRORw/xLly5Vc+bMMfcbyo+cHnbFFVeYNx25/15BRwGnTp1qbu1w1113mZukwg6Z827mzoYsj/TOBt/rS07pEdIDmrMjx+2tH0DmYj1z8oWydevWeQ6WsXr1arMdz3SaoXMEicydHbIYW1k89f9H9uQIZk5yxF3u5Sy3BTtTh0tx8dQpndL6ljdCOX1Pbqydkxx6l5tt25I3RRkp6NVXXzU318yvB0F2dNkR5AhUcI+b3HjzTJx7vuUV3pxq1Kih2rVrZ66TCd7x5FxjuUFlMDl9Snp75L4hed3vJefryU2Qg+sr56i/8cYb5vXkFC3buhZEGmbycENOuZw9e7Y5EidH+fIj53zLzS7lQ1GOAhb0gSbzk9Gf5PD7U089VahliHVkzruZc0uuN8nrJuwyXTpeHPJB6PT8OqeeOSMIyvqSaz5wZmSOzMk+IPeyDG70yRdvGdFRTpEuKJuyf8h1tjIStdMJg8Ihi97M4v48ciNkPAhpfJ533nm5npODC1K/aD2d03NH+OSmlvPmzTPn2EpYZMeTXgaZLsOzyoWX0iNypuu58iI3W5SbasqGlqFz5Zxr6cGWwQfkYlYxePBgc5RILkCVhsTJkyfNFx85H3ndunUFzl92bjksLTfplEDJKRu/+tWvzBekvMjwtX379jV1kgt75dQMGThBbijuDI4g5EiYDJEr5aWe0hiS9SE9NXJxrQyZK29aDqmrXPcmHyZy6pW84cjw6jIcbWHrmh9neNwznactH07S0JPhcMuUKWN604LJ+nbeEOQLpvReymAun3zyiXk4ZHmcL5Vyw1o5Yiinkkk9cp5+0LVr10AvG/JH5ryZOSFDX0tPsaxTIaexODeUlVOfnV5f+SnDassXHxk0QjInF65LnWU9OKTOkydPNhf+y74i85AvM7I+5IL7gjpy8D9kjszdcsst5tQyWTcy8JEsq3RayrLIAGXBZ7C899575kiUXOckjQGnESGvVdQ39441ZNGbWZw4caIZ7Ei+T0puZFnl6J3UUQ4+yHWHOcl3SKmXDMATtbQHHT58WD/44IO6devWukyZMuaGlTIU8dixY/WePXtc3QQzL998842+9tprdcWKFc08mzZtmuu2ADJMrbxWYmKief7NN990NUSuePnll82NN+UWAm6Gy5WhbOUGjzL8rNzgMr+bYIqXXnpJd+jQQZcuXdoM9Svr5t5779W7d+/O8yaYbdq0MfNt1qyZGRI3p/zq6swjp4svvtg8CjNErixTXjfedB6y3RwFlQt+/fxu5uk85Hm4R+a8lTnn7/PLR/B6uvnmm826kGUsVaqUbtSokb7vvvt0WlpanvOdNWtW4Ca71apVM7d0yK8s8kfmYjdzYseOHXrAgAFmSH+5tcmVV16pN2/enGs7XX755bp69eomm7JN5ebsS5cudVUfuEMWvZXFJUuWmDylpqaa3Ej9L7zwQvO9MPi2GMG3kpDt079/fx3NfPJPcTc6ER3kfGkZ5OT9998v7qoAMYHMAZFF5oDoQBYjy1PX8AEAAAAA/ocGHwAAAAB4FA0+AAAAAPAoruEDAAAAAI/iCB8AAAAAeFRE78Pn9/vNTRbLly9vbl4IeJkcPJcbr6amppobwRcXcodYQeaA2MwdmUMs0YXIXEQbfBLG2rVrR/IlgWK3Y8cOVatWrWJ7fXKHWEPmgNjKHZlDLNphkbmINvik50VcpPqoBFWqyOc//4evrcpf26S1ihWsm8jLUpnqE7UwsN8Xl3Dn7u1N66zKD256nooW8Sl228Z/8pRV+XnfrQ9b7sJdd52VpcLFl5AQlrqU5MzZrJNx61db1efh1h1UtIhvWM+qfPaPP1uVn/v9BqvyA5q1c102vtI5VvPWJ07Ylc/KDltGbd8vstOOuS4bDblzXrt7iztVQnySq7/x/bzb9fzLzrX77DwxxKq4UhVTwpaLuFZNrOatN261Kr/10fZW5RuM/cJ12fjy5azmreumWpX3f73JqrxNjmwyZOZ9biXXZbP8GWr54ZlWmYtog885zC4fgAm+ov/imVLe7lSCcNQhWrFuisH/D4dU3KeXkLv8xfsSrcr7fVlRs27CXXcdxv3W50sIT11KcOZs1km5kpw5l1/GHT7Luoc1c3F2mdO+TMvy4cuo7fuF1XqPgtwFMhef5L7BZ7FOSpW12w8TbM9sDWMu4iznrS0zF5ecHDWfc9pyWf2Wy2pTH9v3Ltv3F9vMFepk66lTp6p69eqp5ORk1blzZ7VmzZrCzAaAS2QOiCwyB0QeuQPCw7rBN3v2bDV69Gg1fvx4tW7dOtW2bVvVq1cvtW/fvvDUEIhxZA6ILDIHRB65A6KowffUU0+pkSNHquHDh6sWLVqo6dOnqzJlyqhXX301V9n09HSVlpYW8gAQvswJcgecHTIHRB7fL4EoafBlZGSotWvXqssuu+x/M4iLM7+vWrUqV/lJkyapChUqBB6MoATYsc2cIHdA4ZE5IPL4fglEUYPvwIEDKjs7W1WrVi1kuvy+d+/eXOXHjh2rjh49GnjI8KEAwpc5Qe6AwiNzQOTx/RIIr7CO0pmUlGQeACKH3AGRReaAyCJzQBiP8FWuXFnFx8erX375JWS6/F69enXLlwZwJmQOiCwyB0QeuQOiqMGXmJioOnTooJYuXRqY5vf7ze9dunQJR/2AmEbmgMgic0DkkTsgyk7plCFzhw0bpjp27Kg6deqkpkyZok6cOGFGVQJQ9MgcEFlkDog8cgdEUYNv0KBBav/+/erBBx80F9K2a9dOLVq0KNeFtsWhV2o7q/KLd28I6/zDqSTXHcWTufiU8irel+iqbLbFENdX1Tw/rPtu3059rcpn7dzluqzNcooZ2z+xKt+30yCr8kqFr+7xKSkqnGzqo7OyVCxkzpeQoHy+or9U/s/XDLMq33ztZqvynz/Wwap8hWVbrMpbzfs/lazK96llV/c4i+vAsprajQTpW/mlXV3aNLMqr7612642EmrVdF/Yn27z1hXW3Pm/3qT8vlKuysYlJ7ue7/5HmyobZZJ3W5VXp9Ktimf06ui6bOmtB63mnXatXYaaPWk3YE52fLzrsjojw2revpN269GWbX1s+I8cdV9WZ1rPv1CfRLfddpt5AIgMMgdEFpkDIo/cAVFy43UAAAAAQMlAgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHpWgPGTx7g0lev7RVPdeqe3CVhcUj+y0Y8rnK1Xs+9ZR/ymr8m99NteqfDlfkgqX4zo+rHW/vnZXFS46I8OqvP/0aRUt4pKT3ZXTcUpFT7WVr3lD5Yt3tz/6v9zoer6L/jXLqh7pOtOqfNIzX4Qt0weys63mvTXzHKvyDX86bFX+9g5Xuy4bv/Z7q3n7VXjprCzXZf0nT1rNO71rU9dlszJPK7VLRYUfJ53v+v2i+irter5zn3zSqh4fnaprVb5Z4h6r8q0Sfa7L7sxKt5p3vYQyVuXv3tvJqvyCDe6/XzZ+1f0+LhI27bAqH+dyXynM52J8SorVvLPT0lyX1dpuvQiO8AEAAACAR9HgAwAAAACPosEHAAAAAB5Fgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHpWgotzi3RvCNu9eqe2ipi7RVneb8rZ1QTHx+f77cGHxrvWuZ5ut/VbVuL5Wl6jJnXXda3e1Km+zHm3L96rZ3mre/vR0q/Ju95UArcM2b//p0+7K6UwVTeIOpam4uCRXZd/b9bnFnEtZ1eOaPjdYlX9/4Uyr8qtPp7gu2zk5zWretzXtYFX+Xz9+ZlX+ubULXJe9vcPVVvNWlpnT3262Ku9LcP8VTmdlWc07ec9x12Wzsi3fW8LIn5KlVGl3y1p+vvvPljJPx1vV44npg6zKrxvzvFX549r9Oq+V4O49yJGlsq3K10w6bFW++WOHXJc91fBcq3nHHTlqV75MGavyyuVnkdAZGXbztvpc9Cll8ZErOMIHAAAAAB5Fgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8igYfAAAAAHiUT2utI/ViaWlpqkKFCurwDw1USnnamrGqV2o7FQuydKb6WC1QR48eVSkpKcVWDyd3ezfVdp27JF8p1/NP15lW9fkmw+4tp0NSogqXPVnHVTjVSCgXNXUf0aqPVXn/yZNW5XVWluuyvoQEq3nHV6/mqlyWP119uGt61GTO5rNu5rFzXc9/QLm9VvWxybPYmmm3b9VLKOO6bLzP7rN/8qGGVuXbJm+3Kt+zTGbY1sstdS+yKm+bi7gyZcKW5/TL2rsum5V5Wq38cHyx5s7J3O9WXKcSy7nb3xdscP9dZFvvV6zqc9R/yqp8OV+SChfbzNl+pu/MSrcqP+9YW9dlX53by2re1T+zq3vios+tysdb7N/ZaWlW845LTnZdNktnqI9Oz7HKHK0uAAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8igYfAAAAAHgUDT4AAAAA8CgafAAAAADgUTT4AAAAAMCjElSU65XaznXZxbs3hLUusYT17j1JvlIqyeeuj6dPs+6u57vw+xVW9eiQpMJqbXqG67IdksqpaNK3U1/XZT9Y84HVvLPT0lQ4xaekhK0uWTt3uSunM1U0WZ+eocolusvcWz0ucD3fAavfs6rHzGPnWpUfWt6quMrWftdlt2Yet5r36HM2q3BqOPsW12Wn9ftbWOsSX72aVXmddsx92awsq3mXXrnJddks7f49N9xqJB1RyUnuvto2f+yQ+xn3tqtHv29/bVX+6Sazrcp3SEp0XXbJyVJW8+5R2n2eRRmfVXE156merstmtLarS+LiL6zK6wvb2ZVf+73rsnFtm9vN+1v373VaZ1vN29TH+i8AAAAAACWCVYNvwoQJyufzhTyaNWsWvtoBMY7MAZFH7oDIInNAlJ3S2bJlS/Xhhx/+bwYJUX9WKFCikTkg8sgdEFlkDggf6zRJAKtXrx6e2gDIhcwBkUfugMgic0D4WF/Dt3nzZpWamqoaNGighg4dqrZv355v2fT0dJWWlhbyABC+zAlyB5w9PuuAyCJzQJQ0+Dp37qxmzJihFi1apKZNm6a2bdumunXrpo4dy3ukqEmTJqkKFSoEHrVr1y6qegMxwTZzgtwBZ4fPOiCyyBwQRQ2+3r17q4EDB6o2bdqoXr16qYULF6ojR46oOXPm5Fl+7Nix6ujRo4HHjh07iqreQEywzZwgd8DZ4bMOiCwyB4TXWV0RW7FiRdWkSRO1ZcuWPJ9PSkoyDwBF40yZE+QOKFp81gGRReaAonVW9+E7fvy42rp1q6pRo0bR1QhAvsgcEHnkDogsMgcUY4NvzJgxavny5eqnn35SK1euVNdee62Kj49XQ4YMKeJqARBkDog8cgdEFpkDouiUzp07d5rwHTx4UFWpUkVddNFF6rPPPjP/L4l6pbZTsWLx7g3FXQUUQnFlLttixLNs7bead59aHewqo7VdeZ/PddE4y1OC/OnpVuUX71pvVT5r127XZY/6T4VtvRRmvdvsM9Z1cT9jpSx3l3Dmrn1SokpJctevmrVzl+v5JvlKWdVj5vktrcq/UcCgUGcr/txKVuWzDxy0Kj9n5yqr8k3Guv9s7DzQciRIy/3cZh+wlVCrZtjqkq0zVbRkbvYbPVR8UrKrstU3r3Q937XpGVb1iH+6slX536feaVW+6pKCR+sOtnNgXat513x/r1X5Jm+7r4tt3c/ZZLf9bT/TfZvsrv3MPn3addn4bXZ59mdluS6rtfuyhWrwvf3229YvAKDwyBwQeeQOiCwyB0TxNXwAAAAAgOhFgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8KqE4XvTaJq1Vgq9Ukc+3V2o7q/KLd29Q4WRTn2iqSzTNG0VnQO9+KiE+yV1h3zbX8+1Tq4NVPRbvWm9Vfmvmcavyt9Tr5rrs+1tXqnDq0+Zyy7845Lrk9bW7qnCKb9zAqnz2Fvf7jDWti7ZchAy8tKdKiHOZObXL9XyvqNPRqh6Ltq+wKj/5UEOr8h+2Ku+67HNrF6hwGtzoMqvyvnJlXZe9vlYXy9rY7Y9xbZvbzf3bze7Lph1TsSD179+pBF+iq7LZFvO9/r07rOpRvbzdtk885rcq//3dtV2XrfS1XV02/qmSVfmjj1WxKl+h9H7XZX2f2n031gl2zRpfRmbYMqo3bQvbZ67OTldqq9XsOcIHAAAAAF5Fgw8AAAAAPIoGHwAAAAB4FA0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8KiGSL6a1Nj+zVKZS//1vsUo75g/r/LN0ZomsC4qG2c+D9vviEsidP93132SHcX+x3dePZ/pLbu78GVblw7nebels9/tL2OvuMkPRl7mMsOy3Psvls93PTx/PsipvU/fjYf+ss8ucz18qavIZZ5k5bVGfOMv1YrOs0ZC7QOYsltNmGf2nT1vVJyszvOvCf9rnumx2hs9u3qfs9vOszHi78hb7uW3mbN8b4yxzYfW5aPteZDFv5/ucTeZ8OoIJ3blzp6pdu3akXg6ICjt27FC1atUqttcnd4g1ZA6IrdyROcSiHRaZi2iDz+/3q927d6vy5csrn+9/PQ5paWkmqFLxlJQU5WUsa+wsp0Tr2LFjKjU1VcXFFd/Z07Geu1hZThHry0rmokesLGusLGe0f9aRudhZ1lhZzqLOXERP6ZRKFdQSlYXx+sZzsKyxsZwVKlRQxY3cxdZyxvqykrnoEivLGivLGa2fdWQu9pY1VpazqDLHoC0AAAAA4FE0+AAAAADAo6KiwZeUlKTGjx9vfnody+o9JXU5S2q9bcXKcgqWNbqVxDoXVqwsa6wsZ0ld1pJY58KKlWWNleUs6mWN6KAtAAAAAIAYO8IHAAAAACh6NPgAAAAAwKNo8AEAAACAR9HgAwAAAACPosEHAAAAAB4VFQ2+qVOnqnr16qnk5GTVuXNntWbNGuU1EyZMUD6fL+TRrFkzVdKtWLFC9evXT6Wmpppleu+990Kel0FgH3zwQVWjRg1VunRpddlll6nNmzcrLy7rjTfemGsbX3HFFSoakbmSLVZyR+ZKFjJX8jMnyF3JQebIXIlp8M2ePVuNHj3a3Gdi3bp1qm3btqpXr15q3759ymtatmyp9uzZE3h88sknqqQ7ceKE2WbyppqXJ554Qj377LNq+vTpavXq1aps2bJm+54+fVp5bVmFBDB4G8+aNUtFGzJX8sVK7shcyUPmSnbmBLkrWcgcmXNFF7NOnTrpW2+9NfB7dna2Tk1N1ZMmTdJeMn78eN22bVvtZbI7zZ8/P/C73+/X1atX15MnTw5MO3LkiE5KStKzZs3SXlpWMWzYMH311VfraEfmvCVWckfmoh+Z81bmBLmLbmSOzLlVrEf4MjIy1Nq1a81hWEdcXJz5fdWqVcpr5FCzHK5t0KCBGjp0qNq+fbvysm3btqm9e/eGbN8KFSqY0yq8uH3Fxx9/rKpWraqaNm2q/vCHP6iDBw+qaELmvJ25WMwdmYsuZM77mRPkLnqQuf8icwUr1gbfgQMHVHZ2tqpWrVrIdPldNqSXyE44Y8YMtWjRIjVt2jSzs3br1k0dO3ZMeZWzDWNh+zqH29944w21dOlS9fjjj6vly5er3r17m308WpA5b2cu1nJH5qILmfP+NhbkLnqQOW9v36LMXILrkjgrsmEcbdq0MSGtW7eumjNnjhoxYkSx1g1FY/DgwYH/t27d2mznhg0bml6ZHj16FGvdYhGZ8z4yF13IXGwgd9GDzMWGwUWQuWI9wle5cmUVHx+vfvnll5Dp8nv16tWVl1WsWFE1adJEbdmyRXmVsw1jcfsKOb1C9vFo2sZkztuZi/XckbnoQua8v40FuYseZM7b2/dsMlesDb7ExETVoUMHc4jS4ff7ze9dunRRXnb8+HG1detWM5ysV9WvX98EL3j7pqWlmdGUvL59xc6dO8051tG0jcmctzMX67kjc9GFzHk/c4LcRQ8yR+ai9pROGTJ32LBhqmPHjqpTp05qypQpZnjS4cOHKy8ZM2aMuceGHGrfvXu3GSZYep+GDBmiSvqbS3APg5w/vmHDBlWpUiVVp04dddddd6lHH31UNW7c2AR03Lhx5uLia665RnlpWeXx0EMPqeuuu868Cckb7r333qsaNWpkhgmOJmSuZGculnJH5koWMlfyMyfIXclB5sicazoKPPfcc7pOnTo6MTHRDKP72Wefaa8ZNGiQrlGjhlnGmjVrmt+3bNmiS7ply5aZIWRzPmQIWWfo3HHjxulq1aqZ4XJ79OihN23apL22rCdPntQ9e/bUVapU0aVKldJ169bVI0eO1Hv37tXRiMyVbLGSOzJXspC5kp85Qe5KDjJH5tzyyT/um4cAAAAAgJKiWK/hAwAAAACEDw0+AAAAAPAoGnwAAAAA4FE0+AAAAADAo2jwAQAAAIBH0eADAAAAAI+iwQcAAAAAHkWDDwAAAAA8igYfAAAAAHgUDT4AAAAA8CgafAAAAACgvOn/AHI4xEGCL5HxAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -245,48 +242,69 @@ "metadata": {}, "source": [ "# An idea of how to mix in an algorithm\n", - "Here is a small example of how you might mix in an algorithm, note that decoding requires that you trace out the algorithmic qubits (or not, if you want that effect)" + "Here is a small example of how you might mix in an algorithm, note that decoding requires that you trace out the algorithmic qubits (or not, if you want that effect).\n", + "\n", + "The ```cFRQI_with_alg_demo``` function combines a QPIXL-encoded image with a quantum circuit, by converting images into angle representations and compressing them with a given threshold. In addition to this, we use the ```CircuitCombiner``` class to provide a flexible interface for mixing a QPIXL-encoded data circuit with an algorithmic quantum circuit, applying different strategies: \n", + "\n", + "- ```sequential```: appending the algorithmic circuit after encoding the data, to let it process the entire encoded image.\n", + "- ```merge```: appending gates from both circuits in alternating order, for applying the algorithm in tandem with the encoding.\n", + "- ```custom```: allowing full control using a custom slice rule function ```slice_rule[i]```." ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 30, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
                    ┌───┐                                                                                             \n",
-       "storage qubits_0: ──┤ H ├─────────────────────────────────────────────────────────────────■────────────────────────■──\n",
-       "                    ├───┤                                                                 │                        │  \n",
-       "storage qubits_1: ──┤ H ├───────────────────────────────────────■─────────────────────────┼──────■─────────────────┼──\n",
-       "                    ├───┤                                       │                         │      │                 │  \n",
-       "storage qubits_2: ──┤ H ├─────────────────■─────────────────────┼──────■──────────────────┼──────┼─────────────────┼──\n",
-       "                    └───┘  ┌─────────┐  ┌─┴─┐  ┌───────────┐  ┌─┴─┐  ┌─┴─┐┌──────────┐  ┌─┴─┐  ┌─┴─┐┌───────────┐┌─┴─┐\n",
-       "  encoding qubit: ─────────┤ Ry(π/2) ├──┤ X ├──┤ Ry(-π/14) ├──┤ X ├──┤ X ├┤ Ry(-π/7) ├──┤ X ├──┤ X ├┤ Ry(-2π/7) ├┤ X ├\n",
-       "                  ┌───────┐└────┬────┘┌─┴───┴─┐└─────┬─────┘┌─┴───┴─┐└───┘└────┬─────┘┌─┴───┴─┐└───┘└─────┬─────┘└───┘\n",
-       "algorithm qubits: ┤ alg_0 ├─────■─────┤ alg_1 ├──────■──────┤ alg_3 ├──────────■──────┤ alg_7 ├───────────■───────────\n",
-       "                  └───────┘           └───────┘             └───────┘                 └───────┘                       
" - ], - "text/plain": [ - " ┌───┐ \n", - "storage qubits_0: ──┤ H ├─────────────────────────────────────────────────────────────────■────────────────────────■──\n", - " ├───┤ │ │ \n", - "storage qubits_1: ──┤ H ├───────────────────────────────────────■─────────────────────────┼──────■─────────────────┼──\n", - " ├───┤ │ │ │ │ \n", - "storage qubits_2: ──┤ H ├─────────────────■─────────────────────┼──────■──────────────────┼──────┼─────────────────┼──\n", - " └───┘ ┌─────────┐ ┌─┴─┐ ┌───────────┐ ┌─┴─┐ ┌─┴─┐┌──────────┐ ┌─┴─┐ ┌─┴─┐┌───────────┐┌─┴─┐\n", - " encoding qubit: ─────────┤ Ry(π/2) ├──┤ X ├──┤ Ry(-π/14) ├──┤ X ├──┤ X ├┤ Ry(-π/7) ├──┤ X ├──┤ X ├┤ Ry(-2π/7) ├┤ X ├\n", - " ┌───────┐└────┬────┘┌─┴───┴─┐└─────┬─────┘┌─┴───┴─┐└───┘└────┬─────┘┌─┴───┴─┐└───┘└─────┬─────┘└───┘\n", - "algorithm qubits: ┤ alg_0 ├─────■─────┤ alg_1 ├──────■──────┤ alg_3 ├──────────■──────┤ alg_7 ├───────────■───────────\n", - " └───────┘ └───────┘ └───────┘ └───────┘ " - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], + "source": [ + "from qiskit import QuantumCircuit\n", + "\n", + "class CircuitCombiner:\n", + " def __init__(self, data_circuit: QuantumCircuit, algorithm_circuit: QuantumCircuit):\n", + " self.data = data_circuit\n", + " self.algo = algorithm_circuit\n", + "\n", + " def combine(self, mode=\"sequential\", slice_rule=None) -> QuantumCircuit:\n", + " if mode == \"sequential\":\n", + " return self.data.compose(self.algo, inplace=False)\n", + "\n", + " elif mode in {\"merge\", \"custom\"}:\n", + " n_qubits = max(self.data.num_qubits, self.algo.num_qubits)\n", + " n_clbits = max(self.data.num_clbits, self.algo.num_clbits)\n", + " combined = QuantumCircuit(n_qubits, n_clbits)\n", + "\n", + " data_instrs = list(self.data.data)\n", + " algo_instrs = list(self.algo.data)\n", + " max_len = max(len(data_instrs), len(algo_instrs))\n", + "\n", + " for i in range(max_len):\n", + " decision = \"both\"\n", + " if slice_rule and callable(slice_rule):\n", + " decision = slice_rule(i)\n", + "\n", + " if decision in (\"data\", \"both\") and i < len(data_instrs):\n", + " instr, qargs, cargs = data_instrs[i]\n", + " mapped_qargs = [combined.qubits[self.data.find_bit(q).index] for q in qargs]\n", + " mapped_cargs = [combined.clbits[self.data.find_bit(c).index] for c in cargs]\n", + " combined.append(instr, mapped_qargs, mapped_cargs)\n", + "\n", + " if decision in (\"algo\", \"both\") and i < len(algo_instrs):\n", + " instr, qargs, cargs = algo_instrs[i]\n", + " mapped_qargs = [combined.qubits[self.algo.find_bit(q).index] for q in qargs]\n", + " mapped_cargs = [combined.clbits[self.algo.find_bit(c).index] for c in cargs]\n", + " combined.append(instr, mapped_qargs, mapped_cargs)\n", + "\n", + " return combined\n", + "\n", + " else:\n", + " raise NotImplementedError(f\"Mode '{mode}' is not supported.\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], "source": [ "def cFRQI_with_alg_demo(a, compression):\n", " \"\"\"Takes a standard image in a numpy array (so that the matrix looks like\n", @@ -302,85 +320,217 @@ " Returns:\n", " QuantumCircuit: qiskit circuit that prepared the encoded image\n", " \"\"\"\n", - " a = hlp.convertToAngles(a) # convert grayscale to angles\n", - " a = hlp.preprocess_image(a) # need to flatten the transpose for easier decoding,\n", - " # only really necessary if you want to recover an image.\n", - " # for classification tasks etc. transpose isn't required.\n", + " # Convert image to angle representation\n", + " a = hlp.convertToAngles(a)\n", + " a = hlp.preprocess_image(a) # Ensure flattening and preparation\n", " n = len(a)\n", " k = hlp.ilog2(n)\n", + " \n", " a = 2 * a\n", " a = hlp.sfwht(a)\n", " a = hlp.grayPermutation(a)\n", + " \n", + " # Apply compression by zeroing small coefficients\n", " a_sort_ind = np.argsort(np.abs(a))\n", - " # set smallest absolute values of a to zero according to compression param\n", " cutoff = int((compression / 100.0) * n)\n", " for it in a_sort_ind[:cutoff]:\n", " a[it] = 0\n", "\n", - " # Construct FRQI circuit\n", + " # Construct FRQI circuit (only data + encoding qubits)\n", " dataqbits = qiskit.QuantumRegister(k, \"storage qubits\")\n", " encodingqubit = qiskit.QuantumRegister(1, \"encoding qubit\")\n", - " algorithmqubit = qiskit.QuantumRegister(1, \"algorithm qubits\") # OPTIONAL\n", - " # additional qubit to do interesting stuff with\n", - " circuit = QuantumCircuit(dataqbits, encodingqubit, algorithmqubit)\n", + " circuit = QuantumCircuit(dataqbits, encodingqubit)\n", "\n", - " # Data qubits\n", " circuit.h(dataqbits)\n", "\n", " ctrl, pc, i = 0, 0, 0\n", " while i < (2**k):\n", - " pc = int(0) # Reset the parity check\n", + " pc = 0\n", " if a[i] != 0:\n", - " circuit.unitary(\n", - " np.array(\n", - " [\n", - " [np.cos(a[i]), -1j * np.sin(a[i])],\n", - " [-1j * np.sin(a[i]), np.cos(a[i])],\n", - " ]\n", - " ),\n", - " algorithmqubit[0],\n", - " label=f\"alg_{i}\",\n", - " )\n", - " circuit.cry(\n", - " a[i], algorithmqubit, encodingqubit\n", - " ) # normally would just be an ry gate\n", - " # Loop over sequence of consecutive zero angles to cancel out CNOTS (or rather, to not include them)\n", + " circuit.cry(a[i], dataqbits[0], encodingqubit[0]) # Use first data qubit for control (can be extended)\n", + " \n", " if i == ((2**k) - 1):\n", " ctrl = 0\n", " else:\n", " ctrl = hlp.grayCode(i) ^ hlp.grayCode(i + 1)\n", " ctrl = k - hlp.countr_zero(ctrl, n_bits=k + 1) - 1\n", - " pc ^= 2**ctrl # Update parity check\n", + " pc ^= 2**ctrl\n", " i += 1\n", " while i < (2**k) and a[i] == 0:\n", - " # Compute control qubit\n", " if i == ((2**k) - 1):\n", " ctrl = 0\n", " else:\n", " ctrl = hlp.grayCode(i) ^ hlp.grayCode(i + 1)\n", " ctrl = k - hlp.countr_zero(ctrl, n_bits=k + 1) - 1\n", - " pc ^= 2**ctrl # Update parity check\n", + " pc ^= 2**ctrl\n", " i += 1\n", " for j in range(k):\n", " if (pc >> j) & 1:\n", " circuit.cx(dataqbits[j], encodingqubit[0])\n", + " \n", " circuit.reverse_bits()\n", - " return circuit\n", + " return circuit\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
                  ┌───┐                                                                                    ┌───┐     \n",
+       "storage qubits_0: ┤ H ├─────■────────────────■─────────────────────■─────────────■─────────────■────────■──┤ H ├──■──\n",
+       "                  ├───┤     │                │                     │             │             │        │  └───┘┌─┴─┐\n",
+       "storage qubits_1: ┤ H ├─────┼────────────────┼────────■────────────┼─────────────┼────■────────┼────────┼───────┤ X ├\n",
+       "                  ├───┤     │                │        │            │      ┌───┐  │    │        │        │       └───┘\n",
+       "storage qubits_2: ┤ H ├─────┼───────■────────┼────────┼────■───────┼──────┤ Z ├──┼────┼────────┼────────┼────────────\n",
+       "                  └───┘┌────┴────┐┌─┴─┐┌─────┴─────┐┌─┴─┐┌─┴─┐┌────┴─────┐└───┘┌─┴─┐┌─┴─┐┌─────┴─────┐┌─┴─┐          \n",
+       "  encoding qubit: ─────┤ Ry(π/2) ├┤ X ├┤ Ry(-π/14) ├┤ X ├┤ X ├┤ Ry(-π/7) ├─────┤ X ├┤ X ├┤ Ry(-2π/7) ├┤ X ├──────────\n",
+       "                       └─────────┘└───┘└───────────┘└───┘└───┘└──────────┘     └───┘└───┘└───────────┘└───┘          
" + ], + "text/plain": [ + " ┌───┐ ┌───┐ \n", + "storage qubits_0: ┤ H ├─────■────────────────■─────────────────────■─────────────■─────────────■────────■──┤ H ├──■──\n", + " ├───┤ │ │ │ │ │ │ └───┘┌─┴─┐\n", + "storage qubits_1: ┤ H ├─────┼────────────────┼────────■────────────┼─────────────┼────■────────┼────────┼───────┤ X ├\n", + " ├───┤ │ │ │ │ ┌───┐ │ │ │ │ └───┘\n", + "storage qubits_2: ┤ H ├─────┼───────■────────┼────────┼────■───────┼──────┤ Z ├──┼────┼────────┼────────┼────────────\n", + " └───┘┌────┴────┐┌─┴─┐┌─────┴─────┐┌─┴─┐┌─┴─┐┌────┴─────┐└───┘┌─┴─┐┌─┴─┐┌─────┴─────┐┌─┴─┐ \n", + " encoding qubit: ─────┤ Ry(π/2) ├┤ X ├┤ Ry(-π/14) ├┤ X ├┤ X ├┤ Ry(-π/7) ├─────┤ X ├┤ X ├┤ Ry(-2π/7) ├┤ X ├──────────\n", + " └─────────┘└───┘└───────────┘└───┘└───┘└──────────┘ └───┘└───┘└───────────┘└───┘ " + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from qiskit import QuantumCircuit\n", + "import numpy as np\n", "\n", + "# Sample image data\n", + "img = np.array([0, 1, 2, 3, 4, 5, 6, 7])\n", + "data = cFRQI_with_alg_demo_edit(img, compression=50)\n", "\n", - "circ = cFRQI_with_alg_demo(np.array([0, 1, 2, 3, 4, 5, 6, 7]), 0)\n", - "circ.draw(fold=150, vertical_compression=\"high\")" + "# Sample algorithmic circuit\n", + "algo = QuantumCircuit(3)\n", + "algo.h(0)\n", + "algo.cx(0, 1)\n", + "algo.z(2)\n", + "\n", + "# Sequential: applying the algorithm after QPIXL encoding\n", + "combiner_seq = CircuitCombiner(data, algo)\n", + "combined_seq = combiner_seq.combine(mode=\"sequential\")\n", + "combined_seq.draw(fold=150, vertical_compression=\"high\")\n" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
     ┌───┐┌───┐                                                                                    \n",
+       "q_0: ┤ H ├┤ H ├──■───────■────────────────■─────────────────────■────────■─────────────■────────■──\n",
+       "     ├───┤└───┘┌─┴─┐     │                │                     │        │             │        │  \n",
+       "q_1: ┤ H ├─────┤ X ├─────┼────────────────┼────────■────────────┼────────┼────■────────┼────────┼──\n",
+       "     ├───┤┌───┐└───┘     │                │        │            │        │    │        │        │  \n",
+       "q_2: ┤ H ├┤ Z ├──────────┼───────■────────┼────────┼────■───────┼────────┼────┼────────┼────────┼──\n",
+       "     └───┘└───┘     ┌────┴────┐┌─┴─┐┌─────┴─────┐┌─┴─┐┌─┴─┐┌────┴─────┐┌─┴─┐┌─┴─┐┌─────┴─────┐┌─┴─┐\n",
+       "q_3: ───────────────┤ Ry(π/2) ├┤ X ├┤ Ry(-π/14) ├┤ X ├┤ X ├┤ Ry(-π/7) ├┤ X ├┤ X ├┤ Ry(-2π/7) ├┤ X ├\n",
+       "                    └─────────┘└───┘└───────────┘└───┘└───┘└──────────┘└───┘└───┘└───────────┘└───┘
" + ], + "text/plain": [ + " ┌───┐┌───┐ \n", + "q_0: ┤ H ├┤ H ├──■───────■────────────────■─────────────────────■────────■─────────────■────────■──\n", + " ├───┤└───┘┌─┴─┐ │ │ │ │ │ │ \n", + "q_1: ┤ H ├─────┤ X ├─────┼────────────────┼────────■────────────┼────────┼────■────────┼────────┼──\n", + " ├───┤┌───┐└───┘ │ │ │ │ │ │ │ │ \n", + "q_2: ┤ H ├┤ Z ├──────────┼───────■────────┼────────┼────■───────┼────────┼────┼────────┼────────┼──\n", + " └───┘└───┘ ┌────┴────┐┌─┴─┐┌─────┴─────┐┌─┴─┐┌─┴─┐┌────┴─────┐┌─┴─┐┌─┴─┐┌─────┴─────┐┌─┴─┐\n", + "q_3: ───────────────┤ Ry(π/2) ├┤ X ├┤ Ry(-π/14) ├┤ X ├┤ X ├┤ Ry(-π/7) ├┤ X ├┤ X ├┤ Ry(-2π/7) ├┤ X ├\n", + " └─────────┘└───┘└───────────┘└───┘└───┘└──────────┘└───┘└───┘└───────────┘└───┘" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Merge: alternating operations from both circuits\n", + "combiner_merge = CircuitCombiner(data, algo)\n", + "combined_merge = combiner_merge.combine(mode=\"merge\")\n", + "combined_merge.draw(fold=150, vertical_compression=\"high\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
     ┌───┐                                \n",
+       "q_0: ┤ H ├──■────────────■─────────────■──\n",
+       "     └───┘┌─┴─┐          │             │  \n",
+       "q_1: ─────┤ X ├──■───────┼────────■────┼──\n",
+       "     ┌───┐└───┘  │       │        │    │  \n",
+       "q_2: ┤ H ├──■────┼───────┼────────┼────┼──\n",
+       "     └───┘┌─┴─┐┌─┴─┐┌────┴─────┐┌─┴─┐┌─┴─┐\n",
+       "q_3: ─────┤ X ├┤ X ├┤ Ry(-π/7) ├┤ X ├┤ X ├\n",
+       "          └───┘└───┘└──────────┘└───┘└───┘
" + ], + "text/plain": [ + " ┌───┐ \n", + "q_0: ┤ H ├──■────────────■─────────────■──\n", + " └───┘┌─┴─┐ │ │ \n", + "q_1: ─────┤ X ├──■───────┼────────■────┼──\n", + " ┌───┐└───┘ │ │ │ │ \n", + "q_2: ┤ H ├──■────┼───────┼────────┼────┼──\n", + " └───┘┌─┴─┐┌─┴─┐┌────┴─────┐┌─┴─┐┌─┴─┐\n", + "q_3: ─────┤ X ├┤ X ├┤ Ry(-π/7) ├┤ X ├┤ X ├\n", + " └───┘└───┘└──────────┘└───┘└───┘" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Custom: applying slicing rule function for precision\n", + "img = np.array([0, 1, 2, 3, 4, 5, 6, 7])\n", + "data = cFRQI_with_alg_demo_edit(img, compression=50)\n", + "\n", + "algo = QuantumCircuit(3)\n", + "algo.h(0)\n", + "algo.cx(0, 1)\n", + "algo.z(2)\n", + "\n", + "def alternate(i):\n", + " return \"data\" if i % 2 == 0 else \"algo\"\n", + "\n", + "combiner = CircuitCombiner(data, algo)\n", + "combined_circuit = combiner.combine(mode=\"custom\", slice_rule=alternate)\n", + "combined_circuit.draw(fold=150, vertical_compression=\"high\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "82bdee920508496083fbba72bb654eb2", + "model_id": "d00c89a418ba42c18f918ae4289c8c25", "version_major": 2, "version_minor": 0 }, @@ -397,7 +547,7 @@ "" ] }, - "execution_count": 7, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -1145,7 +1295,7 @@ ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1159,7 +1309,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.8" + "version": "3.11.4" } }, "nbformat": 4,