Usage examples#

github colab colab

# this cell is hidden in the docs
# it installs the requirements to run this demo
#!python -m pip install qutree[demo]
from urllib.request import urlretrieve
import tempfile

import numpy as np
import matplotlib.pyplot as plt
import pennylane as qml
from scipy.stats import unitary_group
from qutree import BBT

Bell state preparation#

@qml.qnode(qml.device("default.qubit", wires=2))
def bell(t):
    qml.Hadamard(wires=[0])
    qml.CRY(np.pi*t,wires=[0,1])
    return qml.state()

ts = np.linspace(0,1,21)
Ss = np.array([bell(t) for t in ts]).T
bbt = BBT(2)
bbt.add_data(Ss)
bbt.plot_tree()
../_images/b3e43fdc079adc2d552f460cb958814b0215a6f2b1552d6ee3cd8b9e4a3ac51c.png

The top sphere shows the effect of the hadamard gate : an even superposition between the two basis state without phase offset. Then on the bottom sphere we see the effect of the parametrised Control Y rotattion : The left sphere represent the subspace where the first qubit is 0. it is of course untouched by the CY gate. The right sphere represent the subspace where the first qubit is 1. The state is gradually rotated about the Y axis from 0 (blue) to 1 (red). The bell state corresponds to the red point.

Study how an encoding spans the hilbert space#

dev = qml.device('default.qubit', wires=3)

@qml.qnode(dev)
def circuit(t):
    state = np.array([1, 2j, 3, t*1j, 5, 6j, 7, 8j])
    state = state / np.linalg.norm(state)
    qml.MottonenStatePreparation(state_vector=state, wires=range(3))
    return qml.state()

print(qml.draw(circuit, expansion_strategy="device", max_length=80)(4))
0: ──RY(2.35)─╭●───────────╭●──────────────╭●────────────────────────╭●
1: ──RY(2.09)─╰X──RY(0.21)─╰X─╭●───────────│────────────╭●───────────│─
2: ──RY(1.88)─────────────────╰X──RY(0.10)─╰X──RY(0.08)─╰X──RY(0.15)─╰X

──╭●────────╭●────╭●────╭●─┤ ╭State
──╰X────────╰X─╭●─│──╭●─│──┤ ├State
───RZ(1.57)────╰X─╰X─╰X─╰X─┤ ╰State
ts = np.linspace(0,8,21)
Ss = np.array([circuit(t) for t in ts]).T
bbt = BBT(3)
bbt.add_data(Ss)
bbt.plot_tree()
../_images/b3e847cf40de3b4409345664196092292e1717ce427638215ff7e436065160cc.png

quantum states dataset from Machine Learning#

The data is generated using the demo from pennylane about classification that can be found here : https://pennylane.ai/qml/demos/tutorial_variational_classifier.html

# read the file from data folder in github
with tempfile.NamedTemporaryFile() as tmp:
    url = 'https://raw.githubusercontent.com/alice4space/qutree/main/docs/source/examples/data/iris_quantum_kernel.npy'
    urlretrieve(url, tmp.name)
    states_ml = np.load(tmp.name,allow_pickle=True)
---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
Cell In[9], line 4
      2 with tempfile.NamedTemporaryFile() as tmp:
      3     url = 'https://raw.githubusercontent.com/alice4space/qutree/main/docs/source/examples/data/iris_quantum_kernel.npy'
----> 4     urlretrieve(url, tmp.name)
      5     states_ml = np.load(tmp.name,allow_pickle=True)

File ~/.asdf/installs/python/3.10.13/lib/python3.10/urllib/request.py:241, in urlretrieve(url, filename, reporthook, data)
    224 """
    225 Retrieve a URL into a temporary location on disk.
    226 
   (...)
    237 data file as well as the resulting HTTPMessage object.
    238 """
    239 url_type, path = _splittype(url)
--> 241 with contextlib.closing(urlopen(url, data)) as fp:
    242     headers = fp.info()
    244     # Just return the local path and the "headers" for file://
    245     # URLs. No sense in performing a copy unless requested.

File ~/.asdf/installs/python/3.10.13/lib/python3.10/urllib/request.py:216, in urlopen(url, data, timeout, cafile, capath, cadefault, context)
    214 else:
    215     opener = _opener
--> 216 return opener.open(url, data, timeout)

File ~/.asdf/installs/python/3.10.13/lib/python3.10/urllib/request.py:525, in OpenerDirector.open(self, fullurl, data, timeout)
    523 for processor in self.process_response.get(protocol, []):
    524     meth = getattr(processor, meth_name)
--> 525     response = meth(req, response)
    527 return response

File ~/.asdf/installs/python/3.10.13/lib/python3.10/urllib/request.py:634, in HTTPErrorProcessor.http_response(self, request, response)
    631 # According to RFC 2616, "2xx" code indicates that the client's
    632 # request was successfully received, understood, and accepted.
    633 if not (200 <= code < 300):
--> 634     response = self.parent.error(
    635         'http', request, response, code, msg, hdrs)
    637 return response

File ~/.asdf/installs/python/3.10.13/lib/python3.10/urllib/request.py:563, in OpenerDirector.error(self, proto, *args)
    561 if http_err:
    562     args = (dict, 'default', 'http_error_default') + orig_args
--> 563     return self._call_chain(*args)

File ~/.asdf/installs/python/3.10.13/lib/python3.10/urllib/request.py:496, in OpenerDirector._call_chain(self, chain, kind, meth_name, *args)
    494 for handler in handlers:
    495     func = getattr(handler, meth_name)
--> 496     result = func(*args)
    497     if result is not None:
    498         return result

File ~/.asdf/installs/python/3.10.13/lib/python3.10/urllib/request.py:643, in HTTPDefaultErrorHandler.http_error_default(self, req, fp, code, msg, hdrs)
    642 def http_error_default(self, req, fp, code, msg, hdrs):
--> 643     raise HTTPError(req.full_url, code, msg, hdrs, fp)

HTTPError: HTTP Error 404: Not Found
bbt = BBT(4)
lam = 0.3
cs = np.concatenate([np.random.random(50)*lam,np.random.random(50)*lam+1-lam])
bbt.add_data(states_ml.T,colors=cs)
bbt.plot_tree()

hamiltonian simulation#

num_qubits = 4
U = unitary_group.rvs(2**num_qubits,random_state = 0)
D,S = np.linalg.eigh(U)

excite only two eigenstates : a single frequency#

ka = 12
kb = 2

S0 = (S[:,ka]+S[:,kb])/np.sqrt(2)
Sts = []
ts = np.linspace(0,2*np.pi/np.abs(D[ka]-D[kb]),101)
for t in ts:
    Sts.append(S @ np.diag(np.exp(1j*D*t)) @ S.T.conj() @ S0)
Sts = np.array(Sts).T
bbt = BBT(4)
bbt.add_data(Sts,cmap='hsv')
bbt.plot_tree()

excite three eigenstates : three frequencies#

ka = 12
kb = 2
kc = 4

S0 = (S[:,ka]+S[:,kb]+S[:,kc])/np.sqrt(3)
Sts = []
ts = np.linspace(0,5,101)
for t in ts:
    Sts.append(S @ np.diag(np.exp(1j*D*t)) @ S.T.conj() @ S0)
Sts = np.array(Sts).T
bbt = BBT(4)
bbt.add_data(Sts,cmap='jet')
bbt.plot_tree()