From 0b994bc309740c250f1f427ddc4f0b32e39e304d Mon Sep 17 00:00:00 2001 From: Vytautas Abramavicius Date: Fri, 15 Nov 2024 12:15:24 +0200 Subject: [PATCH 1/4] added batch dimension to input state --- .../time_dependent/integrators/adaptive.py | 16 +- pyqtorch/time_dependent/integrators/krylov.py | 22 +- pyqtorch/time_dependent/mesolve.py | 26 +- pyqtorch/time_dependent/methods/dp5.py | 5 +- pyqtorch/time_dependent/options.py | 2 + pyqtorch/time_dependent/sesolve.py | 8 + pyqtorch/time_dependent/solvers.py | 2 +- tests/test_analog.py | 12 +- tests/test_solvers.py | 22 +- to_delete.ipynb | 1324 +++++++++++++++++ to_delete.py | 202 +++ 11 files changed, 1602 insertions(+), 39 deletions(-) create mode 100644 to_delete.ipynb create mode 100644 to_delete.py diff --git a/pyqtorch/time_dependent/integrators/adaptive.py b/pyqtorch/time_dependent/integrators/adaptive.py index fd5304a9..60e4be88 100644 --- a/pyqtorch/time_dependent/integrators/adaptive.py +++ b/pyqtorch/time_dependent/integrators/adaptive.py @@ -126,9 +126,10 @@ def init_tstep( """ sc = self.options.atol + torch.abs(y0) * self.options.rtol + f0 = f0.to_dense() if self.options.use_sparse else f0 d0, d1 = ( hairer_norm(y0 / sc).max().item(), - hairer_norm(f0.to_dense() / sc).max().item(), + hairer_norm(f0 / sc).max().item(), ) if d0 < 1e-5 or d1 < 1e-5: @@ -138,7 +139,8 @@ def init_tstep( y1 = y0 + h0 * f0 f1 = fun(t0 + h0, y1) - d2 = hairer_norm((f1 - f0).to_dense() / sc).max().item() / h0 + diff = (f1 - f0).to_dense() if self.options.use_sparse else f1 - f0 + d2 = hairer_norm(diff / sc).max().item() / h0 if d1 <= 1e-15 and d2 <= 1e-15: h1 = max(1e-6, h0 * 1e-3) else: @@ -183,13 +185,17 @@ def run(self) -> Tensor: # initialize the ODE routine t, y, *args = self.init_forward() - n1, n2 = y.shape # run the ODE routine result = [] for tnext in self.tsave: y, *args = self.integrate(t, tnext, y, *args) - result.append(y.mH if n1 == n2 else y.T) + result.append(y) t = tnext - return torch.cat(result).reshape((-1, n1, n2)) + if len(y.shape) == 2: + res = torch.stack(result) + elif len(y.shape) == 3: + res = torch.stack(result).permute(0, 2, 3, 1) + + return res diff --git a/pyqtorch/time_dependent/integrators/krylov.py b/pyqtorch/time_dependent/integrators/krylov.py index 99be0587..7c290a81 100644 --- a/pyqtorch/time_dependent/integrators/krylov.py +++ b/pyqtorch/time_dependent/integrators/krylov.py @@ -30,14 +30,16 @@ def integrate(self, t0: float, t1: float, y: Tensor) -> Tensor: pass def run(self) -> Tensor: - t = self.t0 - # run the Krylov routine - result = [] - y = self.y0 - for tnext in self.tsave: - y = self.integrate(t, tnext, y) - result.append(y.T) - t = tnext - - return torch.cat(result).unsqueeze(-1) + out = [] + for i in range(self.y0.shape[1]): + # run the Krylov routine + result = [] + y = self.y0[:, i : i + 1] + t = self.t0 + for tnext in self.tsave: + y = self.integrate(t, tnext, y) + result.append(y.T) + t = tnext + out.append(torch.cat(result)) + return torch.stack(out, dim=2) diff --git a/pyqtorch/time_dependent/mesolve.py b/pyqtorch/time_dependent/mesolve.py index e429781f..3bede864 100644 --- a/pyqtorch/time_dependent/mesolve.py +++ b/pyqtorch/time_dependent/mesolve.py @@ -12,7 +12,7 @@ def mesolve( H: Callable[..., Any], - psi0: Tensor, + rho0: Tensor, L: list[Tensor], tsave: list | Tensor, solver: SolverType, @@ -22,7 +22,7 @@ def mesolve( Args: H (Callable[[float], Tensor]): time-dependent Hamiltonian of the system - psi0 (Tensor): initial state or density matrix of the system + rho0 (Tensor): initial density matrix of the system L (list[Tensor]): list of jump operators tsave (Tensor): tensor containing simulation time instants solver (SolverType): name of the solver to use @@ -34,18 +34,22 @@ def mesolve( """ options = options or dict() L = torch.stack(L) - if psi0.size(-2) == 1: - rho0 = psi0.mH @ psi0 - elif psi0.size(-1) == 1: - rho0 = psi0 @ psi0.mH - elif psi0.size(-1) == psi0.size(-2): - rho0 = psi0 - else: + + # check dimensions of initial state + n = H(0.0).shape[0] + if ( + (rho0.shape[0] != rho0.shape[1]) + or (rho0.shape[0] != n) + or (len(rho0.shape) != 3) + ): raise ValueError( - "Argument `psi0` must be a ket, bra or density matrix, but has shape" - f" {tuple(psi0.shape)}." + f"Argument `rho0` must be a 3D tensor of shape `({n}, {n}, batch_size)`. " + f"Current shape: {tuple(rho0.shape)}." ) + # permute dimensions to allow batch operations + rho0 = rho0.permute(2, 0, 1) + # instantiate appropriate solver if solver == SolverType.DP5_ME: opt = AdaptiveSolverOptions(**options) diff --git a/pyqtorch/time_dependent/methods/dp5.py b/pyqtorch/time_dependent/methods/dp5.py index 78c0c054..9b4a2cb8 100644 --- a/pyqtorch/time_dependent/methods/dp5.py +++ b/pyqtorch/time_dependent/methods/dp5.py @@ -75,10 +75,11 @@ def step( # compute iterated Runge-Kutta values k = torch.empty(7, *f.shape, dtype=self.options.ctype) - k[0] = f.to_dense() + k[0] = f.to_dense() if self.options.use_sparse else f for i in range(1, 7): dy = torch.tensordot(dt * beta[i - 1, :i], k[:i].clone(), dims=([0], [0])) - k[i] = fun(t + dt * alpha[i - 1].item(), y + dy).to_dense() + a = fun(t + dt * alpha[i - 1].item(), y + dy) + k[i] = a.to_dense() if self.options.use_sparse else a # compute results f_new = k[-1] diff --git a/pyqtorch/time_dependent/options.py b/pyqtorch/time_dependent/options.py index ae29fcad..a21b769b 100644 --- a/pyqtorch/time_dependent/options.py +++ b/pyqtorch/time_dependent/options.py @@ -17,6 +17,7 @@ class AdaptiveSolverOptions: max_factor: float = 5.0 ctype: dtype = torch.complex128 rtype: dtype = torch.float64 + use_sparse: bool = False @dataclass @@ -25,3 +26,4 @@ class KrylovSolverOptions: max_krylov: int = 80 exp_tolerance: float = 1e-10 norm_tolerance: float = 1e-10 + use_sparse: bool = False diff --git a/pyqtorch/time_dependent/sesolve.py b/pyqtorch/time_dependent/sesolve.py index 45092b00..3c463fb7 100644 --- a/pyqtorch/time_dependent/sesolve.py +++ b/pyqtorch/time_dependent/sesolve.py @@ -29,6 +29,14 @@ def sesolve( Returns: Result: dataclass containing the simulated states at each time moment """ + # check dimensions of initial state + n = H(0.0).shape[0] + if (psi0.shape[0] != n) or len(psi0.shape) != 2: + raise ValueError( + f"Argument `psi0` must be a 2D tensor of shape `({n}, batch_size)`. Current shape:" + f" {tuple(psi0.shape)}." + ) + options = options or dict() # instantiate appropriate solver if solver == SolverType.DP5_SE: diff --git a/pyqtorch/time_dependent/solvers.py b/pyqtorch/time_dependent/solvers.py index 480106f0..b95c3c65 100644 --- a/pyqtorch/time_dependent/solvers.py +++ b/pyqtorch/time_dependent/solvers.py @@ -30,7 +30,7 @@ def ode_fun(self, t: float, psi: Tensor) -> Tensor: with warnings.catch_warnings(): # filter-out UserWarning about "Sparse CSR tensor support is in beta state" warnings.filterwarnings("ignore", category=UserWarning) - res = -1j * self.H(t) @ psi.to_sparse() + res = -1j * self.H(t) @ psi.to_sparse() if self.options.use_sparse else psi return res diff --git a/tests/test_analog.py b/tests/test_analog.py index 64ac0d3d..f1e9d0c3 100644 --- a/tests/test_analog.py +++ b/tests/test_analog.py @@ -292,12 +292,14 @@ def test_hamevo_endianness_cnot() -> None: assert torch.allclose(wf_cnot, wf_hamevo, rtol=RTOL, atol=ATOL) -@pytest.mark.parametrize("duration", [torch.rand(1), "duration"]) +@pytest.mark.parametrize("duration", [torch.rand(1)]) +@pytest.mark.parametrize("batch_size", [1, 5]) @pytest.mark.parametrize("ode_solver", [SolverType.DP5_SE, SolverType.KRYLOV_SE]) def test_timedependent( tparam: str, param_y: float, duration: float, + batch_size: int, n_steps: int, torch_hamiltonian: Callable, hamevo_generator: Sequence, @@ -306,14 +308,14 @@ def test_timedependent( ode_solver: SolverType, ) -> None: - psi_start = random_state(2) + psi_start = random_state(2, batch_size) dur_val = duration if isinstance(duration, torch.Tensor) else torch.rand(1) # simulate with time-dependent solver t_points = torch.linspace(0, dur_val[0], n_steps) psi_solver = pyq.sesolve( - torch_hamiltonian, psi_start.reshape(-1, 1), t_points, ode_solver + torch_hamiltonian, psi_start.reshape(-1, batch_size), t_points, ode_solver ).states[-1] # simulate with HamiltonianEvolution @@ -324,14 +326,14 @@ def test_timedependent( hamiltonian_evolution = pyq.HamiltonianEvolution( generator=hamevo_generator, time=tparam, - duration=duration, + duration=dur_val, steps=n_steps, solver=ode_solver, ) values = {"y": param_y, "duration": dur_val} psi_hamevo = hamiltonian_evolution( state=psi_start, values=values, embedding=embedding - ).reshape(-1, 1) + ).reshape(-1, batch_size) assert torch.allclose(psi_solver, psi_hamevo, rtol=RTOL, atol=ATOL) diff --git a/tests/test_solvers.py b/tests/test_solvers.py index f6bc51ef..7a17c854 100644 --- a/tests/test_solvers.py +++ b/tests/test_solvers.py @@ -17,19 +17,23 @@ @pytest.mark.flaky(max_runs=5) +@pytest.mark.parametrize("batch_size", [1, 5]) @pytest.mark.parametrize("ode_solver", [SolverType.DP5_SE, SolverType.KRYLOV_SE]) def test_sesolve( duration: float, + batch_size: int, n_steps: int, torch_hamiltonian: Callable, qutip_hamiltonian: Callable, ode_solver: SolverType, ) -> None: - psi0_qutip = qutip.basis(4, 0) # simulate with torch-based solver - psi0_torch = torch.tensor(psi0_qutip.full()).to(torch.complex128) + psi0_torch = ( + torch.tensor(psi0_qutip.full()).to(torch.complex128).repeat(1, batch_size) + ) + t_points = torch.linspace(0, duration, n_steps) state_torch = sesolve(torch_hamiltonian, psi0_torch, t_points, ode_solver).states[ -1 @@ -38,15 +42,17 @@ def test_sesolve( # simulate with qutip solver t_points = np.linspace(0, duration, n_steps) result = qutip.sesolve(qutip_hamiltonian, psi0_qutip, t_points) - state_qutip = torch.tensor(result.states[-1].full()) + state_qutip = torch.tensor(result.states[-1].full()).repeat(1, batch_size) assert torch.allclose(state_torch, state_qutip, atol=ATOL) @pytest.mark.flaky(max_runs=5) +@pytest.mark.parametrize("batch_size", [1, 5]) @pytest.mark.parametrize("ode_solver", [SolverType.DP5_ME]) def test_mesolve( duration: float, + batch_size: int, n_steps: int, torch_hamiltonian: Callable, qutip_hamiltonian: Callable, @@ -58,14 +64,20 @@ def test_mesolve( # simulate with torch-based solver psi0_torch = torch.tensor(psi0_qutip.full()).to(torch.complex128) + rho0_torch = ( + torch.matmul(psi0_torch, psi0_torch.T).unsqueeze(-1).repeat(1, 1, batch_size) + ) + t_points = torch.linspace(0, duration, n_steps) state_torch = mesolve( - torch_hamiltonian, psi0_torch, jump_op_torch, t_points, ode_solver + torch_hamiltonian, rho0_torch, jump_op_torch, t_points, ode_solver ).states[-1] # simulate with qutip solver t_points = np.linspace(0, duration, n_steps) result = qutip.mesolve(qutip_hamiltonian, psi0_qutip, t_points, jump_op_qutip) - state_qutip = torch.tensor(result.states[-1].full()) + state_qutip = ( + torch.tensor(result.states[-1].full()).unsqueeze(-1).repeat(1, 1, batch_size) + ) assert torch.allclose(state_torch, state_qutip, atol=ATOL) diff --git a/to_delete.ipynb b/to_delete.ipynb new file mode 100644 index 00000000..00cc9aff --- /dev/null +++ b/to_delete.ipynb @@ -0,0 +1,1324 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "PyQTorch logger successfully setup with log level 20\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([0.9320], dtype=torch.float64, grad_fn=)\n" + ] + } + ], + "source": [ + "import torch\n", + "import torch.autograd.gradcheck\n", + "\n", + "import pyqtorch as pyq\n", + "from pyqtorch.embed import ConcretizedCallable, Embedding\n", + "# name0, fn0 = \"fn0\", ConcretizedCallable(\"sin\", [\"x\"])\n", + "name1, fn1 = \"fn1\", ConcretizedCallable(\"mul\", [3, \"x\"])\n", + "# name2, fn2 = \"fn2\", ConcretizedCallable(\"mul\", [\"fn1\", 2.0])\n", + "# name3, fn3 = \"fn3\", ConcretizedCallable(\"log\", [\"fn2\"])\n", + "embedding = pyq.Embedding(\n", + " # vparam_names=[\"x\"],\n", + " fparam_names=[\"x\"],\n", + " var_to_call={name1: fn1},\n", + " # var_to_call={name0: fn0, name1: fn1, name2: fn2, name3: fn3},\n", + ")\n", + "rx = pyq.RX(0, param_name=name1)\n", + "# cry = pyq.CRY(0, 1, param_name=name1)\n", + "# phase = pyq.PHASE(1, param_name=name2)\n", + "# ry = pyq.RY(1, param_name=name3)\n", + "# cnot = pyq.CNOT(1, 2)\n", + "ops = [rx]\n", + "# ops = [rx, cry, phase, ry, cnot]\n", + "n_qubits = 1\n", + "circ = pyq.QuantumCircuit(n_qubits, ops)\n", + "obs = pyq.Observable([pyq.Z(0)])\n", + "\n", + "state = pyq.zero_state(n_qubits)\n", + "\n", + "x = torch.tensor(0.1236, requires_grad=True) #torch.rand(1, requires_grad=True)\n", + "# y = torch.rand(1, requires_grad=True)\n", + "\n", + "values_ad = {\"x\": x}\n", + "embedded_params = embedding(values_ad)\n", + "exp_val = pyq.expectation(circ, state, embedded_params, obs, embedding=embedding)\n", + "\n", + "print(exp_val)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.zeros_like(torch.tensor(1.0))" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from importlib import import_module\n", + "a = import_module(\"pyqtorch.utils\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "heaviside() missing 2 required positional arguments: 'x' and 'vals'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[3], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43ma\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaviside\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mTypeError\u001b[0m: heaviside() missing 2 required positional arguments: 'x' and 'vals'" + ] + } + ], + "source": [ + "a.heaviside()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'x': tensor([0.3781], requires_grad=True),\n", + " 'y': tensor([0.0050], requires_grad=True),\n", + " 'fn0': tensor([0.3691], grad_fn=),\n", + " 'fn1': tensor([0.0019], grad_fn=),\n", + " 'fn2': tensor([0.0037], grad_fn=),\n", + " 'fn3': tensor([-5.5958], grad_fn=)}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "embedded_params" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from pyqtorch import zero_state\n", + "from pyqtorch.utils import SolverType" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "omega = 20.0\n", + "param_y = 2.0\n", + "param_x = 5.0\n", + "sigma_x = torch.tensor([[0.0, 1.0], [1.0, 0.0]])\n", + "sigma_y = torch.tensor([[0.0, -1.0j], [1.0j, 0.0]])\n", + "\n", + "\n", + "def hamiltonian_t(t: float) -> torch.Tensor:\n", + " t = torch.as_tensor(t)\n", + " return omega * (\n", + " param_y * torch.sin(t) * torch.kron(sigma_x, torch.eye(2))\n", + " + param_x * t**2 * torch.kron(torch.eye(2), sigma_y)\n", + " ).to(torch.complex128)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[0.0000+0.0000j, 0.0000-4.0000j, 7.9468+0.0000j, 0.0000+0.0000j],\n", + " [0.0000+4.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 7.9468+0.0000j],\n", + " [7.9468+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-4.0000j],\n", + " [0.0000+0.0000j, 7.9468+0.0000j, 0.0000+4.0000j, 0.0000+0.0000j]],\n", + " dtype=torch.complex128)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hamiltonian_t(0.2)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[[1.+0.j],\n", + " [0.+0.j]],\n", + "\n", + " [[0.+0.j],\n", + " [0.+0.j]]], dtype=torch.complex128)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "zero_state(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "import pyqtorch as pyq" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "sin_t, sin_fn = \"sin_t\", ConcretizedCallable(\"sin\", [\"t\"])\n", + "t_sq, t_sq_fn = \"t_sq\", ConcretizedCallable(\"mul\", [1.0, \"t\"])\n", + "\n", + "generator = pyq.Scale(\n", + " pyq.Add([\n", + " pyq.Scale(\n", + " pyq.Scale(\n", + " pyq.X(0),\n", + " sin_t\n", + " ),\n", + " param_y\n", + " ),\n", + " pyq.Scale(\n", + " pyq.Scale(\n", + " pyq.Y(1),\n", + " t_sq\n", + " ),\n", + " param_x\n", + " ),\n", + " ]),\n", + " omega)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.+1.j)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.tensor(-1+0j) ** 0.5" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "expr_pyq = pyq.sqrt(pyq.sin(\"x\")) + pyq.cos(\"r\") * (1.0 / pyq.log(\"z\") * \"y\")\n", + "# expr_pyq = pyq.cos(\"z\") ** pyq.log(1.5 / (1.0 + (2.0 * pyq.sin(\"x\")) + \"y\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "def get_funcs(expr, independent_args=set()):\n", + " fn_name = expr.call_name\n", + " # print(\"function:\", expr.call_name, \"; function argument\")\n", + " abstract_args = expr.abstract_args\n", + " print(f\"[{fn_name}] args: {[arg.call_name if isinstance(arg, ConcretizedCallable) else arg for arg in abstract_args]}\")\n", + " if len(abstract_args) == 1 and isinstance(abstract_args[0], str):\n", + " independent_args.add(abstract_args[0])\n", + " print(\"[0] independent arg:\", abstract_args[0])\n", + " print(\"---------------\")\n", + " else:\n", + " \n", + " for arg in abstract_args:\n", + " if isinstance(arg, ConcretizedCallable):\n", + " # print(\"function:\", arg.call_name)\n", + " get_funcs(arg)\n", + " else:\n", + " print(\"[1] independent arg:\", arg)\n", + " print('---------------')\n", + "\n", + " return independent_args\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "def _get_independent_args(cc: ConcretizedCallable) -> set:\n", + " # if out is None:\n", + " out = set()\n", + " if len(cc.abstract_args) == 1 and isinstance(cc.abstract_args[0], str):\n", + " print(\"independent arg:\", cc.abstract_args[0])\n", + " return set([cc.abstract_args[0]])\n", + " else:\n", + " # out = set()\n", + " for arg in cc.abstract_args:\n", + " if isinstance(arg, ConcretizedCallable):\n", + " res = _get_independent_args(arg)\n", + " print(\"got:\", res, \"out:\", out)\n", + " out.add(res)\n", + " else:\n", + " print(\"arg:\", arg, out)\n", + " if isinstance(arg, str):\n", + " out.add(arg)\n", + " return out" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[mul] args: [3.0, 'x']\n", + "[1] independent arg: 3.0\n", + "---------------\n", + "[1] independent arg: x\n", + "---------------\n" + ] + }, + { + "data": { + "text/plain": [ + "set()" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_funcs(cc)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "st = set()\n", + "st.add(\"a\")\n", + "st.add(\"b\")\n", + "st.add(\"a\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'a', 'b'}" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "st" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "arg: 3.0 set()\n", + "arg: x set()\n" + ] + }, + { + "data": { + "text/plain": [ + "{'x'}" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "_get_independent_args(cc)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['z', 'x', 'r']" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr_pyq.independent_args" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cc = ConcretizedCallable(\"mul\", [3.0, \"x\"])\n", + "cc.independent_args" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'get_funcs' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[12], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_funcs\u001b[49m(expr_pyq)\n", + "\u001b[0;31mNameError\u001b[0m: name 'get_funcs' is not defined" + ] + } + ], + "source": [ + "get_funcs(expr_pyq)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "from sympy import *\n", + "x, y, z = symbols('x y z')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"Pow(sin(Symbol('x')), Rational(1, 2))\"" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr_sympy = sqrt(sin(x))\n", + "# expr_sympy = cos(z) ** log(1.5 / (1.0 + (2 * sin(x)) + y))\n", + "srepr(expr_sympy)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9535708427429199" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vals = {\"x\": torch.tensor(2.0), \"y\": torch.tensor(0.5), \"z\": torch.tensor(0.2)}\n", + "expr_pyq(vals).item()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle 0.5$" + ], + "text/plain": [ + "0.500000000000000" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Rational(\"1/2\").evalf()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "$\\displaystyle 0.953570881909511$" + ], + "text/plain": [ + "0.953570881909511" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "expr_sympy.subs({x: vals[\"x\"], y: vals[\"y\"], z: vals[\"z\"]})" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "from functools import reduce, partial" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "mapping = {\n", + " Pow: \"pow\",\n", + " cos: \"cos\",\n", + " Add: \"add\",\n", + " Mul: \"mul\",\n", + " sin: \"sin\",\n", + " log: \"log\",\n", + " # sqrt: \"sqrt\",\n", + " # Rational: \n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "def sympy_to_pyq(expr):\n", + " print(\"recursion level start...\")\n", + " print(\"func:\", expr.func, \"|\", expr.args)\n", + "\n", + " if len(expr.args) == 0:\n", + " print(\"returning arg from base case:\")\n", + " res = float(expr) if str(expr).replace('.', '', 1).replace('-', '', 1).isdigit() else str(expr)\n", + " if isinstance(res, str):\n", + " if \"/\" in res:\n", + " # found a rational\n", + " res = float(Rational(res).evalf())\n", + " if \"fix\" in res:\n", + " # found a fixed parameter - convert to float\n", + " res = float(res.split(\"_\")[1])\n", + " print(res, type(res))\n", + " return res\n", + "\n", + " all_results = []\n", + " for i, arg in enumerate(expr.args):\n", + " print(f\"--- {i} all func args:\", expr.args)\n", + " res = sympy_to_pyq(arg)\n", + "\n", + " print(f\"[{i}] returned arg:\", res)\n", + "\n", + "\n", + " all_results.append(res)\n", + " \n", + " print(\"args:\")\n", + " print(all_results)\n", + "\n", + " # if isinstance(expr.func, Rational):\n", + "\n", + "\n", + " if len(all_results) > 2:\n", + " fn = lambda x, y: partial(ConcretizedCallable, call_name=mapping[expr.func])(abstract_args=[x, y])\n", + " cc = reduce(fn, all_results)\n", + " else:\n", + " # a = \", \".join(tmp) if len(tmp) > 1 else str(tmp[0])\n", + " cc = ConcretizedCallable(mapping[expr.func], all_results)\n", + "\n", + " print(\"Concretized callable object:\")\n", + " print(cc)\n", + " return cc" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "generator_qadence = omega * (y * sin(x) + x * (z**2))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "recursion level start...\n", + "func: | (20.0*x*z**2, 20.0*y*sin(x))\n", + "--- 0 all func args: (20.0*x*z**2, 20.0*y*sin(x))\n", + "recursion level start...\n", + "func: | (20.0000000000000, x, z**2)\n", + "--- 0 all func args: (20.0000000000000, x, z**2)\n", + "recursion level start...\n", + "func: | ()\n", + "returning arg from base case:\n", + "20.0 \n", + "[0] returned arg: 20.0\n", + "--- 1 all func args: (20.0000000000000, x, z**2)\n", + "recursion level start...\n", + "func: | ()\n", + "returning arg from base case:\n", + "x \n", + "[1] returned arg: x\n", + "--- 2 all func args: (20.0000000000000, x, z**2)\n", + "recursion level start...\n", + "func: | (z, 2)\n", + "--- 0 all func args: (z, 2)\n", + "recursion level start...\n", + "func: | ()\n", + "returning arg from base case:\n", + "z \n", + "[0] returned arg: z\n", + "--- 1 all func args: (z, 2)\n", + "recursion level start...\n", + "func: | ()\n", + "returning arg from base case:\n", + "2.0 \n", + "[1] returned arg: 2.0\n", + "args:\n", + "['z', 2.0]\n", + "Concretized callable object:\n", + "\n", + "[2] returned arg: \n", + "args:\n", + "[20.0, 'x', ]\n", + "Concretized callable object:\n", + "\n", + "[0] returned arg: \n", + "--- 1 all func args: (20.0*x*z**2, 20.0*y*sin(x))\n", + "recursion level start...\n", + "func: | (20.0000000000000, y, sin(x))\n", + "--- 0 all func args: (20.0000000000000, y, sin(x))\n", + "recursion level start...\n", + "func: | ()\n", + "returning arg from base case:\n", + "20.0 \n", + "[0] returned arg: 20.0\n", + "--- 1 all func args: (20.0000000000000, y, sin(x))\n", + "recursion level start...\n", + "func: | ()\n", + "returning arg from base case:\n", + "y \n", + "[1] returned arg: y\n", + "--- 2 all func args: (20.0000000000000, y, sin(x))\n", + "recursion level start...\n", + "func: sin | (x,)\n", + "--- 0 all func args: (x,)\n", + "recursion level start...\n", + "func: | ()\n", + "returning arg from base case:\n", + "x \n", + "[0] returned arg: x\n", + "args:\n", + "['x']\n", + "Concretized callable object:\n", + "\n", + "[2] returned arg: \n", + "args:\n", + "[20.0, 'y', ]\n", + "Concretized callable object:\n", + "\n", + "[1] returned arg: \n", + "args:\n", + "[, ]\n", + "Concretized callable object:\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "tensor(10.6930)" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cc = sympy_to_pyq(generator_qadence)\n", + "cc(vals)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "fn = lambda x, y: partial(ConcretizedCallable, call_name=\"add\")(abstract_args=[x, y])" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "add['x', 'y'])" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fn(*[\"x\", \"y\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "add[add['x', 'y']), 'z'])" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reduce(fn, [\"x\", \"y\", \"z\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[pow] args: ['cos', 'log']\n", + "[cos] args: ['z']\n", + "final arg: z\n", + "---------------\n", + "[log] args: ['mul']\n", + "[mul] args: [1.5, 'pow']\n", + "independent arg: 1.5\n", + "---------------\n", + "[pow] args: ['add', -1.0]\n", + "[add] args: [1.0, 'mul']\n", + "independent arg: 1.0\n", + "---------------\n", + "[mul] args: [2.0, 'sin']\n", + "independent arg: 2.0\n", + "---------------\n", + "[sin] args: ['x']\n", + "final arg: x\n", + "---------------\n", + "independent arg: -1.0\n", + "---------------\n" + ] + } + ], + "source": [ + "get_funcs(cc)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(1.0128)" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "op = pyq.Scale(pyq.X(0), sin_t)\n", + "\n", + "embedding = pyq.Embedding(\n", + " tparam_name=\"t\",\n", + " var_to_call={sin_t: sin_fn, t_sq: t_sq_fn},\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[0.0000+0.0000j, 0.0000-4.0000j, 7.9468+0.0000j, 0.0000+0.0000j],\n", + " [0.0000+4.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 7.9468+0.0000j],\n", + " [7.9468+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-4.0000j],\n", + " [0.0000+0.0000j, 7.9468+0.0000j, 0.0000+4.0000j, 0.0000+0.0000j]],\n", + " dtype=torch.complex128)" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vals = {\"t\": torch.tensor(0.2)}\n", + "generator.tensor(values=vals, embedding=embedding, full_support=[0,1]).reshape(4,4)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "embedded_params = embedding(vals)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[[0.0000+0.j],\n", + " [0.5985+0.j]],\n", + "\n", + " [[0.5985+0.j],\n", + " [0.0000+0.j]]], dtype=torch.complex128)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "op.tensor(values=embedded_params, embedding=embedding)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "from pyqtorch.primitives import Parametric" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def is_parametrized(operation: pyq.Sequence) -> bool:\n", + " params = []\n", + " for m in operation.modules():\n", + " if isinstance(m, (pyq.Scale, Parametric)):\n", + " params.append(m.param_name)\n", + "\n", + " res = False\n", + " if any([isinstance(p, str) for p in params]):\n", + " res = True\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "is_parametrized(pyq.Sequence([pyq.RX(0, \"x\"), pyq.RY(1, \"y\")]))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "a = (1, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "c, d = a" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "c" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[0.0000+0.0000j, 0.0000-4.0000j, 7.9468+0.0000j, 0.0000+0.0000j],\n", + " [0.0000+4.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 7.9468+0.0000j],\n", + " [7.9468+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-4.0000j],\n", + " [0.0000+0.0000j, 7.9468+0.0000j, 0.0000+4.0000j, 0.0000+0.0000j]],\n", + " dtype=torch.complex128)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "values = {\"t\": torch.tensor(0.3)}\n", + "\n", + "embedded_params = embedding(values)\n", + "\n", + "\n", + "reembedded_params = embedding.reembed_tparam(embedded_params, torch.tensor(0.2))\n", + "\n", + "generator.tensor(values=reembedded_params, embedding=embedding).reshape(4, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[-0.0951+0.0000j],\n", + " [-0.1566+0.0000j],\n", + " [ 0.0000-0.5102j],\n", + " [ 0.0000-0.8403j]], dtype=torch.complex128)\n" + ] + } + ], + "source": [ + "duration = 0.5\n", + "n_steps = 1000\n", + "\n", + "# simulate with torch-based solver\n", + "psi0_torch = zero_state(2).reshape(-1, 1)\n", + "t_points = torch.linspace(0, duration, n_steps)\n", + "state_torch = pyq.sesolve(hamiltonian_t, psi0_torch, t_points, SolverType.DP5_SE).states[-1]\n", + "print(state_torch)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Taking support from generator and ignoring qubit_support input.\n" + ] + }, + { + "ename": "KeyError", + "evalue": "'sin_x'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[21], line 15\u001b[0m\n\u001b[1;32m 12\u001b[0m time \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mtensor([\u001b[38;5;241m1.0\u001b[39m])\n\u001b[1;32m 13\u001b[0m time_symbol \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mt\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 15\u001b[0m hamiltonian_evolution \u001b[38;5;241m=\u001b[39m \u001b[43mHamiltonianEvolution\u001b[49m\u001b[43m(\u001b[49m\u001b[43mgenerator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mgenerator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtime\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtime_symbol\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mqubit_support\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mqubit_targets\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 16\u001b[0m \u001b[43m \u001b[49m\u001b[43mis_time_dependent\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mduration\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mduration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msteps\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mn_steps\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msolver\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mSolverType\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mDP5_SE\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;66;03m# Starting from a uniform state\u001b[39;00m\n\u001b[1;32m 19\u001b[0m psi_start \u001b[38;5;241m=\u001b[39m zero_state(n_qubits)\n", + "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/hamiltonians/evolution.py:194\u001b[0m, in \u001b[0;36mHamiltonianEvolution.__init__\u001b[0;34m(self, generator, time, qubit_support, generator_parametric, cache_length, is_time_dependent, duration, steps, solver)\u001b[0m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgenerator_type \u001b[38;5;241m=\u001b[39m GeneratorType\u001b[38;5;241m.\u001b[39mPARAMETRIC_OPERATION\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m generator \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m 193\u001b[0m Primitive(\n\u001b[0;32m--> 194\u001b[0m \u001b[43mgenerator\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 195\u001b[0m generator\u001b[38;5;241m.\u001b[39mqubit_support,\n\u001b[1;32m 196\u001b[0m )\n\u001b[1;32m 197\u001b[0m ]\n\u001b[1;32m 199\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgenerator_type \u001b[38;5;241m=\u001b[39m GeneratorType\u001b[38;5;241m.\u001b[39mOPERATION\n\u001b[1;32m 200\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:98\u001b[0m, in \u001b[0;36mScale.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 83\u001b[0m \u001b[38;5;124;03mGet the corresponding unitary over n_qubits.\u001b[39;00m\n\u001b[1;32m 84\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;124;03m The unitary representation.\u001b[39;00m\n\u001b[1;32m 92\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 93\u001b[0m scale \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 94\u001b[0m values[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name]\n\u001b[1;32m 95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name, \u001b[38;5;28mstr\u001b[39m)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name\n\u001b[1;32m 97\u001b[0m )\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m scale \u001b[38;5;241m*\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moperations\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:180\u001b[0m, in \u001b[0;36mAdd.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 173\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 174\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpanding tensor operation requires a `full_support` argument \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 175\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlarger than or equal to the `qubit_support`.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 176\u001b[0m )\n\u001b[1;32m 177\u001b[0m mat \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mzeros(\n\u001b[1;32m 178\u001b[0m (\u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m1\u001b[39m), device\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice\n\u001b[1;32m 179\u001b[0m )\n\u001b[0;32m--> 180\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mreduce\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43madd\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[43mop\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mop\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moperations\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mmat\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 184\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:182\u001b[0m, in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 173\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 174\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpanding tensor operation requires a `full_support` argument \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 175\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlarger than or equal to the `qubit_support`.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 176\u001b[0m )\n\u001b[1;32m 177\u001b[0m mat \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mzeros(\n\u001b[1;32m 178\u001b[0m (\u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m1\u001b[39m), device\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice\n\u001b[1;32m 179\u001b[0m )\n\u001b[1;32m 180\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m reduce(\n\u001b[1;32m 181\u001b[0m add,\n\u001b[0;32m--> 182\u001b[0m (\u001b[43mop\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m op \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moperations),\n\u001b[1;32m 183\u001b[0m mat,\n\u001b[1;32m 184\u001b[0m )\n", + "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:98\u001b[0m, in \u001b[0;36mScale.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 83\u001b[0m \u001b[38;5;124;03mGet the corresponding unitary over n_qubits.\u001b[39;00m\n\u001b[1;32m 84\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;124;03m The unitary representation.\u001b[39;00m\n\u001b[1;32m 92\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 93\u001b[0m scale \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 94\u001b[0m values[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name]\n\u001b[1;32m 95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name, \u001b[38;5;28mstr\u001b[39m)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name\n\u001b[1;32m 97\u001b[0m )\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m scale \u001b[38;5;241m*\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moperations\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:94\u001b[0m, in \u001b[0;36mScale.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 76\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtensor\u001b[39m(\n\u001b[1;32m 77\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 78\u001b[0m values: \u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Tensor] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mdict\u001b[39m(),\n\u001b[1;32m 79\u001b[0m embedding: Embedding \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 80\u001b[0m full_support: \u001b[38;5;28mtuple\u001b[39m[\u001b[38;5;28mint\u001b[39m, \u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 81\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Operator:\n\u001b[1;32m 82\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 83\u001b[0m \u001b[38;5;124;03m Get the corresponding unitary over n_qubits.\u001b[39;00m\n\u001b[1;32m 84\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;124;03m The unitary representation.\u001b[39;00m\n\u001b[1;32m 92\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m 93\u001b[0m scale \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m---> 94\u001b[0m \u001b[43mvalues\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparam_name\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name, \u001b[38;5;28mstr\u001b[39m)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name\n\u001b[1;32m 97\u001b[0m )\n\u001b[1;32m 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m scale \u001b[38;5;241m*\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moperations[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39mtensor(values, embedding, full_support)\n", + "\u001b[0;31mKeyError\u001b[0m: 'sin_x'" + ] + } + ], + "source": [ + "import torch\n", + "from pyqtorch import uniform_state, HamiltonianEvolution\n", + "from pyqtorch.matrices import DEFAULT_MATRIX_DTYPE\n", + "\n", + "n_qubits = 2\n", + "qubit_targets = list(range(n_qubits))\n", + "\n", + "# Random hermitian hamiltonian\n", + "matrix = torch.rand(2**n_qubits, 2**n_qubits, dtype=DEFAULT_MATRIX_DTYPE)\n", + "hermitian_matrix = matrix + matrix.T.conj()\n", + "\n", + "time = torch.tensor([1.0])\n", + "time_symbol = \"t\"\n", + "\n", + "hamiltonian_evolution = HamiltonianEvolution(generator=generator, time=time_symbol, qubit_support=qubit_targets, \n", + " is_time_dependent=True, duration=duration, steps=n_steps, solver=SolverType.DP5_SE)\n", + "\n", + "# Starting from a uniform state\n", + "psi_start = zero_state(n_qubits)\n", + "\n", + "# Returns the evolved state\n", + "psi_end = hamiltonian_evolution(state=psi_start, values={time_symbol: time}, embedding=embedding)\n", + "\n", + "print(psi_end)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.1987)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"/home/vytautas/Downloads/task_all_annotations_2024_08_26_07_25_47_coco 1 (1).0/annotations/instances_all.json\", \"r\") as f:\n", + " a = json.load(f)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'id': 1, 'name': 'lav', 'supercategory': ''},\n", + " {'id': 2, 'name': 'civ-car', 'supercategory': ''},\n", + " {'id': 3, 'name': 'infantry', 'supercategory': ''},\n", + " {'id': 4, 'name': 'mlrs', 'supercategory': ''},\n", + " {'id': 5, 'name': 'Tank', 'supercategory': ''},\n", + " {'id': 6, 'name': 'Truck', 'supercategory': ''},\n", + " {'id': 7, 'name': 'apc', 'supercategory': ''},\n", + " {'id': 8, 'name': 'army-truck', 'supercategory': ''},\n", + " {'id': 9, 'name': 'artillery-gun', 'supercategory': ''},\n", + " {'id': 10, 'name': 'car', 'supercategory': ''},\n", + " {'id': 11, 'name': 'humvee', 'supercategory': ''},\n", + " {'id': 12, 'name': 'military-vehicle', 'supercategory': ''},\n", + " {'id': 13, 'name': 'person', 'supercategory': ''},\n", + " {'id': 14, 'name': 'pickup', 'supercategory': ''},\n", + " {'id': 15, 'name': 'rocket-artillery', 'supercategory': ''},\n", + " {'id': 16, 'name': 'soldier', 'supercategory': ''},\n", + " {'id': 17, 'name': 'tank', 'supercategory': ''},\n", + " {'id': 18, 'name': 'truck', 'supercategory': ''},\n", + " {'id': 19, 'name': 'van', 'supercategory': ''},\n", + " {'id': 20, 'name': 'vehicle', 'supercategory': ''}]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a[\"categories\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "for annot in a[\"annotations\"]:\n", + " if annot[\"category_id\"] == 10:\n", + " annot[\"category_id\"] = 2" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "with open(\"/home/vytautas/Downloads/task_all_annotations_2024_08_26_07_25_47_coco 1 (1).0/annotations/instances_all.json\", \"w\") as f:\n", + " json.dump(a, f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pyqtorch", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/to_delete.py b/to_delete.py new file mode 100644 index 00000000..ba26b8cd --- /dev/null +++ b/to_delete.py @@ -0,0 +1,202 @@ +from __future__ import annotations + +import json + +import matplotlib.pyplot as plt +import numpy as np +import qutip +from scipy.interpolate import UnivariateSpline +from whittaker_eilers import WhittakerSmoother + +# user parameters +SMOOTH_LMBDA = 5e-2 +SMOOTH_ORDER = 2 +INTERPOLATE_K = 5 +INTERPOLATE_S = 0.01 + +# parameters and device specs +PATH = "EXPERIMENTS/2024-fresnel-dqc-qel-rerun/agpsr-publication/" +THETA3S = [ + 0.70, + 1.40, + 2.09, + 2.79, + 3.49, + 4.19, + 4.88, + 5.58, + 6.28, +] +QEL_THETA3S_IDX = 3 +PULSE_AMPLITUDE = 9 +MIN_DURATION = 16 +SHIFTS = np.array([2.4699029, 0.90160249]) +X_POINTS = np.linspace( + MIN_DURATION * PULSE_AMPLITUDE / 1000 + max(SHIFTS), + MIN_DURATION * PULSE_AMPLITUDE / 1000 + max(SHIFTS) + 5, + 8, +) # points at which derivatives are to be calculated +QEL_X_POINTS = [ + 4.5186648, + 4.99485528, + 5.23295051, + 5.709141, + 5.94723624, +] # additional points at which derivatives are to be calculated when θ_3=2.79 +C6 = 865723.02 +DURATION_TO_ANGLE = PULSE_AMPLITUDE / 1000 + + +# generator corresponding to a global pulse, specialized for two atoms 5*sqrt(3)um apart +def multi_qubit_rotation_generator(omega: float): + n_qubits = 2 + + # create rotation operators + op_A = [] + for i in range(n_qubits): + prod = [qutip.qeye(2) for _ in range(n_qubits)] + prod[i] = omega / 2 * qutip.sigmax() + op_A.append(qutip.tensor(prod)) + A = sum(op_A) + + # create interaction operators + prod = [(1 + qutip.sigmaz()) / 2, (1 + qutip.sigmaz()) / 2] + r_ij = 5 * np.sqrt(3) + J_ij = C6 / (r_ij**6) + B = J_ij * qutip.tensor(prod) + + # construct generator + G = (A + B) * (2.0 / omega) + + return G + + +def plot_all(): + # SETUP FOR GPSR + # find unique eigenvalue differences + _G = multi_qubit_rotation_generator(omega=PULSE_AMPLITUDE) + print("Generator :", _G) + _eigenvals = _G.eigenenergies() + _diffs = np.round(_eigenvals - _eigenvals.reshape(-1, 1), 7) + _unique_diffs = np.abs(np.unique(np.tril(_diffs))) + _unique_diffs = _unique_diffs[_unique_diffs > 0] + print("Unique eigenvalues differences:", _unique_diffs) + print( + f"Shifts {SHIFTS} used to obtain QPU data was optimized for [4.032524 1.9007948]" + ) + UNIQUE_EVAL_DIFFS = np.array([_unique_diffs[0], _unique_diffs[-2]]) + print("Eigenvalues differences used:", UNIQUE_EVAL_DIFFS) + # calculate M_INV matrix + _M = np.empty((2, 2)) + for i in range(2): + for j in range(2): + _M[i, j] = 4 * np.sin(SHIFTS[i] * UNIQUE_EVAL_DIFFS[j] / 2) + M_INV = np.linalg.pinv(_M) + + # PLOT FOR EACH θ_3 VALUE + fig, _ = plt.subplots(3, 3, sharex=True) + for i in range(len(THETA3S)): + theta3 = THETA3S[i] + if theta3 == THETA3S[QEL_THETA3S_IDX]: + x_pts_for_derivative = np.sort(np.hstack((X_POINTS, QEL_X_POINTS))) + else: + x_pts_for_derivative = X_POINTS + + # LOAD DATA + with open(f"{PATH}data_{theta3}.json", "r") as file: + json_data = json.load(file) + data = np.array( + [ + [item["duration"] * DURATION_TO_ANGLE, item["f"], item["err_f"]] + for item in json_data + ] + ) + + # GPSR + dfdx_GPSR = [] + + def closest_x_index(x: float): + difference_array = np.absolute(data[:, 0] - x) + index = difference_array.argmin() + # print(difference_array[index]) + return index + + for x_v in x_pts_for_derivative: + f1u = data[closest_x_index(x_v + SHIFTS[0]), 1] + f1l = data[closest_x_index(x_v - SHIFTS[0]), 1] + f2u = data[closest_x_index(x_v + SHIFTS[1]), 1] + f2l = data[closest_x_index(x_v - SHIFTS[1]), 1] + F = np.array([f1u - f1l, f2u - f2l]) + dfdx_v = np.sum(UNIQUE_EVAL_DIFFS * np.dot(M_INV, F)) + dfdx_GPSR.append(dfdx_v) + + whittaker_smoother = WhittakerSmoother( + lmbda=SMOOTH_LMBDA, + order=SMOOTH_ORDER, + data_length=len(data[:, 1]), + x_input=data[:, 0], + ) + smoothed_data = whittaker_smoother.smooth(data[:, 1]) + interpolation = UnivariateSpline( + data[:, 0], smoothed_data, k=INTERPOLATE_K, s=INTERPOLATE_S + ) + derivative = interpolation.derivative() + + ax = fig.axes[i] + ax.errorbar( + data[:, 0], + data[:, 1], + data[:, 2], + label="Experiment", + color="tab:blue", + linestyle="none", + marker="o", + ms=2, + ) + ax.plot( + data[:, 0], + smoothed_data, + label="Smoothed", + color="tab:green", + marker="o", + ms=4, + ) + ax.plot( + x_pts_for_derivative, + dfdx_GPSR, + label="GPSR", + color="tab:orange", + marker="o", + ms=4, + ) + x_v = np.linspace(min(data[:, 0]), max(data[:, 0]), 300) + x_v_derivative = np.linspace(min(X_POINTS), max(X_POINTS), 200) + ax.plot( + x_v, + interpolation(x_v), + label="Interpolation", + color="tab:red", + ) + ax.plot( + x_v_derivative, + derivative(x_v_derivative), + label="Derivative of interpolation", + color="tab:pink", + ) + + ax.text( + 0.01, + 0.99, + "$θ_3$ = " + f"{theta3}", + ha="left", + va="top", + transform=ax.transAxes, + ) + + handles, labels = fig.axes[0].get_legend_handles_labels() + fig.legend(handles, labels) + plt.show() + + +if __name__ == "__main__": + plot_all() From 736d05e446a507959904e674a3441ffe5a36c835 Mon Sep 17 00:00:00 2001 From: Vytautas Abramavicius Date: Fri, 15 Nov 2024 12:27:26 +0200 Subject: [PATCH 2/4] removed unnecessary files --- to_delete.ipynb | 1324 ----------------------------------------------- to_delete.py | 202 -------- 2 files changed, 1526 deletions(-) delete mode 100644 to_delete.ipynb delete mode 100644 to_delete.py diff --git a/to_delete.ipynb b/to_delete.ipynb deleted file mode 100644 index 00cc9aff..00000000 --- a/to_delete.ipynb +++ /dev/null @@ -1,1324 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "PyQTorch logger successfully setup with log level 20\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "tensor([0.9320], dtype=torch.float64, grad_fn=)\n" - ] - } - ], - "source": [ - "import torch\n", - "import torch.autograd.gradcheck\n", - "\n", - "import pyqtorch as pyq\n", - "from pyqtorch.embed import ConcretizedCallable, Embedding\n", - "# name0, fn0 = \"fn0\", ConcretizedCallable(\"sin\", [\"x\"])\n", - "name1, fn1 = \"fn1\", ConcretizedCallable(\"mul\", [3, \"x\"])\n", - "# name2, fn2 = \"fn2\", ConcretizedCallable(\"mul\", [\"fn1\", 2.0])\n", - "# name3, fn3 = \"fn3\", ConcretizedCallable(\"log\", [\"fn2\"])\n", - "embedding = pyq.Embedding(\n", - " # vparam_names=[\"x\"],\n", - " fparam_names=[\"x\"],\n", - " var_to_call={name1: fn1},\n", - " # var_to_call={name0: fn0, name1: fn1, name2: fn2, name3: fn3},\n", - ")\n", - "rx = pyq.RX(0, param_name=name1)\n", - "# cry = pyq.CRY(0, 1, param_name=name1)\n", - "# phase = pyq.PHASE(1, param_name=name2)\n", - "# ry = pyq.RY(1, param_name=name3)\n", - "# cnot = pyq.CNOT(1, 2)\n", - "ops = [rx]\n", - "# ops = [rx, cry, phase, ry, cnot]\n", - "n_qubits = 1\n", - "circ = pyq.QuantumCircuit(n_qubits, ops)\n", - "obs = pyq.Observable([pyq.Z(0)])\n", - "\n", - "state = pyq.zero_state(n_qubits)\n", - "\n", - "x = torch.tensor(0.1236, requires_grad=True) #torch.rand(1, requires_grad=True)\n", - "# y = torch.rand(1, requires_grad=True)\n", - "\n", - "values_ad = {\"x\": x}\n", - "embedded_params = embedding(values_ad)\n", - "exp_val = pyq.expectation(circ, state, embedded_params, obs, embedding=embedding)\n", - "\n", - "print(exp_val)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor(0.)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "torch.zeros_like(torch.tensor(1.0))" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from importlib import import_module\n", - "a = import_module(\"pyqtorch.utils\")" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "heaviside() missing 2 required positional arguments: 'x' and 'vals'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43ma\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaviside\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", - "\u001b[0;31mTypeError\u001b[0m: heaviside() missing 2 required positional arguments: 'x' and 'vals'" - ] - } - ], - "source": [ - "a.heaviside()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'x': tensor([0.3781], requires_grad=True),\n", - " 'y': tensor([0.0050], requires_grad=True),\n", - " 'fn0': tensor([0.3691], grad_fn=),\n", - " 'fn1': tensor([0.0019], grad_fn=),\n", - " 'fn2': tensor([0.0037], grad_fn=),\n", - " 'fn3': tensor([-5.5958], grad_fn=)}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embedded_params" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from pyqtorch import zero_state\n", - "from pyqtorch.utils import SolverType" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "omega = 20.0\n", - "param_y = 2.0\n", - "param_x = 5.0\n", - "sigma_x = torch.tensor([[0.0, 1.0], [1.0, 0.0]])\n", - "sigma_y = torch.tensor([[0.0, -1.0j], [1.0j, 0.0]])\n", - "\n", - "\n", - "def hamiltonian_t(t: float) -> torch.Tensor:\n", - " t = torch.as_tensor(t)\n", - " return omega * (\n", - " param_y * torch.sin(t) * torch.kron(sigma_x, torch.eye(2))\n", - " + param_x * t**2 * torch.kron(torch.eye(2), sigma_y)\n", - " ).to(torch.complex128)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([[0.0000+0.0000j, 0.0000-4.0000j, 7.9468+0.0000j, 0.0000+0.0000j],\n", - " [0.0000+4.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 7.9468+0.0000j],\n", - " [7.9468+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-4.0000j],\n", - " [0.0000+0.0000j, 7.9468+0.0000j, 0.0000+4.0000j, 0.0000+0.0000j]],\n", - " dtype=torch.complex128)" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "hamiltonian_t(0.2)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([[[1.+0.j],\n", - " [0.+0.j]],\n", - "\n", - " [[0.+0.j],\n", - " [0.+0.j]]], dtype=torch.complex128)" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "zero_state(2)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "import pyqtorch as pyq" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "sin_t, sin_fn = \"sin_t\", ConcretizedCallable(\"sin\", [\"t\"])\n", - "t_sq, t_sq_fn = \"t_sq\", ConcretizedCallable(\"mul\", [1.0, \"t\"])\n", - "\n", - "generator = pyq.Scale(\n", - " pyq.Add([\n", - " pyq.Scale(\n", - " pyq.Scale(\n", - " pyq.X(0),\n", - " sin_t\n", - " ),\n", - " param_y\n", - " ),\n", - " pyq.Scale(\n", - " pyq.Scale(\n", - " pyq.Y(1),\n", - " t_sq\n", - " ),\n", - " param_x\n", - " ),\n", - " ]),\n", - " omega)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from " - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor(0.+1.j)" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "torch.tensor(-1+0j) ** 0.5" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "expr_pyq = pyq.sqrt(pyq.sin(\"x\")) + pyq.cos(\"r\") * (1.0 / pyq.log(\"z\") * \"y\")\n", - "# expr_pyq = pyq.cos(\"z\") ** pyq.log(1.5 / (1.0 + (2.0 * pyq.sin(\"x\")) + \"y\"))" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "def get_funcs(expr, independent_args=set()):\n", - " fn_name = expr.call_name\n", - " # print(\"function:\", expr.call_name, \"; function argument\")\n", - " abstract_args = expr.abstract_args\n", - " print(f\"[{fn_name}] args: {[arg.call_name if isinstance(arg, ConcretizedCallable) else arg for arg in abstract_args]}\")\n", - " if len(abstract_args) == 1 and isinstance(abstract_args[0], str):\n", - " independent_args.add(abstract_args[0])\n", - " print(\"[0] independent arg:\", abstract_args[0])\n", - " print(\"---------------\")\n", - " else:\n", - " \n", - " for arg in abstract_args:\n", - " if isinstance(arg, ConcretizedCallable):\n", - " # print(\"function:\", arg.call_name)\n", - " get_funcs(arg)\n", - " else:\n", - " print(\"[1] independent arg:\", arg)\n", - " print('---------------')\n", - "\n", - " return independent_args\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "def _get_independent_args(cc: ConcretizedCallable) -> set:\n", - " # if out is None:\n", - " out = set()\n", - " if len(cc.abstract_args) == 1 and isinstance(cc.abstract_args[0], str):\n", - " print(\"independent arg:\", cc.abstract_args[0])\n", - " return set([cc.abstract_args[0]])\n", - " else:\n", - " # out = set()\n", - " for arg in cc.abstract_args:\n", - " if isinstance(arg, ConcretizedCallable):\n", - " res = _get_independent_args(arg)\n", - " print(\"got:\", res, \"out:\", out)\n", - " out.add(res)\n", - " else:\n", - " print(\"arg:\", arg, out)\n", - " if isinstance(arg, str):\n", - " out.add(arg)\n", - " return out" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[mul] args: [3.0, 'x']\n", - "[1] independent arg: 3.0\n", - "---------------\n", - "[1] independent arg: x\n", - "---------------\n" - ] - }, - { - "data": { - "text/plain": [ - "set()" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "get_funcs(cc)" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "st = set()\n", - "st.add(\"a\")\n", - "st.add(\"b\")\n", - "st.add(\"a\")" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'a', 'b'}" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "st" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "arg: 3.0 set()\n", - "arg: x set()\n" - ] - }, - { - "data": { - "text/plain": [ - "{'x'}" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "_get_independent_args(cc)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['z', 'x', 'r']" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr_pyq.independent_args" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cc = ConcretizedCallable(\"mul\", [3.0, \"x\"])\n", - "cc.independent_args" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'get_funcs' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[12], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mget_funcs\u001b[49m(expr_pyq)\n", - "\u001b[0;31mNameError\u001b[0m: name 'get_funcs' is not defined" - ] - } - ], - "source": [ - "get_funcs(expr_pyq)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "from sympy import *\n", - "x, y, z = symbols('x y z')" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Pow(sin(Symbol('x')), Rational(1, 2))\"" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr_sympy = sqrt(sin(x))\n", - "# expr_sympy = cos(z) ** log(1.5 / (1.0 + (2 * sin(x)) + y))\n", - "srepr(expr_sympy)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.9535708427429199" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "vals = {\"x\": torch.tensor(2.0), \"y\": torch.tensor(0.5), \"z\": torch.tensor(0.2)}\n", - "expr_pyq(vals).item()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle 0.5$" - ], - "text/plain": [ - "0.500000000000000" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Rational(\"1/2\").evalf()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/latex": [ - "$\\displaystyle 0.953570881909511$" - ], - "text/plain": [ - "0.953570881909511" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "expr_sympy.subs({x: vals[\"x\"], y: vals[\"y\"], z: vals[\"z\"]})" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "from functools import reduce, partial" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "mapping = {\n", - " Pow: \"pow\",\n", - " cos: \"cos\",\n", - " Add: \"add\",\n", - " Mul: \"mul\",\n", - " sin: \"sin\",\n", - " log: \"log\",\n", - " # sqrt: \"sqrt\",\n", - " # Rational: \n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "def sympy_to_pyq(expr):\n", - " print(\"recursion level start...\")\n", - " print(\"func:\", expr.func, \"|\", expr.args)\n", - "\n", - " if len(expr.args) == 0:\n", - " print(\"returning arg from base case:\")\n", - " res = float(expr) if str(expr).replace('.', '', 1).replace('-', '', 1).isdigit() else str(expr)\n", - " if isinstance(res, str):\n", - " if \"/\" in res:\n", - " # found a rational\n", - " res = float(Rational(res).evalf())\n", - " if \"fix\" in res:\n", - " # found a fixed parameter - convert to float\n", - " res = float(res.split(\"_\")[1])\n", - " print(res, type(res))\n", - " return res\n", - "\n", - " all_results = []\n", - " for i, arg in enumerate(expr.args):\n", - " print(f\"--- {i} all func args:\", expr.args)\n", - " res = sympy_to_pyq(arg)\n", - "\n", - " print(f\"[{i}] returned arg:\", res)\n", - "\n", - "\n", - " all_results.append(res)\n", - " \n", - " print(\"args:\")\n", - " print(all_results)\n", - "\n", - " # if isinstance(expr.func, Rational):\n", - "\n", - "\n", - " if len(all_results) > 2:\n", - " fn = lambda x, y: partial(ConcretizedCallable, call_name=mapping[expr.func])(abstract_args=[x, y])\n", - " cc = reduce(fn, all_results)\n", - " else:\n", - " # a = \", \".join(tmp) if len(tmp) > 1 else str(tmp[0])\n", - " cc = ConcretizedCallable(mapping[expr.func], all_results)\n", - "\n", - " print(\"Concretized callable object:\")\n", - " print(cc)\n", - " return cc" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "generator_qadence = omega * (y * sin(x) + x * (z**2))" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "recursion level start...\n", - "func: | (20.0*x*z**2, 20.0*y*sin(x))\n", - "--- 0 all func args: (20.0*x*z**2, 20.0*y*sin(x))\n", - "recursion level start...\n", - "func: | (20.0000000000000, x, z**2)\n", - "--- 0 all func args: (20.0000000000000, x, z**2)\n", - "recursion level start...\n", - "func: | ()\n", - "returning arg from base case:\n", - "20.0 \n", - "[0] returned arg: 20.0\n", - "--- 1 all func args: (20.0000000000000, x, z**2)\n", - "recursion level start...\n", - "func: | ()\n", - "returning arg from base case:\n", - "x \n", - "[1] returned arg: x\n", - "--- 2 all func args: (20.0000000000000, x, z**2)\n", - "recursion level start...\n", - "func: | (z, 2)\n", - "--- 0 all func args: (z, 2)\n", - "recursion level start...\n", - "func: | ()\n", - "returning arg from base case:\n", - "z \n", - "[0] returned arg: z\n", - "--- 1 all func args: (z, 2)\n", - "recursion level start...\n", - "func: | ()\n", - "returning arg from base case:\n", - "2.0 \n", - "[1] returned arg: 2.0\n", - "args:\n", - "['z', 2.0]\n", - "Concretized callable object:\n", - "\n", - "[2] returned arg: \n", - "args:\n", - "[20.0, 'x', ]\n", - "Concretized callable object:\n", - "\n", - "[0] returned arg: \n", - "--- 1 all func args: (20.0*x*z**2, 20.0*y*sin(x))\n", - "recursion level start...\n", - "func: | (20.0000000000000, y, sin(x))\n", - "--- 0 all func args: (20.0000000000000, y, sin(x))\n", - "recursion level start...\n", - "func: | ()\n", - "returning arg from base case:\n", - "20.0 \n", - "[0] returned arg: 20.0\n", - "--- 1 all func args: (20.0000000000000, y, sin(x))\n", - "recursion level start...\n", - "func: | ()\n", - "returning arg from base case:\n", - "y \n", - "[1] returned arg: y\n", - "--- 2 all func args: (20.0000000000000, y, sin(x))\n", - "recursion level start...\n", - "func: sin | (x,)\n", - "--- 0 all func args: (x,)\n", - "recursion level start...\n", - "func: | ()\n", - "returning arg from base case:\n", - "x \n", - "[0] returned arg: x\n", - "args:\n", - "['x']\n", - "Concretized callable object:\n", - "\n", - "[2] returned arg: \n", - "args:\n", - "[20.0, 'y', ]\n", - "Concretized callable object:\n", - "\n", - "[1] returned arg: \n", - "args:\n", - "[, ]\n", - "Concretized callable object:\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "tensor(10.6930)" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cc = sympy_to_pyq(generator_qadence)\n", - "cc(vals)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "fn = lambda x, y: partial(ConcretizedCallable, call_name=\"add\")(abstract_args=[x, y])" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "add['x', 'y'])" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fn(*[\"x\", \"y\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "add[add['x', 'y']), 'z'])" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "reduce(fn, [\"x\", \"y\", \"z\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[pow] args: ['cos', 'log']\n", - "[cos] args: ['z']\n", - "final arg: z\n", - "---------------\n", - "[log] args: ['mul']\n", - "[mul] args: [1.5, 'pow']\n", - "independent arg: 1.5\n", - "---------------\n", - "[pow] args: ['add', -1.0]\n", - "[add] args: [1.0, 'mul']\n", - "independent arg: 1.0\n", - "---------------\n", - "[mul] args: [2.0, 'sin']\n", - "independent arg: 2.0\n", - "---------------\n", - "[sin] args: ['x']\n", - "final arg: x\n", - "---------------\n", - "independent arg: -1.0\n", - "---------------\n" - ] - } - ], - "source": [ - "get_funcs(cc)" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor(1.0128)" - ] - }, - "execution_count": 68, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "op = pyq.Scale(pyq.X(0), sin_t)\n", - "\n", - "embedding = pyq.Embedding(\n", - " tparam_name=\"t\",\n", - " var_to_call={sin_t: sin_fn, t_sq: t_sq_fn},\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([[0.0000+0.0000j, 0.0000-4.0000j, 7.9468+0.0000j, 0.0000+0.0000j],\n", - " [0.0000+4.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 7.9468+0.0000j],\n", - " [7.9468+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-4.0000j],\n", - " [0.0000+0.0000j, 7.9468+0.0000j, 0.0000+4.0000j, 0.0000+0.0000j]],\n", - " dtype=torch.complex128)" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "vals = {\"t\": torch.tensor(0.2)}\n", - "generator.tensor(values=vals, embedding=embedding, full_support=[0,1]).reshape(4,4)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "embedded_params = embedding(vals)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([[[0.0000+0.j],\n", - " [0.5985+0.j]],\n", - "\n", - " [[0.5985+0.j],\n", - " [0.0000+0.j]]], dtype=torch.complex128)" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "op.tensor(values=embedded_params, embedding=embedding)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "from pyqtorch.primitives import Parametric" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "def is_parametrized(operation: pyq.Sequence) -> bool:\n", - " params = []\n", - " for m in operation.modules():\n", - " if isinstance(m, (pyq.Scale, Parametric)):\n", - " params.append(m.param_name)\n", - "\n", - " res = False\n", - " if any([isinstance(p, str) for p in params]):\n", - " res = True\n", - " return res" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "is_parametrized(pyq.Sequence([pyq.RX(0, \"x\"), pyq.RY(1, \"y\")]))" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "a = (1, 2)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "c, d = a" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "c" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([[0.0000+0.0000j, 0.0000-4.0000j, 7.9468+0.0000j, 0.0000+0.0000j],\n", - " [0.0000+4.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 7.9468+0.0000j],\n", - " [7.9468+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-4.0000j],\n", - " [0.0000+0.0000j, 7.9468+0.0000j, 0.0000+4.0000j, 0.0000+0.0000j]],\n", - " dtype=torch.complex128)" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "values = {\"t\": torch.tensor(0.3)}\n", - "\n", - "embedded_params = embedding(values)\n", - "\n", - "\n", - "reembedded_params = embedding.reembed_tparam(embedded_params, torch.tensor(0.2))\n", - "\n", - "generator.tensor(values=reembedded_params, embedding=embedding).reshape(4, 4)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "tensor([[-0.0951+0.0000j],\n", - " [-0.1566+0.0000j],\n", - " [ 0.0000-0.5102j],\n", - " [ 0.0000-0.8403j]], dtype=torch.complex128)\n" - ] - } - ], - "source": [ - "duration = 0.5\n", - "n_steps = 1000\n", - "\n", - "# simulate with torch-based solver\n", - "psi0_torch = zero_state(2).reshape(-1, 1)\n", - "t_points = torch.linspace(0, duration, n_steps)\n", - "state_torch = pyq.sesolve(hamiltonian_t, psi0_torch, t_points, SolverType.DP5_SE).states[-1]\n", - "print(state_torch)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Taking support from generator and ignoring qubit_support input.\n" - ] - }, - { - "ename": "KeyError", - "evalue": "'sin_x'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[21], line 15\u001b[0m\n\u001b[1;32m 12\u001b[0m time \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mtensor([\u001b[38;5;241m1.0\u001b[39m])\n\u001b[1;32m 13\u001b[0m time_symbol \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mt\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 15\u001b[0m hamiltonian_evolution \u001b[38;5;241m=\u001b[39m \u001b[43mHamiltonianEvolution\u001b[49m\u001b[43m(\u001b[49m\u001b[43mgenerator\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mgenerator\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtime\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtime_symbol\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mqubit_support\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mqubit_targets\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 16\u001b[0m \u001b[43m \u001b[49m\u001b[43mis_time_dependent\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mduration\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mduration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msteps\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mn_steps\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msolver\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mSolverType\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mDP5_SE\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;66;03m# Starting from a uniform state\u001b[39;00m\n\u001b[1;32m 19\u001b[0m psi_start \u001b[38;5;241m=\u001b[39m zero_state(n_qubits)\n", - "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/hamiltonians/evolution.py:194\u001b[0m, in \u001b[0;36mHamiltonianEvolution.__init__\u001b[0;34m(self, generator, time, qubit_support, generator_parametric, cache_length, is_time_dependent, duration, steps, solver)\u001b[0m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgenerator_type \u001b[38;5;241m=\u001b[39m GeneratorType\u001b[38;5;241m.\u001b[39mPARAMETRIC_OPERATION\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m generator \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m 193\u001b[0m Primitive(\n\u001b[0;32m--> 194\u001b[0m \u001b[43mgenerator\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 195\u001b[0m generator\u001b[38;5;241m.\u001b[39mqubit_support,\n\u001b[1;32m 196\u001b[0m )\n\u001b[1;32m 197\u001b[0m ]\n\u001b[1;32m 199\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mgenerator_type \u001b[38;5;241m=\u001b[39m GeneratorType\u001b[38;5;241m.\u001b[39mOPERATION\n\u001b[1;32m 200\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", - "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:98\u001b[0m, in \u001b[0;36mScale.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 83\u001b[0m \u001b[38;5;124;03mGet the corresponding unitary over n_qubits.\u001b[39;00m\n\u001b[1;32m 84\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;124;03m The unitary representation.\u001b[39;00m\n\u001b[1;32m 92\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 93\u001b[0m scale \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 94\u001b[0m values[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name]\n\u001b[1;32m 95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name, \u001b[38;5;28mstr\u001b[39m)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name\n\u001b[1;32m 97\u001b[0m )\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m scale \u001b[38;5;241m*\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moperations\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:180\u001b[0m, in \u001b[0;36mAdd.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 173\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 174\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpanding tensor operation requires a `full_support` argument \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 175\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlarger than or equal to the `qubit_support`.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 176\u001b[0m )\n\u001b[1;32m 177\u001b[0m mat \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mzeros(\n\u001b[1;32m 178\u001b[0m (\u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m1\u001b[39m), device\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice\n\u001b[1;32m 179\u001b[0m )\n\u001b[0;32m--> 180\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mreduce\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 181\u001b[0m \u001b[43m \u001b[49m\u001b[43madd\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 182\u001b[0m \u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[43mop\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mop\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moperations\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 183\u001b[0m \u001b[43m \u001b[49m\u001b[43mmat\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 184\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:182\u001b[0m, in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 173\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 174\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpanding tensor operation requires a `full_support` argument \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 175\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlarger than or equal to the `qubit_support`.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 176\u001b[0m )\n\u001b[1;32m 177\u001b[0m mat \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mzeros(\n\u001b[1;32m 178\u001b[0m (\u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m2\u001b[39m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m \u001b[38;5;28mlen\u001b[39m(full_support), \u001b[38;5;241m1\u001b[39m), device\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice\n\u001b[1;32m 179\u001b[0m )\n\u001b[1;32m 180\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m reduce(\n\u001b[1;32m 181\u001b[0m add,\n\u001b[0;32m--> 182\u001b[0m (\u001b[43mop\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m op \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moperations),\n\u001b[1;32m 183\u001b[0m mat,\n\u001b[1;32m 184\u001b[0m )\n", - "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:98\u001b[0m, in \u001b[0;36mScale.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 83\u001b[0m \u001b[38;5;124;03mGet the corresponding unitary over n_qubits.\u001b[39;00m\n\u001b[1;32m 84\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;124;03m The unitary representation.\u001b[39;00m\n\u001b[1;32m 92\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 93\u001b[0m scale \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 94\u001b[0m values[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name]\n\u001b[1;32m 95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name, \u001b[38;5;28mstr\u001b[39m)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name\n\u001b[1;32m 97\u001b[0m )\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m scale \u001b[38;5;241m*\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moperations\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtensor\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfull_support\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Projects/pasqal/pyqtorch/pyqtorch/composite/compose.py:94\u001b[0m, in \u001b[0;36mScale.tensor\u001b[0;34m(self, values, embedding, full_support)\u001b[0m\n\u001b[1;32m 76\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtensor\u001b[39m(\n\u001b[1;32m 77\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 78\u001b[0m values: \u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Tensor] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mdict\u001b[39m(),\n\u001b[1;32m 79\u001b[0m embedding: Embedding \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 80\u001b[0m full_support: \u001b[38;5;28mtuple\u001b[39m[\u001b[38;5;28mint\u001b[39m, \u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;241m.\u001b[39m] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 81\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Operator:\n\u001b[1;32m 82\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 83\u001b[0m \u001b[38;5;124;03m Get the corresponding unitary over n_qubits.\u001b[39;00m\n\u001b[1;32m 84\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 91\u001b[0m \u001b[38;5;124;03m The unitary representation.\u001b[39;00m\n\u001b[1;32m 92\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m 93\u001b[0m scale \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m---> 94\u001b[0m \u001b[43mvalues\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparam_name\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 95\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name, \u001b[38;5;28mstr\u001b[39m)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparam_name\n\u001b[1;32m 97\u001b[0m )\n\u001b[1;32m 98\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m scale \u001b[38;5;241m*\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moperations[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39mtensor(values, embedding, full_support)\n", - "\u001b[0;31mKeyError\u001b[0m: 'sin_x'" - ] - } - ], - "source": [ - "import torch\n", - "from pyqtorch import uniform_state, HamiltonianEvolution\n", - "from pyqtorch.matrices import DEFAULT_MATRIX_DTYPE\n", - "\n", - "n_qubits = 2\n", - "qubit_targets = list(range(n_qubits))\n", - "\n", - "# Random hermitian hamiltonian\n", - "matrix = torch.rand(2**n_qubits, 2**n_qubits, dtype=DEFAULT_MATRIX_DTYPE)\n", - "hermitian_matrix = matrix + matrix.T.conj()\n", - "\n", - "time = torch.tensor([1.0])\n", - "time_symbol = \"t\"\n", - "\n", - "hamiltonian_evolution = HamiltonianEvolution(generator=generator, time=time_symbol, qubit_support=qubit_targets, \n", - " is_time_dependent=True, duration=duration, steps=n_steps, solver=SolverType.DP5_SE)\n", - "\n", - "# Starting from a uniform state\n", - "psi_start = zero_state(n_qubits)\n", - "\n", - "# Returns the evolved state\n", - "psi_end = hamiltonian_evolution(state=psi_start, values={time_symbol: time}, embedding=embedding)\n", - "\n", - "print(psi_end)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor(0.1987)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import json" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "with open(\"/home/vytautas/Downloads/task_all_annotations_2024_08_26_07_25_47_coco 1 (1).0/annotations/instances_all.json\", \"r\") as f:\n", - " a = json.load(f)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'id': 1, 'name': 'lav', 'supercategory': ''},\n", - " {'id': 2, 'name': 'civ-car', 'supercategory': ''},\n", - " {'id': 3, 'name': 'infantry', 'supercategory': ''},\n", - " {'id': 4, 'name': 'mlrs', 'supercategory': ''},\n", - " {'id': 5, 'name': 'Tank', 'supercategory': ''},\n", - " {'id': 6, 'name': 'Truck', 'supercategory': ''},\n", - " {'id': 7, 'name': 'apc', 'supercategory': ''},\n", - " {'id': 8, 'name': 'army-truck', 'supercategory': ''},\n", - " {'id': 9, 'name': 'artillery-gun', 'supercategory': ''},\n", - " {'id': 10, 'name': 'car', 'supercategory': ''},\n", - " {'id': 11, 'name': 'humvee', 'supercategory': ''},\n", - " {'id': 12, 'name': 'military-vehicle', 'supercategory': ''},\n", - " {'id': 13, 'name': 'person', 'supercategory': ''},\n", - " {'id': 14, 'name': 'pickup', 'supercategory': ''},\n", - " {'id': 15, 'name': 'rocket-artillery', 'supercategory': ''},\n", - " {'id': 16, 'name': 'soldier', 'supercategory': ''},\n", - " {'id': 17, 'name': 'tank', 'supercategory': ''},\n", - " {'id': 18, 'name': 'truck', 'supercategory': ''},\n", - " {'id': 19, 'name': 'van', 'supercategory': ''},\n", - " {'id': 20, 'name': 'vehicle', 'supercategory': ''}]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a[\"categories\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "for annot in a[\"annotations\"]:\n", - " if annot[\"category_id\"] == 10:\n", - " annot[\"category_id\"] = 2" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "with open(\"/home/vytautas/Downloads/task_all_annotations_2024_08_26_07_25_47_coco 1 (1).0/annotations/instances_all.json\", \"w\") as f:\n", - " json.dump(a, f)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pyqtorch", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.13" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/to_delete.py b/to_delete.py deleted file mode 100644 index ba26b8cd..00000000 --- a/to_delete.py +++ /dev/null @@ -1,202 +0,0 @@ -from __future__ import annotations - -import json - -import matplotlib.pyplot as plt -import numpy as np -import qutip -from scipy.interpolate import UnivariateSpline -from whittaker_eilers import WhittakerSmoother - -# user parameters -SMOOTH_LMBDA = 5e-2 -SMOOTH_ORDER = 2 -INTERPOLATE_K = 5 -INTERPOLATE_S = 0.01 - -# parameters and device specs -PATH = "EXPERIMENTS/2024-fresnel-dqc-qel-rerun/agpsr-publication/" -THETA3S = [ - 0.70, - 1.40, - 2.09, - 2.79, - 3.49, - 4.19, - 4.88, - 5.58, - 6.28, -] -QEL_THETA3S_IDX = 3 -PULSE_AMPLITUDE = 9 -MIN_DURATION = 16 -SHIFTS = np.array([2.4699029, 0.90160249]) -X_POINTS = np.linspace( - MIN_DURATION * PULSE_AMPLITUDE / 1000 + max(SHIFTS), - MIN_DURATION * PULSE_AMPLITUDE / 1000 + max(SHIFTS) + 5, - 8, -) # points at which derivatives are to be calculated -QEL_X_POINTS = [ - 4.5186648, - 4.99485528, - 5.23295051, - 5.709141, - 5.94723624, -] # additional points at which derivatives are to be calculated when θ_3=2.79 -C6 = 865723.02 -DURATION_TO_ANGLE = PULSE_AMPLITUDE / 1000 - - -# generator corresponding to a global pulse, specialized for two atoms 5*sqrt(3)um apart -def multi_qubit_rotation_generator(omega: float): - n_qubits = 2 - - # create rotation operators - op_A = [] - for i in range(n_qubits): - prod = [qutip.qeye(2) for _ in range(n_qubits)] - prod[i] = omega / 2 * qutip.sigmax() - op_A.append(qutip.tensor(prod)) - A = sum(op_A) - - # create interaction operators - prod = [(1 + qutip.sigmaz()) / 2, (1 + qutip.sigmaz()) / 2] - r_ij = 5 * np.sqrt(3) - J_ij = C6 / (r_ij**6) - B = J_ij * qutip.tensor(prod) - - # construct generator - G = (A + B) * (2.0 / omega) - - return G - - -def plot_all(): - # SETUP FOR GPSR - # find unique eigenvalue differences - _G = multi_qubit_rotation_generator(omega=PULSE_AMPLITUDE) - print("Generator :", _G) - _eigenvals = _G.eigenenergies() - _diffs = np.round(_eigenvals - _eigenvals.reshape(-1, 1), 7) - _unique_diffs = np.abs(np.unique(np.tril(_diffs))) - _unique_diffs = _unique_diffs[_unique_diffs > 0] - print("Unique eigenvalues differences:", _unique_diffs) - print( - f"Shifts {SHIFTS} used to obtain QPU data was optimized for [4.032524 1.9007948]" - ) - UNIQUE_EVAL_DIFFS = np.array([_unique_diffs[0], _unique_diffs[-2]]) - print("Eigenvalues differences used:", UNIQUE_EVAL_DIFFS) - # calculate M_INV matrix - _M = np.empty((2, 2)) - for i in range(2): - for j in range(2): - _M[i, j] = 4 * np.sin(SHIFTS[i] * UNIQUE_EVAL_DIFFS[j] / 2) - M_INV = np.linalg.pinv(_M) - - # PLOT FOR EACH θ_3 VALUE - fig, _ = plt.subplots(3, 3, sharex=True) - for i in range(len(THETA3S)): - theta3 = THETA3S[i] - if theta3 == THETA3S[QEL_THETA3S_IDX]: - x_pts_for_derivative = np.sort(np.hstack((X_POINTS, QEL_X_POINTS))) - else: - x_pts_for_derivative = X_POINTS - - # LOAD DATA - with open(f"{PATH}data_{theta3}.json", "r") as file: - json_data = json.load(file) - data = np.array( - [ - [item["duration"] * DURATION_TO_ANGLE, item["f"], item["err_f"]] - for item in json_data - ] - ) - - # GPSR - dfdx_GPSR = [] - - def closest_x_index(x: float): - difference_array = np.absolute(data[:, 0] - x) - index = difference_array.argmin() - # print(difference_array[index]) - return index - - for x_v in x_pts_for_derivative: - f1u = data[closest_x_index(x_v + SHIFTS[0]), 1] - f1l = data[closest_x_index(x_v - SHIFTS[0]), 1] - f2u = data[closest_x_index(x_v + SHIFTS[1]), 1] - f2l = data[closest_x_index(x_v - SHIFTS[1]), 1] - F = np.array([f1u - f1l, f2u - f2l]) - dfdx_v = np.sum(UNIQUE_EVAL_DIFFS * np.dot(M_INV, F)) - dfdx_GPSR.append(dfdx_v) - - whittaker_smoother = WhittakerSmoother( - lmbda=SMOOTH_LMBDA, - order=SMOOTH_ORDER, - data_length=len(data[:, 1]), - x_input=data[:, 0], - ) - smoothed_data = whittaker_smoother.smooth(data[:, 1]) - interpolation = UnivariateSpline( - data[:, 0], smoothed_data, k=INTERPOLATE_K, s=INTERPOLATE_S - ) - derivative = interpolation.derivative() - - ax = fig.axes[i] - ax.errorbar( - data[:, 0], - data[:, 1], - data[:, 2], - label="Experiment", - color="tab:blue", - linestyle="none", - marker="o", - ms=2, - ) - ax.plot( - data[:, 0], - smoothed_data, - label="Smoothed", - color="tab:green", - marker="o", - ms=4, - ) - ax.plot( - x_pts_for_derivative, - dfdx_GPSR, - label="GPSR", - color="tab:orange", - marker="o", - ms=4, - ) - x_v = np.linspace(min(data[:, 0]), max(data[:, 0]), 300) - x_v_derivative = np.linspace(min(X_POINTS), max(X_POINTS), 200) - ax.plot( - x_v, - interpolation(x_v), - label="Interpolation", - color="tab:red", - ) - ax.plot( - x_v_derivative, - derivative(x_v_derivative), - label="Derivative of interpolation", - color="tab:pink", - ) - - ax.text( - 0.01, - 0.99, - "$θ_3$ = " + f"{theta3}", - ha="left", - va="top", - transform=ax.transAxes, - ) - - handles, labels = fig.axes[0].get_legend_handles_labels() - fig.legend(handles, labels) - plt.show() - - -if __name__ == "__main__": - plot_all() From 8e3f9663bcb15a53f2451876b4072811f915e786 Mon Sep 17 00:00:00 2001 From: Vytautas Abramavicius Date: Fri, 15 Nov 2024 12:59:08 +0200 Subject: [PATCH 3/4] fixed failing tests --- pyqtorch/hamiltonians/evolution.py | 5 ++++- pyqtorch/time_dependent/solvers.py | 4 +++- tests/test_analog.py | 11 +++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pyqtorch/hamiltonians/evolution.py b/pyqtorch/hamiltonians/evolution.py index d819a128..9d46c3af 100644 --- a/pyqtorch/hamiltonians/evolution.py +++ b/pyqtorch/hamiltonians/evolution.py @@ -150,7 +150,8 @@ def __init__( cache_length: int = 1, duration: Tensor | str | float | None = None, steps: int = 100, - solver=SolverType.DP5_SE, + solver: SolverType = SolverType.DP5_SE, + use_sparse: bool = False, ): """Initializes the HamiltonianEvolution. Depending on the generator argument, set the type and set the right generator getter. @@ -167,6 +168,7 @@ def __init__( self.solver_type = solver self.steps = steps self.duration = duration + self.use_sparse = use_sparse if isinstance(duration, (str, float, Tensor)) or duration is None: self.duration = duration @@ -416,6 +418,7 @@ def Ht(t: torch.Tensor) -> torch.Tensor: torch.flatten(state, start_dim=0, end_dim=-2), t_grid, self.solver_type, + options={"use_sparse": self.use_sparse}, ) # Retrieve the last state of shape (2**n_qubits, batch_size) diff --git a/pyqtorch/time_dependent/solvers.py b/pyqtorch/time_dependent/solvers.py index b95c3c65..22e4826a 100644 --- a/pyqtorch/time_dependent/solvers.py +++ b/pyqtorch/time_dependent/solvers.py @@ -30,7 +30,9 @@ def ode_fun(self, t: float, psi: Tensor) -> Tensor: with warnings.catch_warnings(): # filter-out UserWarning about "Sparse CSR tensor support is in beta state" warnings.filterwarnings("ignore", category=UserWarning) - res = -1j * self.H(t) @ psi.to_sparse() if self.options.use_sparse else psi + res = ( + -1j * self.H(t) @ (psi.to_sparse() if self.options.use_sparse else psi) + ) return res diff --git a/tests/test_analog.py b/tests/test_analog.py index f1e9d0c3..533f3c79 100644 --- a/tests/test_analog.py +++ b/tests/test_analog.py @@ -292,14 +292,16 @@ def test_hamevo_endianness_cnot() -> None: assert torch.allclose(wf_cnot, wf_hamevo, rtol=RTOL, atol=ATOL) -@pytest.mark.parametrize("duration", [torch.rand(1)]) +@pytest.mark.parametrize("duration", [torch.rand(1), "duration"]) @pytest.mark.parametrize("batch_size", [1, 5]) +@pytest.mark.parametrize("use_sparse", [True, False]) @pytest.mark.parametrize("ode_solver", [SolverType.DP5_SE, SolverType.KRYLOV_SE]) def test_timedependent( tparam: str, param_y: float, duration: float, batch_size: int, + use_sparse: bool, n_steps: int, torch_hamiltonian: Callable, hamevo_generator: Sequence, @@ -315,7 +317,11 @@ def test_timedependent( # simulate with time-dependent solver t_points = torch.linspace(0, dur_val[0], n_steps) psi_solver = pyq.sesolve( - torch_hamiltonian, psi_start.reshape(-1, batch_size), t_points, ode_solver + torch_hamiltonian, + psi_start.reshape(-1, batch_size), + t_points, + ode_solver, + options={"use_sparse": use_sparse}, ).states[-1] # simulate with HamiltonianEvolution @@ -329,6 +335,7 @@ def test_timedependent( duration=dur_val, steps=n_steps, solver=ode_solver, + use_sparse=use_sparse, ) values = {"y": param_y, "duration": dur_val} psi_hamevo = hamiltonian_evolution( From 5072bc3a188633649ae646b2a0e21b6d26e57872 Mon Sep 17 00:00:00 2001 From: Vytautas Abramavicius Date: Fri, 15 Nov 2024 13:17:35 +0200 Subject: [PATCH 4/4] fix docs --- docs/time_dependent.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/time_dependent.md b/docs/time_dependent.md index 6fdcbc79..59d9d2af 100644 --- a/docs/time_dependent.md +++ b/docs/time_dependent.md @@ -30,10 +30,15 @@ def ham_t(t: float) -> Tensor: t_points = torch.linspace(0, duration, n_steps) final_state_se = sesolve(ham_t, input_state, t_points, SolverType.DP5_SE).states[-1] -# define jump operator L and solve Lindblad master equation +# define jump operator L L = IMAT.clone() for i in range(n_qubits-1): L = torch.kron(L, XMAT) -final_state_me = mesolve(ham_t, input_state, [L], t_points, SolverType.DP5_ME).states[-1] + +# prepare initial density matrix with batch dimension as the last +rho0 = torch.matmul(input_state, input_state.T).unsqueeze(-1) + +# solve Lindblad master equation +final_state_me = mesolve(ham_t, rho0, [L], t_points, SolverType.DP5_ME).states[-1] ```