diff --git a/docs/update_quairkit_rst.py b/docs/update_quairkit_rst.py index 8219768..af11123 100644 --- a/docs/update_quairkit_rst.py +++ b/docs/update_quairkit_rst.py @@ -232,7 +232,7 @@ def _update_conf_py(source_directory: str = _sphinx_source_dir): author = "QuAIR" # The full version, including alpha/beta/rc tags -release = "0.2.0" +release = "0.3.0" # -- General configuration --------------------------------------------------- diff --git a/quairkit/__init__.py b/quairkit/__init__.py index b3a4ae4..e8ebf8d 100644 --- a/quairkit/__init__.py +++ b/quairkit/__init__.py @@ -47,151 +47,39 @@ cd QuAIRKit pip install -e . -Batch computation ------------------ - -QuAIRKit supports batch computations for quantum circuit simulations, state measurement and quantum information processing. It is easy to use and can be customized for different quantum (machine learning) algorithms. - -Below is an example of batch computation for quantum circuit simulation. Here a zero state is passed through four different quantum circuits, and compared with the target state. - -```python -import quairkit as qkit -from quairkit.database import * -from quairkit.qinfo import * - -target_state = zero_state(1) -unitary_data = pauli_group(1) - -cir = qkit.Circuit(1) -cir.oracle(unitary_data, 0) -cir.ry(param=[0, 1, 2, 3]) - -print(state_fidelity(cir(), target_state)) # zero-state input by default -``` - -```text -tensor([1.0000, 0.4794, 0.8415, 0.0707]) -``` - -Qudit computation ------------------ - -QuAIRKit also supports batch computations for quantum circuit simulations and most of the quantum information processing tools in qudit quantum computing. Note that qudit computation can be used with batch computation, as shown below - -```python -# claim three systems, with 1 qubit and 1 qutrit -cir = qkit.Circuit(2, system_dim=[2, 3]) - -# apply the Heisenberg-Weyl operators on all systems -cir.oracle(heisenberg_weyl(6), [0, 1]) - -# apply the H gate on the first system, controlled by the second system -cir.control_oracle(h(), [1, 0]) - -# trace out the qutrit system and get the qubit state -traced_state = cir().trace(1) - -print('The 6th and 7th state for the batched qubit state is', traced_state[5:7]) -``` - -```text -The 6th and 7th state for the batched qubit state is ---------------------------------------------------- - Backend: density_matrix - System dimension: [2] - System sequence: [0] - Batch size: [2] - - # 0: -[[1.+0.j 0.+0.j] - [0.+0.j 0.+0.j]] - # 1: -[[0.5+0.j 0.5+0.j] - [0.5+0.j 0.5+0.j]] ---------------------------------------------------- -``` - -Fast construction ------------------ - -QuAIRKit provides a fast and flexible way to construct quantum circuits, by self-managing the parameters. All parameters would be created randomly if not specified. QuAIRKit also supports built-in layer ansatzes, such as `complex_entangled_layer`. - -```python -cir = qkit.Circuit(3) - -cir.h() # apply Hadamard gate on all qubits -cir.complex_entangled_layer(depth=3) # apply complex entangled layers of depth 3 -cir.universal_three_qubits() # apply universal three-qubit gate with random parameters -``` - -`qkit.Circuit` is a child class of `torch.nn.Module`, so you can access its parameters and other attributes directly, or use it as a layer in a hybrid neural network. - -Implicit transition -------------------- - -If you want to perform noise simulation or mixed-state-related tools, there is no need to specify the backend, or import other libraries. Just call the function, and QuAIRKit will transit the backend for you. - -```python -cir = qkit.Circuit(3) - -cir.complex_entangled_layer(depth=3) -print(cir().backend) - -# partial transpose on the first two qubits -print(cir().transpose([0, 1]).backend) - -cir.depolarizing(prob=0.1) -print(cir().backend) -``` - -```text -state_vector -density_matrix -density_matrix -``` - -Global setup ------------- - -QuAIRKit provides global setup functions to set the default data type, device and random seed. - -```python -qkit.set_dtype('complex128') # default data type is complex64 -qkit.set_device('cuda') # make sure CUDA is setup with torch -qkit.set_seed(73) # set seeds for all random number generators -``` - -Overall Structure ------------------ - -QuAIRKit provides the following functionalities, +Functionality +------------- - Quantum neural network algorithm simulation - Quantum circuit simulation & visualization - Quantum channel simulation - Quantum algorithm/information tools -`quairkit`: QuAIRKit source code +Modules +------- + +``quairkit``: QuAIRKit source code -- `database`: module of useful matrices & sets -- `loss`: module of quantum loss functions -- `qinfo`: library of quantum algorithms & information tools -- `circuit`: quantum circuit interface +- ``ansatz``: module of circuit templates +- ``database``: module of useful matrices & sets +- ``operator``: module of quantum operators +- ``qinfo``: library of quantum algorithms & information tools +- ``circuit``: quantum circuit interface Tutorials --------- -- `Hamiltonian in QuAIRKit `_ -- `Constructing Quantum Circuits in QuAIRKit `_ -- `Measuring quantum states in QuAIRKit `_ -- `Quantum gates and quantum channels `_ -- `Quantum information tools `_ -- `Manipulation of Quantum States in QuAIRKit `_ -- `Training parameterized quantum circuits `_ -- `Batch Computation `_ -- `Neural network setup customization `_ -- `Introduction to qudit quantum computing `_ +Check out the tutorial folder on `GitHub `_ for more information. + +Relations with Paddle Quantum +----------------------------- +`Paddle Quantum `_ is the world's first cloud-integrated +quantum machine learning platform based on Baidu PaddlePaddle. As most contributors to this project +are also contributors to Paddle Quantum, QuAIRKit incorporates key architectural elements and +interface designs from its predecessor. QuAIRKit focuses more on providing specialized tools and +resources for researchers and developers engaged in cutting-edge quantum algorithm design and +theoretical explorations in quantum information science. """ import os @@ -206,19 +94,20 @@ from . import loss from . import qinfo from .circuit import Circuit +from . import application name = "quairkit" -__version__ = "0.2.0" +__version__ = "0.3.0" def print_info() -> None: r"""Print the information of QuAIRKit, its dependencies and current environment. """ - import matplotlib + import torch import numpy import scipy - import torch + import matplotlib print("\n---------VERSION---------") print("quairkit:", __version__) print("torch:", torch.__version__) @@ -235,9 +124,8 @@ def print_info() -> None: print("OS version:", platform.version()) - import re import subprocess - + import re # stack overflow #4842448 print("---------DEVICE---------") if platform.system() == "Windows": diff --git a/quairkit/application/__init__.py b/quairkit/application/__init__.py new file mode 100644 index 0000000..9f9e478 --- /dev/null +++ b/quairkit/application/__init__.py @@ -0,0 +1,20 @@ +# !/usr/bin/env python3 +# Copyright (c) 2024 QuAIR team. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r""" +The application library of QuAIRKit. +""" + +from .comb import PQCombNet diff --git a/quairkit/application/comb/__init__.py b/quairkit/application/comb/__init__.py new file mode 100644 index 0000000..674a093 --- /dev/null +++ b/quairkit/application/comb/__init__.py @@ -0,0 +1,20 @@ +# !/usr/bin/env python3 +# Copyright (c) 2024 QuAIR team. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r""" +The module of PQCombNet. +""" + +from .comb import PQCombNet diff --git a/quairkit/application/comb/comb.py b/quairkit/application/comb/comb.py new file mode 100644 index 0000000..6eef790 --- /dev/null +++ b/quairkit/application/comb/comb.py @@ -0,0 +1,1299 @@ +# !/usr/bin/env python3 +# Copyright (c) 2024 QuAIR team. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r""" +The source file of the PQCombNet class. +""" + +import csv +import itertools +import os +import time +from copy import deepcopy +from typing import Any, Callable, Dict, List, Optional, Tuple, Union + +import numpy as np +import torch +from torch.nn import ModuleList + +from quairkit.circuit import Circuit +from quairkit.core import set_seed, to_state, utils +from quairkit.database import bell_state, random_unitary, zero_state +from quairkit.operator import ParamOracle +from quairkit.qinfo import channel_repr_convert + +__all__ = ["PQCombNet"] + + +class PQCombNet: + r""" + Parameterized Quantum Comb Net. + + Args: + target_function: The function to apply to each unitary in the dataset. + num_slots: The number of unitaries to be queried. + ancilla: The ancilla dimension or dimension list. + slot_dim: The slot dimension for the unitaries to be queried. + train_unitary_info: The number of unitaries or the unitary dataset to be used for training or the training unitary set. + test_unitary_info: The number of unitaries or the unitary dataset to be used for testing or the testing unitary set. + train_mode: The training mode, which can be "process", "comb", or "swap", default is "process". + task_name: Optional name for the task, useful for data logging and storage. + is_ctrl_U: Flag to indicate if a controlled-U operation is used in the training process. + seed: Optional seed for random number generation, enhancing reproducibility. + """ + + def __init__( + self, + target_function: Callable[[torch.Tensor], torch.Tensor], + num_slots: int = 1, + ancilla: Union[List[int], int] = 0, + slot_dim: int = 2, + train_unitary_info: Union[int, torch.Tensor] = 1000, + test_unitary_info: Union[int, torch.Tensor] = 0, + train_mode: str = "process", + task_name: str = None, + is_ctrl_U: bool = False, + seed: Optional[int] = None, + ) -> None: + _setup_parameters( + self, + target_function, + num_slots, + ancilla, + slot_dim, + train_mode, + task_name, + is_ctrl_U, + seed, + ) + _setup_unitary_sets(self, train_unitary_info, test_unitary_info) + _initialize_training_environment(self) + + @property + def target_function(self) -> Callable[[torch.Tensor], torch.Tensor]: + return self._target_function + + @target_function.setter + def target_function(self, value: Callable[[torch.Tensor], torch.Tensor]) -> None: + self._target_function = value + _calculate_omegas(self) + + @property + def num_slots(self) -> int: + return self._num_slots + + @num_slots.setter + def num_slots(self, value: int) -> None: + self._num_slots = value + self._num_V = self._num_slots + 1 + if self._train_mode == "comb": + _calculate_omegas(self) + + @property + def ancilla_dim_list(self) -> List[int]: + return self._ancilla_dim_list + + @ancilla_dim_list.setter + def ancilla_dim_list(self, value: List[int]) -> None: + self._ancilla_dim_list = value + self._system_dim_list = self._ancilla_dim_list + [self.slot_dim] + + @property + def ancilla_dim(self) -> int: + return np.prod(self.ancilla_dim_list).__int__() + + @property + def slot_dim(self) -> int: + return self._slot_dim + + @property + def train_mode(self) -> str: + return self._train_mode + + @train_mode.setter + def train_mode(self, value: str) -> None: + if self.is_ctrl_U: + raise ValueError("Cannot set train_mode when is_ctrl_U is True") + self._train_mode = value + + @property + def LR(self) -> float: + return self._LR + + @LR.setter + def LR(self, value: float) -> None: + self._LR = value + + @property + def NUM_ITR(self) -> int: + return self._NUM_ITR + + @property + def task_name(self) -> str: + return self._task_name + + @property + def seed(self) -> int: + return self._seed + + @seed.setter + def seed(self, value: int) -> None: + self._seed = value + set_seed(self._seed) + + @property + def is_ctrl_U(self) -> bool: + return self._is_ctrl_U + + @property + def num_V(self) -> int: + return self._num_V + + @property + def train_unitary_set(self) -> torch.Tensor: + return self._train_unitary_set + + @train_unitary_set.setter + def train_unitary_set(self, value: torch.Tensor) -> None: + self._train_unitary_set = value + _calculate_omegas(self) + + @property + def test_unitary_set(self) -> torch.Tensor: + return self._test_unitary_set + + @test_unitary_set.setter + def test_unitary_set(self, value: torch.Tensor) -> None: + self._test_unitary_set = value + _calculate_omegas(self) + + @property + def omega_train(self) -> torch.Tensor: + return self._omega_train + + @property + def omega_test(self) -> torch.Tensor: + return self._omega_test + + @property + def V_circuit_list(self) -> ModuleList: + return self._V_circuit_list + + @V_circuit_list.setter + def V_circuit_list(self, value: ModuleList) -> None: + self.num_slots = value.__len__() - 1 + self.ancilla_dim_list = value[0].system_dim[:-1] + self._V_circuit_list = value + + @property + def data_directory_name(self) -> str: + return self._data_directory_name + + @data_directory_name.setter + def data_directory_name(self, value: str) -> None: + self._data_directory_name = value + + @property + def system_dim_list(self) -> List[int]: + return self._system_dim_list + + @property + def system_dim(self) -> int: + return np.prod(self.system_dim_list).__int__() + + def update_V_circuit( + self, + index: int, + new_V: Union[ + Circuit, ParamOracle, torch.Tensor, Tuple[torch.Tensor, List[int]] + ], + ) -> None: + r""" + Update the V circuit at the specified index with a new circuit. + + Args: + index: The index of the V circuit to update. + new_V: The new V circuit, which can be a ParamOracle, Circuit, torch.Tensor or Tuple[torch.Tensor, List[int]]. + + Raises: + ValueError: If the index is out of range or if the dimension of the provided Circuit does not match the dimension of the existing Circuit. + TypeError: If the new_V is not a Circuit, ParamOracle, torch.Tensor, or Tuple[torch.Tensor, List[int]]. + """ + if not (0 <= index < len(self.V_circuit_list)): + raise ValueError(f"Index out of range: {index}") + + if isinstance(V := new_V, Circuit): + if new_V.system_dim != self.system_dim_list: + raise ValueError( + f"The dimension of the provided Circuit does not match the dimension of the existing Circuit: {new_V.system_dim} != {self.system_dim_list}" + ) + else: + V = Circuit(system_dim=self.system_dim_list) + if isinstance(new_V, ParamOracle): + V.append(new_V) + elif isinstance(new_V, torch.Tensor): + V.oracle(oracle=new_V, system_idx=self.system_dim_list) + elif ( + isinstance(new_V, tuple) + and isinstance(new_V[0], torch.Tensor) + and isinstance(new_V[1], list) + ): + V.oracle(oracle=new_V[0], system_idx=new_V[1]) + else: + raise TypeError( + "new_V must be a Circuit, ParamOracle, torch.Tensor, Tuple[torch.Tensor, or List[int]]" + ) + + self.V_circuit_list[index] = V + + def train( + self, + projector: Optional[torch.Tensor] = None, + base_lr: float = 0.1, + max_epochs: int = 10000, + is_save_data: bool = False, + is_auto_stop: bool = True, + ) -> None: + r""" + Train the PQCombNet model. + + Args: + projector: The projector to apply to the ancilla system of the output state. + base_lr: The base learning rate for the optimizer. + max_epochs: The maximum number of epochs to train for. + is_save_data: A flag to indicate whether to save the training data. + is_auto_stop: A flag to indicate whether to stop training early if the learning rate is too low. + """ + if self.train_mode == "swap": + _swap_train( + self, projector, base_lr, max_epochs, is_save_data, is_auto_stop + ) + else: + _train(self, projector, base_lr, max_epochs, is_save_data, is_auto_stop) + + def extract_highest_fidelity(self) -> None: + r""" + Call the _extract_highest_fidelity function to generate the fidelity tables. + If the file does not exist, prompt the user to set is_save_data to True. + """ + filepath = os.path.join( + self.data_directory_name, f"{self.task_name}_train_log.csv" + ) + if not os.path.exists(filepath): + print( + f"File {filepath} does not exist. Consider setting is_save_data to True." + ) + return + + _extract_highest_fidelity( + self.data_directory_name, f"{self.task_name}_train_log.csv" + ) + + def plot(self): + r""" + Plot the quantum comb circuit. + """ + cir = Circuit(system_dim=self.system_dim_list) + for index, V_circuit in enumerate(self.V_circuit_list): + cir.extend(deepcopy(V_circuit)) + if index < self.num_slots: + if self.is_ctrl_U: + cir.control_oracle( + torch.eye(self.slot_dim), + [len(self.ancilla_dim_list) - 1, len(self.ancilla_dim_list)], + latex_name=(r"$U$" if index % 2 == 0 else r"$U^{\dagger}$"), + ) + else: + cir.oracle( + torch.eye(self.slot_dim), + len(self.ancilla_dim_list), + latex_name=(r"$U$"), + ) + cir.plot() + + +def _prepare_initial_state(self: PQCombNet, is_choi_mode: bool) -> torch.Tensor: + r""" + Prepare the initial state for the quantum circuit. + + Args: + is_choi_mode: A boolean flag indicating whether to prepare a Choi state. + + Returns: + The initial state tensor. + """ + ancilla_state = zero_state( + num_systems=len(self.ancilla_dim_list), system_dim=self.ancilla_dim_list + ) + bell_states = bell_state( + num_systems=2 * (self.num_V if is_choi_mode else 1), + system_dim=self.slot_dim, + ) + return to_state( + utils.linalg._nkron(ancilla_state.ket, bell_states.ket), + ancilla_state.system_dim + bell_states.system_dim, + ) + + +def _construct_circuit( + self: PQCombNet, + system_dim_loss: int, + unitary_set: torch.Tensor, + V_list_applied_index: list, +) -> Circuit: + r""" + Construct the quantum circuit for the loss calculation. + + Args: + system_dim_loss: The system dimension for the loss calculation. + unitary_set: The set of unitary matrices to apply. + V_list_applied_index: List of indices for applying V circuits. + + Returns: + The constructed quantum circuit. + """ + cir_loss = Circuit(system_dim=system_dim_loss) + _apply_V_circuits(self, cir_loss, V_list_applied_index, unitary_set) + return cir_loss + + +def _average_fidelity( + self: PQCombNet, + fid_type: str, + projector: torch.Tensor = None, +) -> torch.Tensor: + r""" + Compute the average fidelity for a given set of unitaries and omega tensor. + + Args: + fid_type: Type of fidelity calculation ('train' or 'test'). + projector: The projector to apply to the ancilla system of output state. + max_batch_size: The maximum number of unitary matrices to be processed in parallel. + + Returns: + The average fidelity as a real-valued tensor. + """ + if fid_type == "test" and self.test_unitary_set.__len__() == 0: + return torch.tensor(-1) + # Set up the parameters + is_comb_mode = self.train_mode == "comb" + num_target_systems = 2 * self.num_V if is_comb_mode else 2 + system_dim_loss = self.ancilla_dim_list + [self.slot_dim] * num_target_systems + V_list_applied_index = _get_V_list_applied_index(self, is_comb_mode) + + # Prepare the input state + Psi_in = _prepare_initial_state(self, is_comb_mode) + + # Construct the circuit + circuit = _construct_circuit( + self, + system_dim_loss, + self.train_unitary_set if fid_type == "train" else self.test_unitary_set, + V_list_applied_index, + ) + + # Compute the output density matrix + psi_out = circuit(Psi_in).density_matrix @ ( + projector + if projector is not None + else torch.eye(self.ancilla_dim, dtype=Psi_in.dtype) + ).kron(torch.eye(self.slot_dim**num_target_systems, dtype=Psi_in.dtype)) + + psi_out_density_matrix = utils.linalg._partial_trace( + psi_out, + list(range(len(self.ancilla_dim_list))), + system_dim_loss, + ) + + if is_comb_mode: + return ( + utils.linalg._trace( + psi_out_density_matrix + @ (self.omega_train if fid_type == "train" else self.omega_test) + ) + * self.slot_dim ** (self.num_V - 2) + ).real + else: + return torch.mean( + utils.linalg._trace( + psi_out_density_matrix + @ (self.omega_train if fid_type == "train" else self.omega_test) + ) + ).real + + +def _save_results( + self: PQCombNet, + itr: int, + fidelity: float, + loss: float, + base_lr: float, + current_lr: float, +) -> None: + data = { + "slot_dim": self.slot_dim, + "num_slots": self.num_slots, + "ancilla_dim": self.ancilla_dim, + "train_mode": self.train_mode, + "base_lr": base_lr, + "current_lr": current_lr, + "num_test_unitary": len(self.train_unitary_set), + "num_train_unitary": len(self.train_unitary_set), + "seed": self.seed, + "max_epochs": itr, + "loss": loss, + "fidelity": fidelity, + } + _save_results_to_csv( + data=data, + filename=f"{self.task_name}_train_log.csv", + directory=self.data_directory_name, + ) + + +def _setup_parameters( + self: PQCombNet, + target_function: Callable[[torch.Tensor], torch.Tensor], + num_slots: int, + ancilla: Union[List[int], int] = 0, + slot_dim: int = 2, + train_mode: str = "comb", + task_name: Optional[str] = None, + is_ctrl_U: bool = False, + seed: Optional[int] = None, +) -> None: + r""" + Combines the setup of basic parameters and training-specific parameters for quantum computation and training. + + Args: + target_function: The function to apply to each unitary in the dataset + num_slots: The number of unitaries to be queried + ancilla: The ancilla dimension or dimension list + slot_dim: The slot dimension for the unitaries to be queried + train_mode: The training mode, which can be "process", "comb", or "swap" + task_name: Optional name for the task, useful for data logging and storage + is_ctrl_U: Flag to indicate if a controlled-U operation is used in the training process + seed: Optional seed for random number generation, enhancing reproducibility + """ + # Basic parameters setup + self._target_function = target_function + self._is_ctrl_U = is_ctrl_U + self._slot_dim = slot_dim + self._num_slots = num_slots + self._ancilla_dim_list = ( + [2] * ancilla + if isinstance(ancilla, int) + else [dim for dim in ancilla if dim != 0] + ) + self._num_V = num_slots + 1 + self._system_dim_list = self._ancilla_dim_list + [slot_dim] + self._task_name = ( + task_name or f"pqcomb_{target_function.__name__}{'_ctrl' if is_ctrl_U else ''}" + ) + + # Training parameters setup + self._seed = seed or np.random.randint(1e6) + + _validate_training_mode(self, train_mode) + + +def _setup_unitary_sets( + self: PQCombNet, + train_unitary_info: Union[int, torch.Tensor], + test_unitary_info: Union[int, torch.Tensor], +) -> None: + r""" + Prepares the unitary sets for training and testing. + + Args: + train_unitary_info: Information or data for training unitaries. + test_unitary_info: Information or data for testing unitaries. + """ + self._train_unitary_set = _generate_unitary_set(train_unitary_info, self.slot_dim) + self._test_unitary_set = ( + _generate_unitary_set(test_unitary_info, self.slot_dim) + if test_unitary_info != 0 + else torch.tensor([]) + ) + + _calculate_omegas(self) + + +def _calculate_omegas(self: PQCombNet) -> None: + r""" + Calculate omega for train and test unitary sets. + """ + try: + self._omega_train = _get_omega(self, self.train_unitary_set) + self._omega_test = _get_omega(self, self.test_unitary_set) + except RuntimeError as e: + if "not enough memory" not in str(e) or self.train_mode != "comb": + raise e + + print( + f"[{self.task_name} | {self.train_mode} | {self.seed}] " + f"Out of memory error caught, switching train_mode from '{self.train_mode}' to ", + end="", + ) + self.train_mode = "process" + print(f"'{self.train_mode}'...") + self._omega_train = _get_omega(self, self.train_unitary_set) + self._omega_test = _get_omega(self, self.test_unitary_set) + + +def _validate_training_mode(self: PQCombNet, train_mode: str) -> None: + r""" + Validates the training mode against supported modes. + + Args: + train_mode: Training mode to validate. + """ + train_mode_list = ["comb", "process", "swap"] + if (train_mode := train_mode.lower()) not in train_mode_list: + raise ValueError( + f"Invalid train_mode: {train_mode}, must be one of {train_mode_list}" + ) + if train_mode == "comb" and self.is_ctrl_U: + raise ValueError("Controlled-U operation is not supported in 'comb' mode.") + self._train_mode = train_mode + + +def _initialize_training_environment(self: PQCombNet) -> None: + r""" + Sets up the data directories and initializes the training environment. + + Initializes the omega tensors and the list of variable quantum circuits for the simulation. + """ + self._data_directory_name = f"{self.task_name}_data" + self._V_circuit_list = _create_V_circuit_list(self) + + +def _get_omega(self: PQCombNet, unitary_set: torch.Tensor) -> torch.Tensor: + r""" + Compute the omega tensor for a given task. + + Args: + unitary_set: The set of unitary matrices. + + Returns: + torch.Tensor: The omega tensor. + """ + if unitary_set.__len__() == 0: + return torch.tensor(-1) + if self.train_mode == "comb": + return _compute_omega_choi( + self.target_function, unitary_set, self.slot_dim, self.num_slots + ) + else: + return _compute_omega_process(self.target_function, unitary_set, self.slot_dim) + + +def _create_V_circuit_list(self: PQCombNet) -> ModuleList: + r""" + Create a list of V circuits. + + Returns: + ModuleList: The list of V circuits. + """ + V_circuit_list = ModuleList() + + for _ in range(self.num_V): + V = Circuit(system_dim=self.system_dim_list) + V.universal_qudits(system_idx=list(range(len(self.system_dim_list)))) + V_circuit_list.append(V) + + return V_circuit_list + + +def _get_V_list_applied_index( + self: PQCombNet, is_comb_mode: bool +) -> Union[List[List[int]], List[int]]: + r""" + Returns the list of indices where V circuits are applied, depending on the training mode. + + Args: + is_choi_mode: Indicates whether the 'choi' mode is used for determining the index list. + + Returns: + Union[List[List[int]], List[int]]: The list of indices where V circuits are applied. + """ + if is_comb_mode: + return [ + list(range(len(self.ancilla_dim_list))) + + [len(self.ancilla_dim_list) + 2 * j + 1] + for j in range(self.num_V) + ] + else: + return list(range(len(self.system_dim_list))) + + +def _apply_V_circuits( + self: PQCombNet, + cir_loss: Circuit, + V_list_applied_index: List[Union[List[int], int]], + unitary_set: torch.Tensor, +) -> None: + r""" + Applies the V circuits to the circuit loss object. + + Args: + cir_loss: The circuit to which the V circuits are applied. + V_list_applied_index: A list or a list of lists of indices where V circuits should be applied. + unitary_set: The set of unitary matrices used in the control operations. + """ + for index, V_circuit in enumerate(self._V_circuit_list): + cir_loss.oracle( + V_circuit.unitary_matrix(), + ( + V_list_applied_index[index] + if self.train_mode == "comb" + else V_list_applied_index + ), + latex_name=f"$\\mathcal{{V}}_{{{index}}}$", + ) + if self.train_mode != "comb" and index < self.num_slots: + _apply_controlled_U(self, cir_loss, unitary_set, index) + + +def _apply_controlled_U( + self: PQCombNet, cir_loss: Circuit, unitary_set: torch.Tensor, index: int +) -> None: + r""" + Applies the controlled U or U† depending on the configuration. + + Args: + cir_loss: The circuit to which the controlled operations are applied. + unitary_set: The set of unitary matrices. + index: The index of the current operation in the sequence. + """ + if self.is_ctrl_U: + cir_loss.control_oracle( + unitary_set if index % 2 == 0 else utils.linalg._dagger(unitary_set), + [len(self.ancilla_dim_list) - 1, len(self.ancilla_dim_list)], + latex_name=(r"$U$" if index % 2 == 0 else r"$U^{\dagger}$"), + ) + else: + cir_loss.oracle( + unitary_set, + len(self.ancilla_dim_list), + latex_name=(r"$U$"), + ) + + +def _log_progress( + self: PQCombNet, + itr: int, + loss: torch.Tensor, + time_list: list, + base_lr: float, + current_lr: float, + max_epochs: int, + projector: torch.Tensor = None, + is_save_data: bool = False, + is_auto_stop: bool = True, +) -> bool: + r""" + Logs the training progress at specified intervals and saves the results. + It provides insights into the current state of training, including loss, fidelity, and learning rate. + + This function checks if the current iteration is a multiple of 100 or the last iteration. + If so, it calculates the average fidelity, constructs a log message with relevant metrics, + and prints it. The function also saves the results and may determine if training should stop early. + + Args: + itr: The current iteration number. + loss: The current loss value. + time_list: A list of time taken for each iteration. + base_lr: The initial learning rate. + current_lr: The current learning rate. + max_epochs: The total number of iterations. + projector: The projector to apply to the ancilla system of the output state. + is_save_data: A flag to indicate whether to save the training data. + is_auto_stop: A flag to indicate whether to stop training early if the learning rate is too low. + + Returns: + Returns True if training should be stopped early, otherwise None. + """ + if ( + itr % 100 == 0 + or itr == max_epochs - 1 + or (current_lr < 1e-3 * base_lr and is_auto_stop) + ): + fidelity = _average_fidelity(self, "test", projector).item() + + print( + ( + f"[{self.task_name} | {self.train_mode} | {self.seed} | \033[90m{itr}\t{np.mean(time_list):.4f}s\033[0m] " + f"slot_dim: {self.slot_dim}, slots: {self.num_slots}, " + + ( + f"ancilla_dim: {self.ancilla_dim}" + if all(dim == 2 for dim in self.ancilla_dim_list) + or not self.ancilla_dim_list + else f"aux_dim: {self.ancilla_dim}" + ) + + f", \033[93mLR: {current_lr:.2e}\033[0m" + + f", \033[91mLoss: {loss.item():.8f}\033[0m" + + (f", \033[92mFid: {fidelity:.8f}\033[0m" if fidelity >= 0 else "") + ), + ) + + time_list.clear() + # Save results and possibly stop training + if is_save_data: + _save_results(self, itr, fidelity, loss.item(), base_lr, current_lr) + + # Stop training if auto-stop conditions are met + return current_lr < 1e-3 * base_lr and is_auto_stop + + +def _compute_omega_choi( + target_function: Callable[[torch.Tensor], torch.Tensor], + unitary_set: torch.Tensor, + slot_dim: int, + num_slots: int, +) -> torch.Tensor: + r""" + Compute the omega tensor using the 'choi' mode. + + Args: + target_function: The function to apply to each tensor in the dataset. + unitary_set: The set of unitary matrices. + slot_dim: The slot dimension for the unitaries to be queried. + num_slots: The parameter 'num_slots' used in computation. + + Returns: + torch.Tensor: The computed omega tensor. + """ + omega = 0 + for u in unitary_set: + u_transformed_choi = channel_repr_convert( + target_function(u), source="kraus", target="choi" + ) + u_conj_choi = channel_repr_convert(u.conj(), source="kraus", target="choi") + omega += utils.linalg._nkron( + *([u_transformed_choi] + [u_conj_choi] * num_slots) + ) + omega /= len(unitary_set) + perm_list = [0, 2 * num_slots + 1] + list(range(1, 2 * num_slots + 1)) + return utils.linalg._permute_systems( + omega, perm_list, [slot_dim] * 2 * (num_slots + 1) + ) + + +def _generate_unitary_set( + unitary_info: Union[int, torch.Tensor], slot_dim: int +) -> torch.Tensor: + r""" + Generates a set of unitary matrices based on provided info. + + Args: + unitary_info: Details to generate or directly provide the unitaries. + slot_dim: slot_dim for the unitary matrices. + """ + return ( + random_unitary(num_systems=1, size=unitary_info, system_dim=slot_dim) + if isinstance(unitary_info, int) + else unitary_info + ) + + +def _compute_omega_process( + target_function: Callable[[torch.Tensor], torch.Tensor], + unitary_set: torch.Tensor, + slot_dim: int, +) -> torch.Tensor: + r""" + Compute the omega tensor for the 'process' or 'swap' mode. + + Args: + target_function: The function to apply to each unitary in the dataset. + unitary_set: The set of unitary. + slot_dim: The slot dimension for the unitaries to be queried. + + Returns: + torch.Tensor: The computed omega tensor. + """ + target_unitary = target_function(unitary_set) + return ( + bell_state(num_systems=2, system_dim=slot_dim) + .evolve(target_unitary.kron(torch.eye(slot_dim))) + .density_matrix + ) + + +def _print_progress_bar( + iteration: int, + total: int, + prefix: str = "", + suffix: str = "", + decimals: int = 1, + length: int = 50, + fill: str = "█", +) -> None: + r""" + Call in a loop to create a terminal progress bar. + + Args: + iteration: Current iteration. + total: Total iterations. + prefix: Prefix string. + suffix: Suffix string. + decimals: Positive number of decimals in percent complete. + length: Character length of the bar. + fill: Bar fill character. + """ + percent = f"{100 * (iteration / float(total)):.{decimals}f}" + filled_length = int(length * iteration // total) + bar = fill * filled_length + "-" * (length - filled_length) + print(f"\r{prefix} |{bar}| {percent}% {suffix}", end="\r") + if iteration == total: + print() + + +def _save_results_to_csv(data: Dict[str, Any], filename: str, directory: str) -> None: + r""" + Save the results to a CSV file. + + Args: + data: A dictionary containing the data to be saved. + filename: The name of the CSV file. + directory: The directory where the CSV file will be saved. + """ + filepath = os.path.join(directory, filename) + + # Ensure the directory exists + os.makedirs(directory, exist_ok=True) + + # Define the column names + fieldnames = list(data.keys()) + + # Write to the CSV file + file_exists = os.path.isfile(filepath) + + with open(filepath, mode="a", newline="") as file: + writer = csv.DictWriter(file, fieldnames=fieldnames) + + if not file_exists: + writer.writeheader() + + writer.writerow(data) + + +def _extract_highest_fidelity(data_directory, filename): + r""" + Extract the highest fidelity for each combination of num_slots and ancilla_dim and generate a table. + + Args: + data_directory: The directory where the CSV file is saved. + filename: The name of the CSV file. + """ + try: + import pandas as pd + except ImportError as e: + raise ImportError( + "The pandas library is required to run this function. Please install it using 'pip install pandas'." + ) from e + + # Construct the full file path + filepath = os.path.join(data_directory, filename) + + # Read the CSV file into a DataFrame + df = pd.read_csv(filepath) + + # Find unique slot_dim values + slot_dim_values = df["slot_dim"].unique() + + # Create a directory to save the result tables + result_dir = os.path.join(data_directory, "fidelity_tables") + os.makedirs(result_dir, exist_ok=True) + + # Iterate over each unique slot_dim value + for slot_dim in slot_dim_values: + # Filter the DataFrame for the current slot_dim + df_filtered = df[df["slot_dim"] == slot_dim] + + # Pivot the table to have num_slots as rows and ancilla_dim as columns, with max fidelity as values + pivot_table = df_filtered.pivot_table( + index="num_slots", + columns="ancilla_dim", + values="fidelity", + aggfunc="max", + ) + + # Save the pivot table to a CSV file + output_filename = f"fidelity_table_slot_dim_{slot_dim}.csv" + output_filepath = os.path.join(result_dir, output_filename) + pivot_table.to_csv(output_filepath) + print(f"Saved table for slot_dim = {slot_dim} to {output_filepath}") + + +def _qudit_swap_matrix(dim: int): + """ + Returns the SWAP gate for a qudit of dimension dim. + + Args: + dim (int): The dimension of the qudit. + """ + qudit_swap_matrix = torch.zeros(dim**2, dim**2) + for x, y in itertools.product(range(dim), range(dim)): + qudit_swap_matrix[y * dim + x, x * dim + y] = 1 + return qudit_swap_matrix + + +def _train_swap_circuit( + self: PQCombNet, + depth: int = 1, + base_lr: float = 0.1, + max_epochs: int = 1000, + loss_threshold: float = 1e-3, +) -> Tuple[Circuit, float]: + r""" + Train the SWAP gate circuit to pass the last unitary in the comb. + + Args: + depth: The depth of the SWAP gate circuit. + base_lr: The base learning rate for the optimizer. + max_epochs: The maximum number of training epochs. + loss_threshold: The loss threshold for stopping the training. + + Returns: + Tuple[Circuit, float]: The trained SWAP gate circuit and the final loss value. + """ + # check if the slot_dim is greater than or equal to the ancilla_dim + assert self.slot_dim <= self.ancilla_dim, ( + f"slot_dim must be greater than or equal to ancilla_dim, " + f"but got slot_dim={self.slot_dim} and ancilla_dim={self.ancilla_dim}" + ) + + assert self.slot_dim == self.ancilla_dim_list[-1], ( + f"slot_dim must be equal to the last element of ancilla_dim_list to construct the SWAP gate, " + f"but got slot_dim={self.slot_dim} and ancilla_dim_list={self.ancilla_dim_list}" + ) + actual_swap_cir = Circuit(system_dim=self.system_dim_list) + for _ in range(depth): + actual_swap_cir.universal_qudits(list(range(actual_swap_cir.num_systems))) + ideal_swap_cir = Circuit(system_dim=self.system_dim_list) + ideal_swap_cir.oracle( + _qudit_swap_matrix(self.slot_dim), + [len(self.system_dim_list) - 2, len(self.system_dim_list) - 1], + ) + + ideal_unitary_matrix = ideal_swap_cir.unitary_matrix() + ideal_choi_ket = ( + ideal_unitary_matrix.kron(torch.eye(self.system_dim)) + @ bell_state(2, self.system_dim).ket + ) + + # define the loss function as 1 minus the fidelity between the Choi matrices of the actual and desired circuits + def swap_loss_func(): + actual_choi_ket = ( + actual_swap_cir.unitary_matrix().kron(torch.eye(self.system_dim)) + @ bell_state(2, self.system_dim).ket + ) + # calculate the fidelity between the actual and desired density matrices + return 1 - abs(utils.linalg._dagger(actual_choi_ket) @ ideal_choi_ket) ** 2 + + # initialize the optimizer and scheduler + opt = torch.optim.Adam(actual_swap_cir.parameters(), lr=base_lr) + scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(opt, "min") + + # start the training process + for itr in range(max_epochs): + _print_progress_bar(itr + 1, max_epochs, prefix="Progress") + # calculate the loss + loss = swap_loss_func() + # obtain the updated learning rate + lr = scheduler.optimizer.param_groups[0]["lr"] + if loss.item() < loss_threshold or lr < base_lr * 1e-4: + print( + f"[pqc_search_swap | \033[90m{itr}\033[0m | {depth}] ", + f"Stop training SWAP with lr={lr:.2e}, loss={loss.item():.8f}.", + ) + break + + # zero the gradients + opt.zero_grad() + # backpropagation + loss.backward() + # update the parameters + opt.step() + # adjust the learning rate according to the loss value + scheduler.step(loss) + + # print training information every 40 iterations or on the last iteration + if itr % 100 == 0 or itr == max_epochs - 1: + print( + f"[pqc_search_swap | \033[90m{itr}\033[0m | {depth}] " + f"slot_dim: {self.slot_dim}, " + + ( + f"ancilla_dim: {self.ancilla_dim}" + if all(dim == 2 for dim in self.ancilla_dim_list) + or not self.ancilla_dim_list + else f"aux_dim: {self.ancilla_dim}" + ) + + f", \033[93mLR: {lr:.2e}\033[0m, " + f"\033[91mLoss: {loss.item():.8f}\033[0m" + ) + + if loss.item() < loss_threshold: + print(f"Applying SWAP gate with lr={lr:.2e}, loss={loss.item():.8f}.") + return actual_swap_cir, loss.item() + else: + print("Retrain SWAP gate...") + return _train_swap_circuit(self, depth=depth + 1) + + +def _swap_train( + self: PQCombNet, + projector: Optional[torch.Tensor], + base_lr: float, + max_epochs: int, + is_save_data: bool, + is_auto_stop: bool, +) -> None: + """ + Trains the PQCombNet model using the SWAP gate approach. + + This method incrementally adds parameterized SWAP gates to the model and trains them to enhance the model's capacity. The training process involves: + - Initializing and training a SWAP gate. + - Sequentially adding SWAP gates to the model until the desired number of slots is achieved. + - Training only the newly added SWAP gates. + - Training all gates in the model for fine-tuning. + + Optionally, it records training data such as fidelity metrics and timing information. + + Args: + projector: The projector tensor used for fidelity calculations. If `None`, a default projector is used. + base_lr: The base learning rate for the optimizer. + max_epochs: The maximum number of training epochs for each training phase. + is_save_data: If `True`, saves the training data and results to the specified directory. + is_auto_stop: If `True`, enables early stopping based on convergence criteria. + + Returns: + None. + """ + n_s = self.num_slots + print( + f"Training SWAP gate with slot_dim={self.slot_dim} and ancilla_dim={self.ancilla_dim}" + ) + start_time_overall = time.time() + param_swap_gate, swap_loss = _train_swap_circuit(self) + time_train_swap = time.time() - start_time_overall + self.V_circuit_list = torch.nn.ModuleList( + [Circuit(system_dim=self.system_dim_list)] + ) + while self.num_slots < n_s: + self.num_slots = self.V_circuit_list.__len__() + for V_circuit in self.V_circuit_list: + V_circuit.requires_grad_(False) + self.V_circuit_list[-1].extend(deepcopy(param_swap_gate)) + self.V_circuit_list.append(deepcopy(param_swap_gate)) + if is_save_data: + # Insert SWAP and calculate initial fidelity + fidelity_train_swap_start = _average_fidelity( + self, "train", projector + ).item() + fidelity_test_swap_start = _average_fidelity(self, "test", projector).item() + + # Train only SWAP gate + print("Training only on parameterized SWAP gates.") + start_time_swap_only = time.time() + _train( + self, + projector, + base_lr, + max_epochs, + is_save_data=False, + is_auto_stop=is_auto_stop, + ) + time_swap_only = time.time() - start_time_swap_only + + if is_save_data: + # Calculate fidelity after SWAP-only training + fidelity_train_swap_only = _average_fidelity( + self, "train", projector + ).item() + fidelity_test_swap_only = _average_fidelity(self, "test", projector).item() + + # Allow all gates to be trained + for V_circuit in self.V_circuit_list: + V_circuit.requires_grad_(True) + + # Train all gates + print("Training on all gates.") + start_time_all = time.time() + _train( + self, + projector, + base_lr, + max_epochs, + is_save_data=is_save_data, + is_auto_stop=is_auto_stop, + ) + + if is_save_data: + time_all = time.time() - start_time_all + + # Calculate fidelity after training all gates + fidelity_train_all = _average_fidelity(self, "train", projector).item() + fidelity_test_all = _average_fidelity(self, "test", projector).item() + + if not os.path.exists(self.data_directory_name): + os.makedirs(self.data_directory_name) + + csv_file_name = os.path.join( + self.data_directory_name, + f"swap_fidelity_time_dataset={self.train_unitary_set.__len__()}_d={self.slot_dim}.csv", + ) + if not os.path.exists(csv_file_name): + with open(csv_file_name, mode="w", newline="") as file: + writer = csv.writer(file) + writer.writerow( + [ + "seed", + "num_slots", + "ancilla_dim", + "train_mode", + "fidelity_train_swap_start", + "fidelity_test_swap_start", + "time_swap_only", + "fidelity_train_swap_only", + "fidelity_test_swap_only", + "time_all", + "fidelity_train_all", + "fidelity_test_all", + "time_train_swap", + "time_overall", + "swap_loss", + ] + ) + + swap_start_only_all_fidelity_time_item = ( + self.seed, + self.num_slots, + self.ancilla_dim, + self.train_mode, + fidelity_train_swap_start, + fidelity_test_swap_start, + time_swap_only, + fidelity_train_swap_only, + fidelity_test_swap_only, + time_all, + fidelity_train_all, + fidelity_test_all, + time_train_swap, + time.time() - start_time_overall, + swap_loss, + ) + + with open(csv_file_name, mode="a", newline="") as file: + writer = csv.writer(file) + writer.writerow(swap_start_only_all_fidelity_time_item) + + if is_save_data: + # Extract the highest fidelity for each combination of num_slots and ancilla_dim + try: + import pandas as pd + except ImportError as e: + raise ImportError( + "The pandas library is required to run this function. Please install it using 'pip install pandas'." + ) from e + + # Read the CSV file into a DataFrame + df = pd.read_csv(csv_file_name).round(4) + + # Pivot the table to have num_slots as rows and ancilla_dim as columns, with max fidelity_test_all as values + pivot_table = df.pivot_table( + index="num_slots", + columns="ancilla_dim", + values="fidelity_test_all", + aggfunc="max", + ) + + # Save the pivot table to a new CSV file + max_fidelity_filename = os.path.join( + self.data_directory_name, + f"max_fidelity_dataset={self.train_unitary_set.__len__()}_d={self.slot_dim}.csv", + ) + pivot_table.to_csv(max_fidelity_filename) + print(f"Saved max fidelity table to {max_fidelity_filename}") + + +def _train( + self: PQCombNet, + projector: Optional[torch.Tensor], + base_lr: float, + max_epochs: int, + is_save_data: bool, + is_auto_stop: bool, +) -> None: + r""" + Train the model using the provided parameters. + + Args: + projector: The projector tensor used for fidelity calculations. If `None`, a default projector is used. + base_lr: The base learning rate for the optimizer. + max_epochs: The maximum number of training epochs. + is_save_data: If `True`, saves the training data and results to the specified directory. + is_auto_stop: If `True`, enables early stopping based on convergence criteria. + + Returns: + None. + """ + opt = torch.optim.Adam(self._V_circuit_list.parameters(), lr=base_lr) + scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(opt, "min") + + time_list = [] + for itr in range(max_epochs): + _print_progress_bar(itr + 1, max_epochs, prefix="Progress") + + start_time = time.time() + loss = 1 - _average_fidelity(self, "train", projector) + time_list.append(time.time() - start_time) + + if _log_progress( + self, + itr, + loss, + time_list, + base_lr, + scheduler.get_last_lr()[0], + max_epochs, + projector, + is_save_data, + is_auto_stop, + ): + break + + opt.zero_grad() + loss.backward() + opt.step() + scheduler.step(loss) + + fidelity = _average_fidelity(self, "test", projector).item() + + if is_save_data: + V_circuit_lists_dir = os.path.join(self.data_directory_name, "V_circuit_lists") + os.makedirs(V_circuit_lists_dir, exist_ok=True) + save_path = os.path.join( + V_circuit_lists_dir, + f"V_circuit_list_{self.train_mode}_sd{self.slot_dim}_ns{self.num_slots}_na{self.ancilla_dim}_itr{itr}" + + (f"_fid{fidelity:.5f}.pt" if fidelity >= 0 else ".pt"), + ) + torch.save(self.V_circuit_list, save_path) + print( + f"[{self.task_name} | {self.train_mode} | {self.seed}] Finished training" + + (f" with Fidelity: {fidelity:.8f}" if fidelity >= 0 else "") + ) diff --git a/quairkit/application/locc/__init__.py b/quairkit/application/locc/__init__.py new file mode 100644 index 0000000..6a6565f --- /dev/null +++ b/quairkit/application/locc/__init__.py @@ -0,0 +1,18 @@ +# !/usr/bin/env python3 +# Copyright (c) 2024 QuAIR team. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r""" +The module of LOCCNet. +""" diff --git a/quairkit/circuit.py b/quairkit/circuit.py index 8563ffc..d7d7200 100644 --- a/quairkit/circuit.py +++ b/quairkit/circuit.py @@ -30,7 +30,6 @@ LinearEntangledLayer, OperatorList, QAOALayer, RealBlockLayer, RealEntangledLayer, SuperpositionLayer, WeakSuperpositionLayer) -from .core import Backend, get_backend, get_dtype, get_float_dtype, to_state from .core.intrinsic import _alias, _cnot_idx_fetch, _format_circuit_idx from .core.state import State from .database import std_basis, zero_state @@ -39,13 +38,15 @@ BitFlip, BitPhaseFlip, ChoiRepr, Collapse, ControlOracle, Depolarizing, Gate, GeneralizedAmplitudeDamping, GeneralizedDepolarizing, H, - KrausRepr, Oracle, P, ParamOracle, PauliChannel, - PhaseDamping, PhaseFlip, ResetChannel, S, Sdg, - StinespringRepr, T, Tdg, ThermalRelaxation, + KrausRepr, OneWayLOCC, Oracle, P, ParamOracle, + PauliChannel, PhaseDamping, PhaseFlip, ResetChannel, S, + Sdg, StinespringRepr, T, Tdg, ThermalRelaxation, UniversalThreeQubits, UniversalTwoQubits, X, Y, Z) from .operator.gate import _circuit_plot from .operator.gate.custom import UniversalQudits +__all__ = ['Circuit'] + class Circuit(OperatorList): r"""Quantum circuit. @@ -68,6 +69,7 @@ def __init__(self, num_systems: Optional[int] = None, # alias self.toffoli = self.ccx self.cx = self.cnot + self.collapse = self.measure # TODO recover the gather logic for CNOT # preparing cnot index in 'cycle' case @@ -1163,7 +1165,7 @@ def oracle( self, oracle: torch.Tensor, system_idx: Union[List[int], int], gate_name: Optional[str] = 'O', latex_name: Optional[str] = None, plot_width: Optional[float] = None ) -> None: - """Add an oracle gate. + r"""Add an oracle gate. Args: oracle: Unitary oracle to be implemented. @@ -1185,27 +1187,31 @@ def oracle( @_alias({"system_idx": "qubits_idx"}) def control_oracle( - self, oracle: torch.Tensor, system_idx: List[int], + self, oracle: torch.Tensor, system_idx: List[Union[List[int], int]], proj: Union[torch.Tensor] = None, gate_name: Optional[str] = 'O', latex_name: Optional[str] = None, plot_width: Optional[float] = None ) -> None: - """Add a controlled oracle gate. + r"""Add a controlled oracle gate. Args: oracle: Unitary oracle to be implemented. - system_idx: Indices of the systems on which the gates are applied. + system_idx: Indices of the systems on which the gates are applied. The first element in the list is the control system, + defaulting to the $|d-1\rangle \langle d-1|$ state as the control qubit, + while the remaining elements represent the oracle system. + proj: Projector matrix for the control qubit. Defaults to ``None`` gate_name: name of this oracle. latex_name: latex name of this oracle, default to be the gate name. plot_width: width of this gate in circuit plot, default to be proportional with the gate name. """ - system_idx = self.__info_update(system_idx, len(system_idx)) + _system_idx = sum(([item] if isinstance(item, int) else item for item in system_idx), []) + _system_idx = self.__info_update(_system_idx, len(_system_idx)) gate_info = { 'gatename': f"c{gate_name}", 'texname': f"${gate_name}$" if latex_name is None else latex_name, 'plot_width': 0.6 * len(gate_name) if plot_width is None else plot_width} - acted_system_dim = [self.__system_dim[idx] for idx in system_idx] + acted_system_dim = [self.__system_dim[idx] for idx in _system_idx] self.append(ControlOracle( - oracle, system_idx, acted_system_dim, gate_info)) + oracle, system_idx, acted_system_dim, proj, gate_info)) @_alias({"system_idx": "qubits_idx"}) def param_oracle(self, generator: Callable[[torch.Tensor], torch.Tensor], num_acted_param: int, @@ -1234,26 +1240,24 @@ def param_oracle(self, generator: Callable[[torch.Tensor], torch.Tensor], num_ac self.append(ParamOracle( generator, param, num_acted_param, False, system_idx, acted_system_dim, gate_info)) - def collapse(self, system_idx: Union[Iterable[int], int, str] = None, - desired_result: Union[int, str] = None, if_print: bool = False, - measure_basis: Optional[torch.Tensor] = None) -> None: + @_alias({"system_idx": "qubits_idx", "post_selection": "desired_result"}) + def measure(self, system_idx: Union[Iterable[int], int, str] = None, + post_selection: Union[int, str] = None, if_print: bool = False, + measure_basis: Optional[torch.Tensor] = None) -> None: r""" Args: - system_idx: list of systems to be collapsed. Defaults to all qubits. - desired_result: The desired result you want to collapse. Defaults to ``None`` meaning randomly choose one. + system_idx: list of systems to be measured. Defaults to all qubits. + post_selection: the post selection result after measurement. Defaults to ``None`` meaning preserving all measurement outcomes. if_print: whether print the information about the collapsed state. Defaults to ``False``. measure_basis: The basis of the measurement. The quantum state will collapse to the corresponding eigenstate. - Raises: - NotImplementedError: If the basis of measurement is not z. Other bases will be implemented in future. - TypeError: cannot get probability of state when the backend is unitary_matrix. - Note: - When desired_result is `None`, Collapse does not support gradient calculation + When desired_result is `None`, collapse is equivalent to mid-circuit measurement. + """ system_idx = self.__info_update(system_idx, None) self.append(Collapse( - system_idx, desired_result, if_print, measure_basis)) + system_idx, post_selection, if_print, measure_basis)) def superposition_layer( self, qubits_idx: Iterable[int] = None @@ -1363,7 +1367,7 @@ def bit_flip( qubits_idx: Indices of the qubits on which the channels are applied. Defaults to 'full'. """ qubits_idx = self.__info_update(qubits_idx, 1) - self.append(BitFlip(prob, qubits_idx, self.num_qubits)) + self.append(BitFlip(prob, qubits_idx)) def phase_flip( self, prob: Union[torch.Tensor, float], qubits_idx: Union[Iterable[int], int, str] = 'full' @@ -1375,8 +1379,7 @@ def phase_flip( qubits_idx: Indices of the qubits on which the channels are applied. Defaults to 'full'. """ qubits_idx = self.__info_update(qubits_idx, 1) - self.append(PhaseFlip(prob, qubits_idx, - self.num_qubits)) + self.append(PhaseFlip(prob, qubits_idx)) def bit_phase_flip( self, prob: Union[torch.Tensor, float], qubits_idx: Union[Iterable[int], int, str] = 'full' @@ -1538,6 +1541,20 @@ def stinespring_channel( acted_system_dim = [self.__system_dim[idx] for idx in system_idx] self.append(StinespringRepr(stinespring_repr, system_idx, acted_system_dim)) + def locc(self, local_unitary: torch.Tensor, system_idx: List[Union[List[int], int]]) -> None: + r"""Add a one-way local operation and classical communication (LOCC) protocol comprised of unitary operations. + + Args: + measure_idx: Indices of the measured systems. + system_idx: Indices of the systems on which the protocol is applied. The first element represents the measure system(s) and the remaining elements represent the local system(s). + + """ + _system_idx = (list(system_idx[0]) if isinstance(system_idx[0], int) else system_idx[0]) + system_idx[1:] + _system_idx = self.__info_update(_system_idx, len(_system_idx)) + + acted_system_dim = [self.__system_dim[idx] for idx in _system_idx] + self.append(OneWayLOCC(local_unitary, system_idx, acted_system_dim)) + def __str__(self): history = self.gate_history num_systems = self.__num_system diff --git a/quairkit/core/intrinsic.py b/quairkit/core/intrinsic.py index deffec7..ab44ee1 100644 --- a/quairkit/core/intrinsic.py +++ b/quairkit/core/intrinsic.py @@ -265,36 +265,43 @@ def _get_complex_dtype(float_dtype: torch.dtype) -> torch.dtype: return complex_dtype -def _type_fetch(data: Union[np.ndarray, torch.Tensor, State, Any], +_ArrayLike = Union[np.ndarray, torch.Tensor] +_StateLike = Union[np.ndarray, torch.Tensor, State] +_ParamLike = Union[np.ndarray, torch.Tensor, Iterable[float]] +_SingleParamLike = Union[_ParamLike, float] +_General = Union[_ArrayLike, _StateLike, _SingleParamLike] + + +def _type_fetch(data: _General, ndim: Optional[int]= None) -> Union[str, Tuple[str, List[int]]]: r"""Fetch the type of ``data`` Args: data: the input data, and datatype of which should be either ``numpy.ndarray``, - ''torch.Tensor'' or ``quairkit.State`` + ``torch.Tensor``, ``quairkit.State``, ``Iterable[float]`` or ``float`` + where the last two types will be considered as "tensor". ndim: the number of dimensions to be removed, used for batched data Returns: - When ``ndim`` is not none, the returned tuple contains the following variables: - - a string of datatype of ``data``, can be either ``"numpy"``, ``"tensor"`` or ``"state"`` + When ndim is not none, the returned tuple contains the following variables: + - a string of datatype of ``data``, can be either ``"numpy"``, ``"tensor"``, ``"state"``, or ``"other"`` - the batch dimension - When ``ndim`` is none, the returned variable is just the string. - - Raises: - TypeError: cannot recognize the current type of input data. + When ndim is none, the returned variable is just the string. """ if isinstance(data, np.ndarray): return "numpy" if ndim is None else ("numpy", list(data.shape[:-ndim])) - + if isinstance(data, torch.Tensor): - return "tensor" if ndim is None else ("tensor", list(data.shape[:-ndim])) + return "tensor" if ndim is None else list(data.shape[:-ndim]) if isinstance(data, State): return "state" if ndim is None else ("state", list(data.batch_dim)) - raise TypeError( - f"cannot recognize the current type {type(data)} of input data.") + assert ndim is None, \ + ("Cannot obtain batch dimension for data type other than " + + f"np.ndarray, torch.Tensor or quairkit.State: received {type(data)}") + return "other" def _density_to_vector(rho: Union[np.ndarray, torch.Tensor]) -> Union[np.ndarray, torch.Tensor]: @@ -325,13 +332,14 @@ def _density_to_vector(rho: Union[np.ndarray, torch.Tensor]) -> Union[np.ndarray return state.detach().numpy() if type_str == "numpy" else state -def _type_transform(data: Union[np.ndarray, torch.Tensor, State], output_type: str, - system_dim: Optional[Union[List[int], int]] = None) -> Union[np.ndarray, torch.Tensor, State]: +def _type_transform(data: _General, output_type: str, + system_dim: Optional[Union[List[int], int]] = None) -> _StateLike: r""" transform the datatype of ``input`` to ``output_type`` Args: - data: data to be transformed - output_type: datatype of the output data, type is either ``"numpy"``, ``"tensor"`` or ``"state"`` + data: data to be transformed, can be and datatype of which should be either ``numpy.ndarray``, + ``quairkit.State``, ``float``, ``Iterable[float]`` or ``torch.Tensor`` + output_type: datatype of the output data, type is either ``"numpy"``, ``"state"``, ``"tensor"`` system_dim: dimension of the system, used for transforming to state. Defaults to qubit case. Returns: @@ -342,11 +350,16 @@ def _type_transform(data: Union[np.ndarray, torch.Tensor, State], output_type: s """ current_type = _type_fetch(data) + + if current_type == "other": + current_type = "tensor" + data = torch.tensor(data) - support_type = {"numpy", "tensor", "state"} - if output_type not in support_type: - raise ValueError( - f"does not support transformation to type {output_type}") + if output_type == "other": + output_type = "tensor" + else: + assert output_type in {"numpy", "tensor", "state"}, \ + f"does not support transformation from {current_type} to type {output_type}" if current_type == output_type: return data diff --git a/quairkit/core/state/backend/__init__.py b/quairkit/core/state/backend/__init__.py index e04af30..9e4a2eb 100644 --- a/quairkit/core/state/backend/__init__.py +++ b/quairkit/core/state/backend/__init__.py @@ -50,28 +50,29 @@ class State(ABC): system_seq: the system order of this state. Defaults to be from 0 to n - 1. """ - def __init__(self, data: torch.Tensor, sys_dim: List[int], system_seq: Optional[List[int]] = None): + def __init__(self, data: torch.Tensor, sys_dim: List[int], + system_seq: Optional[List[int]] = None): self._data, self._sys_dim = data.contiguous().to(dtype=base.get_dtype(), device=base.get_device()), sys_dim self._system_seq = list(range(len(sys_dim))) if system_seq is None else system_seq self.is_swap_back = True # TODO: depreciated, will be removed in the future self._keep_dim = False - + @abstractmethod def __getitem__(self, key: Union[int, slice]) -> 'State': r"""Indexing of the State class """ @abstractmethod - def index_select(self, dim: int, index: torch.Tensor) -> 'State': - r"""Indexing elements from the State batch along the given dimension. + def prob_select(self, outcome_idx: torch.Tensor, prob_idx: int = -1) -> 'State': + r"""Indexing probability outcome from the State batch along the given dimension. Args: - dim: the dimension in which we index - index: the 1-D tensor containing the indices to index - - Note: - Here `dim` refers to the dimension in batch_dim, dimensions for data are not considered. + outcome_idx: the 1-D tensor containing the outcomes to index + prob_idx: the int that indexing which probability distribution. Defaults to be the last distribution. + + Returns: + States that are selected by the specific probability outcomes. """ @@ -107,12 +108,13 @@ def __copy__(self) -> 'State': return self.clone() def __str__(self) -> str: - split_line = '\n---------------------------------------------------\n' + split_line = "\n-----------------------------------------------------\n" s = f"{split_line} Backend: {self.backend}\n" s += f" System dimension: {self._sys_dim}\n" s += f" System sequence: {self._system_seq}\n" data = np.round(self.numpy(), decimals=2) + interrupt_num = 5 if not self.batch_dim: s += str(data.squeeze(0)) s += split_line @@ -121,6 +123,13 @@ def __str__(self) -> str: s += f" Batch size: {self.batch_dim}\n" for i, mat in enumerate(data): s += f"\n # {i}:\n{mat}" + + if i > interrupt_num: + break_line = ("\n----------skipped for the rest of " + + f"{list(data.shape)[0] - interrupt_num} states----------\n") + s+= break_line + return s + s += split_line return s @@ -165,14 +174,43 @@ def data(self) -> torch.Tensor: 'The data property is depreciated, use ket or density_matrix instead', DeprecationWarning) return self._data + def _joint_probability(self, prob_idx: List[int]) -> torch.Tensor: + r"""The joint probability distribution of these states' occurrences + + Args: + prob_idx: the indices of probability distributions + + """ + result_prob = torch.tensor(1.0) + for idx in sorted(prob_idx): + selected_prob = self._prob[idx] + result_prob = result_prob.view(list(result_prob.shape) + [1] * (selected_prob.dim() - result_prob.dim())) + result_prob = torch.mul(result_prob, selected_prob) + return result_prob + + @property + def probability(self) -> torch.Tensor: + r"""The probability distribution(s) of these states' occurrences + """ + return self._joint_probability(range(len(self._prob))) + + @property + def _prob_dim(self) -> List[int]: + r"""Current probability dimensions + """ + return list(self._prob[-1].shape[-len(self._prob):]) if self._prob else [] + @property def batch_dim(self) -> List[int]: r"""The batch dimension of this state """ - if hasattr(self, '_batch_dim'): - return self._batch_dim - else: - raise KeyError(f"The state class {self.backend} does not have batch functional") + return self._batch_dim + self._prob_dim + + @property + def _squeeze_shape(self) -> List[int]: + r"""The squeezed shape of this state batch + """ + return [-1, int(np.prod(self._prob_dim))] @property def shape(self) -> torch.Size: @@ -195,7 +233,7 @@ def device(self) -> torch.device: def numel(self) -> int: r"""The number of elements in this data """ - return int(np.prod(self.batch_dim)) if self.batch_dim else 1 + return int(np.prod(self.batch_dim)) @property def dim(self) -> int: @@ -383,17 +421,18 @@ def permute(self, target_seq: List[int]) -> 'State': return new_state def reset_sequence(self) -> None: - r"""reset the system order to default sequence i.e. from 1 to n. + r"""reset the system order to default sequence i.e. from 0 to n - 1. """ self.system_seq = list(range(self.num_systems)) @abstractmethod - def _evolve(self, unitary: torch.Tensor, sys_idx: List[int]) -> None: + def _evolve(self, unitary: torch.Tensor, sys_idx: List[int], on_batch: bool = True) -> None: r"""Evolve this state with unitary operators. Args: unitary: the unitary operator. sys_idx: the system indices to be acted on. + on_batch: whether this unitary operator evolves on batch axis. Defaults to True. Note: The difference between `State.evolve` and `State._evolve` is that the former returns a new state @@ -467,6 +506,14 @@ def _expec_val(self, obs: torch.Tensor, sys_idx: List[int]) -> torch.Tensor: """ + @abstractmethod + def _expec_state(self, prob_idx: List[int]) -> 'State': + r"""The expectation with respect to the specific probability distribution(s) of states + + Args: + prob_idx: indices of probability distributions. Defaults to all distributions. + """ + @abstractmethod def _measure(self, measure_op: torch.Tensor, sys_idx: List[int]) -> Tuple[torch.Tensor, 'State']: r"""Measure the quantum state with the measured operators. @@ -583,7 +630,7 @@ def expec_val(self, hamiltonian: Hamiltonian, shots: Optional[int] = 0, for i in range(num_terms): qubits_idx = list_qubits_idx[i] if qubits_idx == ['']: - expec_val_each_term.append(list_coef[i] * self.trace) + expec_val_each_term.append(list_coef[i] * self.trace()) continue matrix = list_matrices[i] @@ -596,9 +643,31 @@ def expec_val(self, hamiltonian: Hamiltonian, shots: Optional[int] = 0, expec_val_each_term = torch.stack(expec_val_each_term) return expec_val_each_term if decompose else torch.sum(expec_val_each_term, dim=0) + + def expec_state(self, prob_idx: Optional[Union[int, List[int]]] = None) -> 'State': + r"""The expectation with respect to the specific probability distribution(s) of states + + Args: + prob_idx: indices of probability distributions. Defaults to all distributions. + + Returns: + The expected State obtained from the taken probability distributions. + + """ + if self._prob == []: + return self.clone() + num_prob = len(self._prob) + + if prob_idx is None: + prob_idx = list(range(num_prob)) + elif isinstance(prob_idx, int): + prob_idx = [prob_idx] + else: + prob_idx = [num_prob + idx if idx < 0 else idx for idx in sorted(prob_idx)] + return self._expec_state(prob_idx) - def measure(self, measured_op: torch.Tensor = None, sys_idx: Optional[Union[int, List[int]]] = None, - is_povm: Optional[bool] = False, keep_state: Optional[bool] = False + def measure(self, measured_op: Optional[torch.Tensor] = None, sys_idx: Optional[Union[int, List[int]]] = None, + is_povm: bool = False, keep_state: bool = False ) -> Union[torch.Tensor, Tuple[torch.Tensor, 'State']]: r"""Measure the quantum state diff --git a/quairkit/core/state/backend/density_matrix.py b/quairkit/core/state/backend/density_matrix.py index 479ed40..5af382c 100644 --- a/quairkit/core/state/backend/density_matrix.py +++ b/quairkit/core/state/backend/density_matrix.py @@ -35,36 +35,62 @@ class MixedState(State): data: tensor array (in density matrix representation) for quantum mixed state(s). sys_dim: a list of dimensions for each system. system_seq: the system order of this state. Defaults to be from 1 to n. - + probability: list of state probability distributions. Defaults to be 1. + Note: The data is stored in the matrix-form with shape :math:`(-1, d, d)` """ - def __init__(self, data: torch.Tensor, sys_dim: List[int], system_seq: Optional[List[int]] = None): + def __init__(self, data: torch.Tensor, sys_dim: List[int], + system_seq: Optional[List[int]] = None, + probability: Optional[List[torch.Tensor]] = None): dim = int(np.prod(sys_dim)) + self._prob = [] if probability is None else probability - self._batch_dim = list(data.shape[:-2]) + non_batch_len = 2 + len(self._prob) + self._batch_dim = list(data.shape[:-non_batch_len]) + data = data.reshape([-1, dim, dim]) super().__init__(data, sys_dim, system_seq) def __getitem__(self, key: Union[int, slice]) -> 'MixedState': assert self.batch_dim, \ f"This state is not batched and hence cannot be indexed: received key {key}." - return MixedState(self.density_matrix[key], self.system_dim, self.system_seq) + return MixedState(self.density_matrix[key], self.system_dim, self.system_seq, + [prob.clone() for prob in self._prob]) - def index_select(self, dim: int, index: torch.Tensor) -> 'MixedState': - dim = dim - 2 if dim < 0 else dim - return MixedState(torch.index_select(self.density_matrix, dim=dim, index=index).squeeze(), - self.system_dim, self.system_seq) + def prob_select(self, outcome_idx: torch.Tensor, prob_idx: int = -1) -> 'MixedState': + if prob_idx > 0: + prob_idx -= len(self._prob) + + new_prob = [] + for idx, prob in enumerate(self._prob): + if len(self._prob) > prob_idx + idx: + new_prob.append(prob.index_select(dim=prob_idx, index=outcome_idx).squeeze(prob_idx)) + elif len(self._prob) < prob_idx + idx: + new_prob.append(prob.clone()) + elif outcome_idx.numel() != 1: + new_prob.append(prob.index_select(dim=prob_idx, index=outcome_idx)) + + data_idx = prob_idx - 2 + data = self.density_matrix.index_select(dim=data_idx, index=outcome_idx).squeeze(data_idx) + return MixedState(data, self.system_dim, self.system_seq, new_prob) def expand(self, batch_dim: List[int]) -> 'MixedState': + if self._prob != []: + raise NotImplementedError( + "Indexing of mixed state with probabilistic computation is not supported." + ) + expand_state = self.clone() expand_state._batch_dim = batch_dim + expand_state._prob = [] if np.prod(batch_dim) == np.prod(self._batch_dim): return expand_state - expand_state._data = self._data.expand(batch_dim + [-1, -1]).reshape([-1, self.dim, self.dim]) + non_batch_len = 2 + len(self._prob) + expand_state._data = self._data.expand(batch_dim + [-1] * non_batch_len).reshape([-1, self.dim, self.dim]) return expand_state @property @@ -98,7 +124,7 @@ def ket(self) -> torch.Tensor: @property def density_matrix(self) -> torch.Tensor: self.reset_sequence() - return self._data.view(self._batch_dim + [self.dim, self.dim]).clone() + return self._data.view(self.batch_dim + [self.dim, self.dim]).clone() def _trace(self, trace_idx: List[int]) -> 'MixedState': remain_seq, remain_system_dim = [], [] @@ -109,19 +135,19 @@ def _trace(self, trace_idx: List[int]) -> 'MixedState': trace_dim = math.prod([self.system_dim[x] for x in trace_idx]) self.system_seq = trace_idx + remain_seq - data = self._data.clone().view(self._batch_dim + [self.dim, self.dim]) + data = self._data.view(self.batch_dim + [self.dim, self.dim]) data = utils.linalg._trace_1(data, trace_dim) # convert remaining sequence value_to_index = {value: index for index, value in enumerate(sorted(remain_seq))} remain_seq = [value_to_index[i] for i in remain_seq] - return MixedState(data, remain_system_dim, remain_seq) + return MixedState(data, remain_system_dim, remain_seq, self._prob) def _transpose(self, transpose_idx: List[int]) -> 'MixedState': - state = self.clone() - state.system_seq = transpose_idx + [x for x in self._system_seq if x not in transpose_idx] - + self.system_seq = transpose_idx + [x for x in self._system_seq if x not in transpose_idx] transpose_dim = math.prod([self.system_dim[x] for x in transpose_idx]) + + state = self.clone() state._data = utils.linalg._transpose_1(state._data, transpose_dim) return state @@ -129,8 +155,9 @@ def normalize(self) -> None: self._data = torch.div(self._data, utils.linalg._trace(self._data, -2, -1).view([-1, 1, 1])) def clone(self) -> 'MixedState': - data = self._data.view(self._batch_dim + [self.dim, self.dim]).clone() - return MixedState(data, self.system_dim, self.system_seq) + dim = self.dim + data = self._data.view(self.batch_dim + [dim, dim]).clone() + return MixedState(data, self.system_dim, self.system_seq, [prob.clone() for prob in self._prob]) def fit(self, backend: str) -> torch.Tensor: data = self.density_matrix @@ -155,59 +182,85 @@ def system_seq(self, target_seq: List[int]) -> None: self._data = utils.linalg._base_transpose_for_dm(self._data, perm_map, current_system_dim).contiguous() self._system_seq = target_seq - def _evolve(self, unitary: torch.Tensor, sys_idx: List[int]) -> None: - self._batch_dim = self._batch_dim or list(unitary.shape[:-2]) + def _evolve(self, unitary: torch.Tensor, sys_idx: List[int], on_batch: bool = True) -> None: + dim, _shape = self.dim, self._squeeze_shape + if on_batch: + self._batch_dim = self._batch_dim or list(unitary.shape[:-2]) + evolve_axis = [-1, 1] + else: + evolve_axis = [1, -1] applied_dim = unitary.shape[-1] self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] - data = self._data.view([-1, applied_dim, (self.dim ** 2) // applied_dim]) + unitary = unitary.view(evolve_axis + [applied_dim, applied_dim]) + data = self._data.view(_shape + [applied_dim, (dim ** 2) // applied_dim]) data = torch.matmul(unitary, data) - data = data.view([-1, self.dim, applied_dim, self.dim // applied_dim]) - self._data = torch.matmul(unitary.unsqueeze(-3).conj().clone(), data).view([-1, self.dim, self.dim]) + data = data.view(_shape + [dim, applied_dim, dim // applied_dim]) + self._data = torch.matmul(unitary.unsqueeze(-3).conj().clone(), data).view([-1, dim, dim]) def _evolve_keep_dim(self, unitary: torch.Tensor, sys_idx: List[int]) -> None: - self._batch_dim = (self._batch_dim or list(unitary.shape[:-3])) + list(unitary.shape[-3:-2]) - unitary = unitary.view((list(unitary.shape[:-2]) or [-1]) + list(unitary.shape[-2:])) + unitary_batch_dim = list(unitary.shape[:-2]) + dim, _shape = self.dim, self._squeeze_shape + self._batch_dim = (self._batch_dim or unitary_batch_dim[:-1]) + unitary_batch_dim[-1:] - applied_dim, num_unitary = unitary.shape[-1], unitary.shape[-3] + applied_dim, num_unitary = unitary.shape[-1], int(np.prod(unitary_batch_dim[-1:])) self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] - data = self._data.view([-1, 1, applied_dim, (self.dim ** 2) // applied_dim]) + unitary = unitary.view([-1, 1] + [num_unitary, applied_dim, applied_dim]) + data = self._data.view(_shape + [1, applied_dim, (dim ** 2) // applied_dim]) data = torch.matmul(unitary, data) - data = data.view([-1, num_unitary, self.dim, applied_dim, self.dim // applied_dim]) + data = data.view(_shape + [num_unitary, dim, applied_dim, dim // applied_dim]) unitary = unitary.unsqueeze(-3) data = torch.matmul(unitary.conj(), data) - self._data = data.view([-1, self.dim, self.dim]) + self._data = data.view([-1, dim, dim]) def _expec_val(self, obs: torch.Tensor, sys_idx: List[int]) -> torch.Tensor: + dim = self.dim self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] applied_dim, num_obs = obs.shape[-1], obs.shape[-3] - state = self._data.view([-1, 1, applied_dim, (self.dim ** 2) // applied_dim]) - state = torch.matmul(obs, state).view([-1, num_obs, self.dim, self.dim]) + state = self._data.view([-1, 1, applied_dim, (dim ** 2) // applied_dim]) + state = torch.matmul(obs, state).view([-1, dim, dim]) - return utils.linalg._trace(state, -2, -1).view(self._batch_dim + [num_obs]) + return utils.linalg._trace(state, -2, -1).view(self.batch_dim + [num_obs]) - def _measure(self, measure_op: torch.Tensor, sys_idx: List[int]) -> Tuple[torch.Tensor, 'MixedState']: - origin_batch_dim, origin_data = self._batch_dim.copy(), self._data.clone() - self._evolve_keep_dim(measure_op, sys_idx) - - data = self._data.view([-1, self.dim, self.dim]) + def _expec_state(self, prob_idx: List[int]) -> 'MixedState': + dim, num_prob = self.dim, len(self._prob) + batch_prob_len = len(self._prob[-1].shape[:-num_prob]) + prob = self._joint_probability(prob_idx) - prob = utils.linalg._trace(data, -2, -1).view([-1, 1, 1]) - collapsed_state = data / prob - collapsed_state[collapsed_state != collapsed_state] = 0 + states = self._data.view([-1] + self._prob_dim + [dim ** 2]) + prob = prob.view(list(prob.shape) + [1] * (self._prob[-1].dim() - prob.dim() + 1)) + prob_state = torch.mul(prob, states) + + sum_idx = [idx + 1 for idx in prob_idx] + expectation = prob_state.sum(sum_idx) + + new_prob = [] + if len(prob_idx) != num_prob: + new_prob = [prob.clone() for idx, prob in enumerate(self._prob) if idx not in prob_idx] + expectation = expectation.view(self._batch_dim + list(new_prob[-1].shape[batch_prob_len:]) + [dim, dim]) + else: + expectation = expectation.view(self._batch_dim + [dim, dim]) + return MixedState(expectation, self.system_dim, self.system_seq, new_prob) + + def _measure(self, measure_op: torch.Tensor, sys_idx: List[int]) -> Tuple[torch.Tensor, 'MixedState']: + new_state = self.clone() + new_state._evolve_keep_dim(measure_op, sys_idx) - new_batch_dim = self._batch_dim - collapsed_state = MixedState(collapsed_state.view(new_batch_dim + [self.dim, self.dim]), - self.system_dim, self.system_seq) - prob = prob.view(new_batch_dim) + data = new_state._data + measure_prob = utils.linalg._trace(data, -2, -1).real.view([-1, 1, 1]) + collapsed_data = data / measure_prob + collapsed_data[collapsed_data != collapsed_data] = 0 - self._batch_dim, self._data = origin_batch_dim, origin_data - return prob.real, collapsed_state + measure_prob = measure_prob.view(new_state._batch_dim[:-1] + self._prob_dim + [-1]) + new_state._data = collapsed_data + new_state._batch_dim = new_state._batch_dim[:-1] + new_state._prob.append(measure_prob) + return measure_prob, new_state def __kraus_transform(self, list_kraus: torch.Tensor, sys_idx: List[int]) -> None: r"""Apply the Kraus operators to the state. @@ -227,6 +280,7 @@ def __choi_transform(self, choi: torch.Tensor, sys_idx: List[int]) -> None: choi: the Choi operator. sys_idx: the system index list. """ + _shape = self._squeeze_shape self._batch_dim = self._batch_dim or list(choi.shape[:-2]) refer_sys_idx = [x for x in self._system_seq if x not in sys_idx] @@ -235,10 +289,11 @@ def __choi_transform(self, choi: torch.Tensor, sys_idx: List[int]) -> None: dim_out = choi.shape[-1] // dim_in self.system_seq = refer_sys_idx + sys_idx - data = self._data.view([-1, dim_refer, dim_in, dim_refer, dim_in]).transpose(-1, -3) - data = torch.matmul(data.reshape([-1, (dim_refer ** 2) * dim_in, dim_in]), - choi.view([-1, dim_in, dim_in * (dim_out ** 2)])) - data = torch.transpose(data.view([-1, dim_in, dim_refer, dim_out, dim_in, dim_out]), -3, -4) + data = self._data.view(_shape + [dim_refer, dim_in, dim_refer, dim_in]) + choi = choi.view([-1, 1] + [dim_in, dim_in * (dim_out ** 2)]) + + data = torch.matmul(data.transpose(-1, -3).reshape(_shape + [(dim_refer ** 2) * dim_in, dim_in]), choi) + data = torch.transpose(data.view(_shape + [dim_in, dim_refer, dim_out, dim_in, dim_out]), -3, -4) data = utils.linalg._trace(data, -2, -5) self._data = data.view([-1, dim_refer * dim_out, dim_refer * dim_out]) @@ -251,6 +306,5 @@ def sqrt(self) -> torch.Tensor: def log(self) -> torch.Tensor: if self.rank < self.dim: warnings.warn( - "The state is not full-rank, thus the matrix logarithm may not be accurate.", UserWarning) - + f"The matrix logarithm may not be accurate: expect rank {self.dim}, received {self.rank}", UserWarning) return utils.linalg._logm(self.density_matrix) diff --git a/quairkit/core/state/backend/state_vector.py b/quairkit/core/state/backend/state_vector.py index 430f4f0..dcf72e7 100644 --- a/quairkit/core/state/backend/state_vector.py +++ b/quairkit/core/state/backend/state_vector.py @@ -34,15 +34,21 @@ class PureState(State): data: tensor array in vector representation for quantum pure state(s). sys_dim: a list of dimensions for each system. system_seq: the system order of this state. Defaults to be from 1 to n. + probability: tensor array for state distributions. Defaults to be 1. Note: The data is stored in the vector-form with shape :math:`(-1, d)` """ - def __init__(self, data: torch.Tensor, sys_dim: List[int], system_seq: Optional[List[int]] = None): + def __init__(self, data: torch.Tensor, sys_dim: List[int], + system_seq: Optional[List[int]] = None, + probability: Optional[List[torch.Tensor]] = None): dim = int(np.prod(sys_dim)) + self._prob = [] if probability is None else probability + + non_batch_len = 2 + len(self._prob) + self._batch_dim = list(data.shape[:-non_batch_len]) - self._batch_dim = list(data.shape[:-2]) data = data.reshape([-1, dim]) super().__init__(data, sys_dim, system_seq) @@ -51,21 +57,42 @@ def __init__(self, data: torch.Tensor, sys_dim: List[int], system_seq: Optional[ def __getitem__(self, key: Union[int, slice]) -> 'PureState': assert self.batch_dim, \ f"This state is not batched and hence cannot be indexed: received key {key}." - return PureState(self.ket[key], self.system_dim, self.system_seq) + return PureState(self.ket[key], self.system_dim, self.system_seq, + [prob.clone() for prob in self._prob]) - def index_select(self, dim: int, index: torch.Tensor) -> 'PureState': - dim = dim - 2 if dim < 0 else dim - return PureState(torch.index_select(self.ket, dim=dim, index=index).squeeze().unsqueeze(-1), - self.system_dim, self.system_seq) + def prob_select(self, outcome_idx: torch.Tensor, prob_idx: int = -1) -> 'PureState': + num_prob = len(self._prob) + if prob_idx > 0: + prob_idx -= num_prob + + new_prob = [] + for idx, prob in enumerate(self._prob): + if num_prob > prob_idx + idx: + new_prob.append(prob.index_select(dim=prob_idx, index=outcome_idx).squeeze(prob_idx)) + elif num_prob < prob_idx + idx: + new_prob.append(prob.clone()) + elif outcome_idx.numel() != 1: + new_prob.append(prob.index_select(dim=prob_idx, index=outcome_idx)) + + data_idx = prob_idx - 2 + data = self.ket.index_select(dim=data_idx, index=outcome_idx).squeeze(data_idx) + return PureState(data, self.system_dim, self.system_seq, new_prob) def expand(self, batch_dim: List[int]) -> 'PureState': + if self._prob != []: + raise NotImplementedError( + "Batch expansion of pure state with probabilistic computation is not supported." + ) + expand_state = self.clone() expand_state._batch_dim = batch_dim + expand_state._prob = [] if np.prod(batch_dim) == np.prod(self._batch_dim): return expand_state - expand_state._data = expand_state._data.expand(batch_dim + [-1]).reshape([-1, self.dim]) + non_batch_len = 1 + len(self._prob) + expand_state._data = self._data.expand(batch_dim + [-1] * non_batch_len).reshape([-1, self.dim]) return expand_state @property @@ -99,18 +126,21 @@ def check(data: torch.Tensor, sys_dim: Union[int, List[int]], eps: Optional[floa @property def ket(self) -> torch.Tensor: self.reset_sequence() - return self._data.view(self._batch_dim + [self.dim, 1]).clone() + return self._data.view(self.batch_dim + [self.dim, 1]).clone() @property def density_matrix(self) -> torch.Tensor: - return torch.matmul(self.ket, self.bra) + ket = self.ket + return torch.matmul(ket, ket.mH) def _trace(self, sys_idx: List[int]) -> MixedState: - state = MixedState(self.density_matrix, self.system_dim, self.system_seq) + state = MixedState(self.density_matrix, self.system_dim, self.system_seq, + [prob.clone() for prob in self._prob]) return state._trace(sys_idx) def _transpose(self, sys_idx: List[int]) -> MixedState: - state = MixedState(self.density_matrix, self.system_dim, self.system_seq) + state = MixedState(self.density_matrix, self.system_dim, self.system_seq, + [prob.clone() for prob in self._prob]) return state._transpose(sys_idx) @property @@ -121,8 +151,8 @@ def normalize(self): return torch.div(self._data, torch.norm(self._data, dim=-1)) def clone(self) -> 'PureState': - data = self._data.view(self._batch_dim + [self.dim, 1]).clone() - state = PureState(data, self.system_dim, self.system_seq) + data = self._data.view(self.batch_dim + [self.dim, 1]).clone() + state = PureState(data, self.system_dim, self.system_seq, [prob.clone() for prob in self._prob]) state._switch_unitary_matrix = self._switch_unitary_matrix return state @@ -158,59 +188,98 @@ def _record_unitary(self, unitary: torch.Tensor, sys_idx: List[int]) -> None: self._evolve_keep_dim(unitary, sys_idx) return - applied_dim = unitary.shape[-1] + applied_dim, dim = unitary.shape[-1], self.dim self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] - data = self._data.view([self.dim, -1, applied_dim, self.dim // applied_dim]) - self._data = torch.matmul(unitary, data).view([-1, self.dim]) + data = self._data.view([dim, -1, applied_dim, dim // applied_dim]) + self._data = torch.matmul(unitary, data).view([-1, dim]) - def _evolve(self, unitary: torch.Tensor, sys_idx: List[int]) -> None: + def _evolve(self, unitary: torch.Tensor, sys_idx: List[int], on_batch: bool = True) -> None: if self._switch_unitary_matrix: self._record_unitary(unitary, sys_idx) return + dim, _shape = self.dim, self._squeeze_shape + + if on_batch: + self._batch_dim = self._batch_dim or list(unitary.shape[:-2]) + evolve_axis = [-1, 1] + else: + evolve_axis = [1, -1] + + applied_dim = unitary.shape[-1] + self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] + + unitary = unitary.view(evolve_axis + [applied_dim, applied_dim]) + data = self._data.view(_shape + [applied_dim, dim // applied_dim]) + self._data = torch.matmul(unitary, data).view([-1, dim]) + + def _evolve_probabilistic(self, unitary: torch.Tensor, sys_idx: List[int]) -> None: + dim, _shape = self.dim, self._squeeze_shape self._batch_dim = self._batch_dim or list(unitary.shape[:-2]) applied_dim = unitary.shape[-1] self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] - data = self._data.view([-1, applied_dim, self.dim // applied_dim]) - self._data = torch.matmul(unitary, data).view([-1, self.dim]) + unitary = unitary.view([1, -1, applied_dim, applied_dim]) + data = self._data.view(_shape + [applied_dim, dim // applied_dim]) + self._data = torch.matmul(unitary, data).view([-1, dim]) def _evolve_keep_dim(self, unitary: torch.Tensor, sys_idx: List[int]) -> None: - self._batch_dim = (self._batch_dim or list(unitary.shape[:-3])) + list(unitary.shape[-3:-2]) - unitary = unitary.view((list(unitary.shape[:-2]) or [-1]) + list(unitary.shape[-2:])) + unitary_batch_dim = list(unitary.shape[:-2]) + dim, _shape = self.dim, self._squeeze_shape + self._batch_dim = (self._batch_dim or unitary_batch_dim[:-1]) + list(unitary_batch_dim[-1:]) - applied_dim = unitary.shape[-1] + applied_dim, num_unitary = unitary.shape[-1], int(np.prod(unitary_batch_dim[-1:])) self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] - data = self._data.view([-1, 1, applied_dim, self.dim // applied_dim]) - self._data = torch.matmul(unitary, data).view([-1, self.dim]) + unitary = unitary.view([-1, 1] + [num_unitary, applied_dim, applied_dim]) + data = self._data.view(_shape + [1, applied_dim, dim // applied_dim]) + self._data = torch.matmul(unitary, data).view([-1, dim]) def _expec_val(self, obs: torch.Tensor, sys_idx: List[int]) -> torch.Tensor: + dim = self.dim self.system_seq = sys_idx + [x for x in self._system_seq if x not in sys_idx] applied_dim, num_obs = obs.shape[-1], obs.shape[-3] - state = self._data.view([-1, 1, applied_dim, self.dim // applied_dim]) - measured_state = torch.matmul(obs, state).view([-1, num_obs, self.dim]) + state = self._data.view([-1, 1, applied_dim, dim // applied_dim]) + measured_state = torch.matmul(obs, state).view([-1, num_obs, dim]) + + return torch.linalg.vecdot(self._data.unsqueeze(-2), measured_state).view(self.batch_dim + [num_obs]) - return torch.linalg.vecdot(self._data.unsqueeze(-2), measured_state).view(self._batch_dim + [num_obs]) + def _expec_state(self, prob_idx: List[int]) -> 'PureState': + dim, num_prob = self.dim, len(self._prob) + batch_prob_len = len(self._prob[-1].shape[:-num_prob]) + prob = self._joint_probability(prob_idx) + + states = self._data.view([-1] + self._prob_dim + [dim]) + prob = prob.view(list(prob.shape) + [1] * (self._prob[-1].dim() - prob.dim() + 1)) + prob_state = torch.mul(prob, states) + + sum_idx = [idx + 1 for idx in prob_idx] + expectation = prob_state.sum(sum_idx) + + new_prob = [] + if len(prob_idx) != num_prob: + new_prob = [prob.clone() for idx, prob in enumerate(self._prob) if idx not in prob_idx] + expectation = expectation.view(self._batch_dim + list(new_prob[-1].shape[batch_prob_len:]) + [dim, 1]) + else: + expectation = expectation.view(self._batch_dim + [dim, 1]) + return PureState(expectation, self.system_dim, self.system_seq, new_prob) def _measure(self, measure_op: torch.Tensor, sys_idx: List[int]) -> Tuple[torch.Tensor, 'PureState']: - origin_batch_dim, origin_data = self._batch_dim.copy(), self._data.clone() - self._evolve_keep_dim(measure_op, sys_idx) - data = self._data.view([-1, self.dim, 1]) - - prob = data.mH @ data - collapsed_state = data / torch.sqrt(prob) - collapsed_state[collapsed_state != collapsed_state] = 0 + new_state = self.clone() + new_state._evolve_keep_dim(measure_op, sys_idx) - new_batch_dim = self._batch_dim - collapsed_state = PureState(collapsed_state.view(new_batch_dim + [self.dim, 1]), - self.system_dim, self.system_seq) - prob = prob.view(new_batch_dim) + data = new_state._data.view([-1, self.dim, 1]) + measure_prob = (data.mH @ data).real + collapsed_data = data / torch.sqrt(measure_prob) + collapsed_data[collapsed_data != collapsed_data] = 0 - self._batch_dim, self._data = origin_batch_dim, origin_data - return prob.real, collapsed_state + measure_prob = measure_prob.view(new_state._batch_dim[:-1] + self._prob_dim + [-1]) + new_state._data = collapsed_data.view([-1, self.dim]) + new_state._batch_dim = new_state._batch_dim[:-1] + new_state._prob.append(measure_prob) + return measure_prob, new_state def _transform(self, *args) -> None: raise NotImplementedError( @@ -218,7 +287,8 @@ def _transform(self, *args) -> None: Please call the 'transform' function directly instead of '_transform'.") def transform(self, op: torch.Tensor, sys_idx: List[int] = None, repr_type: str = 'kraus') -> MixedState: - state = MixedState(self.density_matrix, self.system_dim, self.system_seq) + state = MixedState(self.density_matrix, self.system_dim, self.system_seq, + [prob.clone() for prob in self._prob]) return state.transform(op, sys_idx, repr_type) def sqrt(self) -> torch.Tensor: diff --git a/quairkit/core/state/state.py b/quairkit/core/state/state.py index 0e7fb7c..7cef17a 100644 --- a/quairkit/core/state/state.py +++ b/quairkit/core/state/state.py @@ -17,6 +17,8 @@ Common functions for the State class. """ +import warnings +from functools import reduce from typing import Dict, List, Optional, Type, Union import numpy as np @@ -48,7 +50,8 @@ def __state_convert(input_state: State, backend: Optional[str], system_dim: Unio assert input_state.dim == int(np.prod(system_dim)), \ f"The state dimension {input_state.dim} does not match with the input system dimension: {system_dim}." initializer = __state_dict[backend] - return initializer(input_state.fit(backend), system_dim) + return initializer(input_state.fit(backend), system_dim, list(range(len(system_dim))), + [prob.clone() for prob in input_state._prob]) def __fetch_default_init(list_dim: List[int]) -> Type[State]: @@ -69,10 +72,11 @@ def __fetch_default_init(list_dim: List[int]) -> Type[State]: def to_state( data: Union[torch.Tensor, np.ndarray, State], - system_dim: Optional[Union[int, List[int]]] = 2, + system_dim: Union[int, List[int]] = 2, dtype: Optional[str] = None, state_backend: Optional[str] = None, - eps: Optional[float] = 1e-4 + eps: Optional[float] = 1e-4, + prob: Optional[List[torch.Tensor]] = None ) -> State: r"""The function to generate a specified state instance. @@ -84,6 +88,7 @@ def to_state( dtype: Used to specify the data dtype of the data. Defaults to the global setup. state_backend: The backend of the state. Specified only when the input data is an instance of the State class. eps: The tolerance for checking the validity of the input state. Can be adjusted to ``None`` to disable the check. + prob: The (list of) probability distribution of the state. The length of the list denotes the number of distributions. Returns: The generated quantum state. @@ -117,7 +122,7 @@ def to_state( f"the backend is not recognized or implemented: receive {get_backend()}") num_systems = initializer.check(data, system_dim, eps) system_dim = [system_dim] * num_systems if isinstance(system_dim, int) else system_dim - return initializer(data, system_dim) + return initializer(data, system_dim, list(range(num_systems)), prob) def image_to_density_matrix(image_filepath: str) -> State: @@ -148,21 +153,41 @@ def image_to_density_matrix(image_filepath: str) -> State: return to_state(rho) +def __kron_state(state_1st: State, state_2nd: State) -> State: + r"""Calculate the tensor product of two states. + """ + system_dim = state_1st.system_dim + state_2nd.system_dim + system_seq = state_1st.system_seq + [x + state_1st.num_systems for x in state_2nd.system_seq] + + if state_1st._prob: + prob = state_1st._prob + if state_2nd._prob: + warnings.warn( + "Detect tensor product of two probabilistic states: will discard prob info of the 2nd one", UserWarning) + else: + prob = state_2nd._prob + + if state_1st.backend == 'state_vector' and state_2nd.backend == 'state_vector': + data = utils.linalg._kron(state_1st.ket, state_2nd.ket) + return PureState(data, system_dim, system_seq, prob) + else: + data = utils.linalg._kron(state_1st.density_matrix, state_2nd.density_matrix) + return MixedState(data, system_dim, system_seq, prob) + -def tensor_state(state_a: State, state_b: State, *args: State) -> State: +def tensor_state(state_1st: State, *args: State) -> State: r"""calculate tensor product (kronecker product) between at least two state. This function automatically returns State instance Args: - state_a: State - state_b: State + state_a: the first state args: other states Returns: tensor product state of input states Note: - Need to be careful with the backend of states; + Need to be careful with the backend of states; Support broadcasting for batch states. Use ``quairkit.linalg.NKron`` if the input datatype is ``torch.Tensor`` or ``numpy.ndarray``. """ - return to_state(utils.qinfo._nkron(state_a.density_matrix, state_b.density_matrix, [st.density_matrix for st in args])) + return reduce(__kron_state, args, state_1st) if args else state_1st diff --git a/quairkit/core/utils/__init__.py b/quairkit/core/utils/__init__.py index 1da112d..5ffa433 100644 --- a/quairkit/core/utils/__init__.py +++ b/quairkit/core/utils/__init__.py @@ -28,4 +28,4 @@ # # ----------------------------------------------------------------- -from . import check, linalg, qinfo +from . import check, linalg, matrix, qinfo, representation diff --git a/quairkit/core/utils/check.py b/quairkit/core/utils/check.py index 889c3e1..9b638f9 100644 --- a/quairkit/core/utils/check.py +++ b/quairkit/core/utils/check.py @@ -31,12 +31,12 @@ def _is_square(mat: torch.Tensor) -> bool: return mat.ndim >= 2 and mat.shape[-1] == mat.shape[-2] -def _is_hermitian(mat: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_hermitian(mat: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: mat = mat.to(torch.complex128) return (mat - utils.linalg._dagger(mat)).norm(dim=(-2, -1)) < eps -def _is_positive(mat: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_positive(mat: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: mat = mat.to(torch.complex128) herm_check = _is_hermitian(mat, eps) @@ -45,8 +45,7 @@ def _is_positive(mat: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor return herm_check & pos_check -def _is_state_vector(vec: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: - # assume the input is of shape [..., d, 1] or [d, 1] +def _is_state_vector(vec: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: vec = vec.to(torch.complex128) eps = min(eps * vec.shape[-2], 1e-4) @@ -54,7 +53,7 @@ def _is_state_vector(vec: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Te return (vec_bra @ vec - (1 + 0j)).norm(dim=(-2, -1)) < eps -def _is_density_matrix(rho: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_density_matrix(rho: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: rho = rho.to(torch.complex128) eps = min(eps * rho.shape[-1], 1e-4) @@ -63,12 +62,12 @@ def _is_density_matrix(rho: torch.Tensor, eps: Optional[float] = 1e-6) -> torch. return is_trace_one & is_pos -def _is_projector(mat: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_projector(mat: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: mat = mat.to(torch.complex128) return (mat @ mat - mat).norm(dim=(-2, -1)) < eps -def _is_isometry(mat: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_isometry(mat: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: mat = mat.to(torch.complex128) dim = mat.shape[-1] eps = min(eps * dim, 1e-2) @@ -77,11 +76,11 @@ def _is_isometry(mat: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor return (utils.linalg._dagger(mat) @ mat - identity).norm(dim=(-2, -1)) < eps -def _is_unitary(mat: torch.Tensor, eps: Optional[float] = 1e-4) -> torch.Tensor: +def _is_unitary(mat: torch.Tensor, eps: float = 1e-4) -> torch.Tensor: return _is_isometry(mat, eps) & _is_hermitian(utils.linalg._dagger(mat) @ mat, eps) -def _is_ppt(density_op: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_ppt(density_op: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: density_op = density_op.to(torch.complex128) return utils.qinfo._negativity(density_op) <= eps @@ -102,7 +101,7 @@ def _is_linear( func: Callable[[torch.Tensor], torch.Tensor], generator: Union[List[int], Callable[[], torch.Tensor]], input_dtype: torch.dtype, - eps: Optional[float] = 1e-5, + eps: float = 1e-5, ) -> torch.Tensor: list_err = [] for _ in range(5): @@ -117,7 +116,7 @@ def _is_linear( return torch.mean(torch.concat(list_err)) < eps -def _is_povm(set_op: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_povm(set_op: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: dim, batch_shape, set_op = set_op.shape[-1], list(set_op.shape[:-3]), set_op.view([-1] + list(set_op.shape[-3:])) pos_check = _is_positive(set_op.view([-1, dim, dim]), eps) @@ -129,7 +128,7 @@ def _is_povm(set_op: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: return (pos_check & complete_check).view(batch_shape) -def _is_pvm(set_op: torch.Tensor, eps: Optional[float] = 1e-6) -> torch.Tensor: +def _is_pvm(set_op: torch.Tensor, eps: float = 1e-6) -> torch.Tensor: set_op = set_op.to(torch.complex128) povm_check = _is_povm(set_op, eps) diff --git a/quairkit/core/utils/linalg.py b/quairkit/core/utils/linalg.py index 2d23ca7..112606d 100644 --- a/quairkit/core/utils/linalg.py +++ b/quairkit/core/utils/linalg.py @@ -32,6 +32,7 @@ def _abs_norm(mat: torch.Tensor) -> float: norms = torch.norm(torch.abs(mat), dim=(-2, -1)) return norms.item() if mat.ndim == 2 else norms.tolist() + def _p_norm_herm(mat: torch.Tensor, p: torch.Tensor) -> torch.Tensor: eigval = torch.linalg.eigvalsh(mat) norm = torch.abs(eigval).pow(p).sum(dim = len(list(mat.shape[:-2]))).pow(1 / p) @@ -219,16 +220,6 @@ def _partial_trace_discontiguous( return _partial_trace(rho, traced_qubits, system_dim) -def _zero(dtype: Optional[torch.dtype] = None) -> torch.Tensor: - dtype = torch.float64 if dtype is None else dtype - return torch.tensor([0], dtype=dtype) - - -def _one(dtype: Optional[torch.dtype] = None) -> torch.Tensor: - dtype = torch.float64 if dtype is None else dtype - return torch.tensor([1], dtype=dtype) - - def _density_to_vector(rho: torch.Tensor) -> torch.Tensor: # Handle a batch of density matrices @@ -251,30 +242,34 @@ def _density_to_vector(rho: torch.Tensor) -> torch.Tensor: return eigvec[torch.arange(len(max_eigval_indices)), : ,max_eigval_indices].squeeze().unsqueeze(-1) - -def _trace(mat: torch.Tensor, axis1: Optional[int]=-2, axis2: Optional[int]=-1) -> torch.Tensor: +def _trace(mat: torch.Tensor, axis1: int = -2, axis2: int =- 1) -> torch.Tensor: dia_elements = torch.diagonal(mat, offset=0 ,dim1=axis1, dim2=axis2) - return torch.sum(dia_elements, dim=-1, keepdim=False) + return torch.sum(dia_elements, dim=-1) +def _kron(matrix_A: torch.Tensor, matrix_B: torch.Tensor) -> torch.Tensor: + r"""(batched) Kronecker product + + Args: + matrix_A: input (batched) matrix + matrix_B: input (batched) matrix + + Returns: + The Kronecker product of the two (batched) matrices + + Note: + See https://discuss.pytorch.org/t/kronecker-product/3919/11 + """ + mat_dim = torch.Size([matrix_A.shape[-2] * matrix_B.shape[-2], matrix_A.shape[-1] * matrix_B.shape[-1]]) + output = matrix_A.unsqueeze(-1).unsqueeze(-3) * matrix_B.unsqueeze(-2).unsqueeze(-4) + batch_dim = output.shape[:-4] + return output.reshape(batch_dim + mat_dim) + def _nkron( - matrix_A: torch.Tensor, matrix_B: torch.Tensor, *args: torch.Tensor + matrix_1st: torch.Tensor, *args: torch.Tensor ) -> torch.Tensor: - batch_dim = list(matrix_A.shape[:-2]) - batch_size = [int(np.prod(batch_dim))] - - matrix_A = matrix_A.reshape(batch_size + list(matrix_A.shape[-2:])) - matrix_B = matrix_B.reshape(batch_size + list(matrix_B.shape[-2:])) - - def batch_kron(a, b): - siz1 = torch.Size([a.shape[-2] * b.shape[-2], a.shape[-1] * b.shape[-1]]) - res = a.unsqueeze(-1).unsqueeze(-3) * b.unsqueeze(-2).unsqueeze(-4) - siz0 = res.shape[:-4] - return res.reshape(siz0 + siz1) - - initial_kron = torch.stack([torch.kron(matrix_A[i], matrix_B[i]) for i in range(matrix_A.size(0))]) - return reduce(batch_kron, args, initial_kron).squeeze() + return reduce(_kron, args, matrix_1st).squeeze() def _partial_transpose(state: torch.Tensor, transpose_idx: List[int], system_dim: List[int]) -> torch.Tensor: @@ -472,8 +467,6 @@ def backward(ctx, G): return _adjoint(A, G, _logm_scipy) - - class __Sqrtm(torch.autograd.Function): @staticmethod def forward(ctx, A): @@ -493,7 +486,6 @@ def backward(ctx, G): return _adjoint(A, G, _sqrtm_scipy) - _logm = __Logm.apply _sqrtm = __Sqrtm.apply @@ -623,6 +615,5 @@ def _prob_sample(distributions: torch.Tensor, shots: int = 1024, keys = [f'{i:0{num_bits}b}' if binary else str(i) for i in range(num_elements)] - results = dict(OrderedDict((key, counts[:, i]) for i, key in enumerate(keys))) - - return results \ No newline at end of file + results = OrderedDict((key, counts[:, i]) for i, key in enumerate(keys)) + return dict(results) diff --git a/quairkit/core/utils/matrix.py b/quairkit/core/utils/matrix.py new file mode 100644 index 0000000..170ab6d --- /dev/null +++ b/quairkit/core/utils/matrix.py @@ -0,0 +1,570 @@ +# !/usr/bin/env python3 +# Copyright (c) 2023 QuAIR team. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r""" +Gate matrices. +""" + +import math + +import numpy as np +import torch + +from .. import utils + + +def __get_complex_dtype(float_dtype: torch.dtype) -> torch.dtype: + if float_dtype == torch.float32: + complex_dtype = torch.complex64 + elif float_dtype == torch.float64: + complex_dtype = torch.complex128 + else: + raise ValueError( + f"The dtype should be torch.float32 or torch.float64: received {float_dtype}") + return complex_dtype + + +def _zero(dtype: torch.dtype = None, device: torch.device = None) -> torch.Tensor: + return torch.tensor([0], dtype=dtype, device=device) + + +def _one(dtype: torch.dtype = None, device: torch.device = None) -> torch.Tensor: + return torch.tensor([1], dtype=dtype, device=device) + + +def _phase(dim: int, dtype: torch.dtype = torch.complex128) -> torch.Tensor: + w = np.exp(2 * math.pi * 1j / dim) + return torch.from_numpy(np.diag([w**i for i in range(dim)])).to(dtype) + + +def _shift(dim: int, dtype: torch.dtype = torch.complex128) -> torch.Tensor: + return torch.roll(torch.eye(dim), shifts=1, dims=0).to(dtype) + + +def _grover(oracle: torch.Tensor) -> torch.Tensor: + complex_dtype = oracle.dtype + dimension = oracle.shape[0] + ket_zero = torch.eye(dimension, 1).to(complex_dtype) + + diffusion_op = (2 + 0j) * ket_zero @ ket_zero.T - torch.eye(dimension) + reflection_op = torch.kron(_z(), torch.eye(dimension // 2)).to(complex_dtype) + + return oracle @ diffusion_op @ oracle.conj().T @ reflection_op + + +def _qft(num_qubits: int, dtype: torch.dtype = torch.complex128) -> torch.Tensor: + N = 2**num_qubits + omega_N = np.exp(1j * 2 * math.pi / N) + + qft_mat = np.ones([N, N]).astype("complex128") + for i in range(1, N): + for j in range(1, N): + qft_mat[i, j] = omega_N ** ((i * j) % N) + + return torch.tensor(qft_mat / math.sqrt(N)).to(dtype) + + +def _h(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + element = math.sqrt(2) / 2 + gate_matrix = [ + [element, element], + [element, -element], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _s(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0], + [0, 1j], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _sdg(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0], + [0, -1j], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _t(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0], + [0, math.sqrt(2) / 2 + math.sqrt(2) / 2 * 1j], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _tdg(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0], + [0, math.sqrt(2) / 2 - math.sqrt(2) / 2 * 1j], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _eye(dim: int = 2, dtype: torch.dtype = torch.complex128) -> torch.Tensor: + return torch.eye(dim, dtype=dtype) + + +def _x(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [0, 1], + [1, 0], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _y(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [0, -1j], + [1j, 0], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _z(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0], + [0, -1], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _p(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0, _1 = torch.zeros_like(theta), torch.ones_like(theta) + gate_matrix = [ + _1, _0, + _0, torch.cos(theta) + 1j * torch.sin(theta), + ] + return torch.cat(gate_matrix).view([2, 2]) + + +def _rx(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + gate_matrix = [ + torch.cos(theta / 2), -1j * torch.sin(theta / 2), + -1j * torch.sin(theta / 2), torch.cos(theta / 2), + ] + return torch.cat(gate_matrix).view([2, 2]) + + +def _ry(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + gate_matrix = [ + torch.cos(theta / 2), -torch.sin(theta / 2), + torch.sin(theta / 2), torch.cos(theta / 2), + ] + return torch.cat(gate_matrix).view([2, 2]) + 0j + + +def _rz(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0 = torch.zeros_like(theta) + gate_matrix = [ + torch.exp(-1j * theta / 2), _0, + _0, torch.exp(1j * theta / 2), + ] + return torch.cat(gate_matrix).view([2, 2]) + + +def _u3(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([3, 1]) + theta, phi, lam = theta[0], theta[1], theta[2] + gate_matrix = [ + torch.cos(theta / 2), -torch.exp(1j * lam) * torch.sin(theta / 2), + torch.exp(1j * phi) * torch.sin(theta / 2), torch.exp(1j * (phi + lam)) * torch.cos(theta / 2), + ] + return torch.cat(gate_matrix).view([2, 2]) + + + +# ------------------------------------------------- Split line ------------------------------------------------- + + #Belows are multi-qubit matrices. + + + +def _cnot(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 1], + [0, 0, 1, 0], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _cy(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, -1j], + [0, 0, 1j, 0], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _cz(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, -1], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _swap(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0, 0, 0], + [0, 0, 1, 0], + [0, 1, 0, 0], + [0, 0, 0, 1], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + + +def _cp(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0, _1 = torch.zeros_like(theta), torch.ones_like(theta) + gate_matrix = [ + _1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, _1, _0, + _0, _0, _0, torch.cos(theta) + 1j * torch.sin(theta), + ] + return torch.cat(gate_matrix).view([4, 4]) + + +def _crx(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0, _1 = torch.zeros_like(theta), torch.ones_like(theta) + gate_matrix = [ + _1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, torch.cos(theta / 2), -1j * torch.sin(theta / 2), + _0, _0, -1j * torch.sin(theta / 2), torch.cos(theta / 2), + ] + return torch.cat(gate_matrix).view([4, 4]) + + +def _cry(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0, _1 = torch.zeros_like(theta), torch.ones_like(theta) + gate_matrix = [ + _1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, torch.cos(theta / 2), -torch.sin(theta / 2), + _0, _0, torch.sin(theta / 2), torch.cos(theta / 2), + ] + return torch.cat(gate_matrix).view([4, 4]) + 0j + + +def _crz(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0, _1 = torch.zeros_like(theta), torch.ones_like(theta) + gate_matrix = [ + _1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, torch.cos(theta / 2) - 1j * torch.sin(theta / 2), _0, + _0, _0, _0, torch.cos(theta / 2) + 1j * torch.sin(theta / 2), + ] + return torch.cat(gate_matrix).view([4, 4]) + + +def _cu(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([4, 1]) + _0, _1 = torch.zeros_like(theta[-1]), torch.ones_like(theta[-1]) + + param1 = torch.cos(theta[0] / 2) * (torch.cos(theta[3]) + 1j * torch.sin(theta[3])) + param2 = -torch.sin(theta[0] / 2) * (torch.cos(theta[2] + theta[3]) + 1j * torch.sin(theta[2] + theta[3])) + param3 = torch.sin(theta[0] / 2) * (torch.cos(theta[1] + theta[3]) + 1j * torch.sin(theta[1] + theta[3])) + param4 = torch.cos(theta[0] / 2) * ( + torch.cos(theta[1] + theta[2] + theta[3]) + + 1j * torch.sin(theta[1] + theta[2] + theta[3]) + ) + + gate_matrix = [ + _1, _0, _0, _0, + _0, _1, _0, _0, + _0, _0, param1, param2, + _0, _0, param3, param4, + ] + return torch.cat(gate_matrix).view([4, 4]) + + +def _rxx(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0 = torch.zeros_like(theta) + param1 = torch.cos(theta / 2) + param2 = -1j * torch.sin(theta / 2) + + gate_matrix = [ + param1, _0, _0, param2, + _0, param1, param2, _0, + _0, param2, param1, _0, + param2, _0, _0, param1, + ] + return torch.cat(gate_matrix).view([4, 4]) + + +def _ryy(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0 = torch.zeros_like(theta) + + param1 = torch.cos(theta / 2) + param2 = -1j * torch.sin(theta / 2) + param3 = 1j * torch.sin(theta / 2) + + gate_matrix = [ + param1, _0, _0, param3, + _0, param1, param2, _0, + _0, param2, param1, _0, + param3, _0, _0, param1, + ] + return torch.cat(gate_matrix).view([4, 4]) + + +def _rzz(theta: torch.Tensor) -> torch.Tensor: + theta = theta.view([1]) + _0 = torch.zeros_like(theta) + + param1 = torch.cos(theta / 2) - 1j * torch.sin(theta / 2) + param2 = torch.cos(theta / 2) + 1j * torch.sin(theta / 2) + + gate_matrix = [ + param1, _0, _0, _0, + _0, param2, _0, _0, + _0, _0, param2, _0, + _0, _0, _0, param1, + ] + return torch.cat(gate_matrix).view([4, 4]) + + +def _ms(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + val1 = math.sqrt(2) / 2 + val2 = 1j / math.sqrt(2) + gate_matrix = [ + [val1, 0, 0, val2], + [0, val1, val2, 0], + [0, val2, val1, 0], + [val2, 0, 0, val1], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _cswap(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _toffoli(dtype: torch.dtype = torch.complex128) -> torch.Tensor: + gate_matrix = [ + [1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0], + ] + return torch.tensor(gate_matrix, dtype=dtype) + + +def _universal2(theta: torch.Tensor) -> torch.Tensor: + theta, complex_dtype = theta.view([15]), __get_complex_dtype(theta.dtype) + unitary = _eye(4, complex_dtype) + _cnot_gate = _cnot(complex_dtype) + + unitary = utils.linalg._unitary_transformation( + unitary, _u3(theta[[0, 1, 2]]), qubit_idx=0, num_qubits=2 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _u3(theta[[3, 4, 5]]), qubit_idx=1, num_qubits=2 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _cnot_gate, qubit_idx=[1, 0], num_qubits=2 + ) + + unitary = utils.linalg._unitary_transformation( + unitary, _rz(theta[[6]]), qubit_idx=0, num_qubits=2 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _ry(theta[[7]]), qubit_idx=1, num_qubits=2 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _cnot_gate, qubit_idx=[0, 1], num_qubits=2 + ) + + unitary = utils.linalg._unitary_transformation( + unitary, _ry(theta[[8]]), qubit_idx=1, num_qubits=2 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _cnot_gate, qubit_idx=[1, 0], num_qubits=2 + ) + + unitary = utils.linalg._unitary_transformation( + unitary, _u3(theta[[9, 10, 11]]), qubit_idx=0, num_qubits=2 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _u3(theta[[12, 13, 14]]), qubit_idx=1, num_qubits=2 + ) + + return unitary + + +def _universal3(theta: torch.Tensor) -> torch.Tensor: + theta, complex_dtype = theta.view([81]), __get_complex_dtype(theta.dtype) + unitary = _eye(8, complex_dtype) + __h, __s, __cnot = _h(complex_dtype), _s(complex_dtype), _cnot(complex_dtype) + + psi = torch.reshape(theta[:60], shape=[4, 15]) + phi = torch.reshape(theta[60:], shape=[7, 3]) + + def __block_u(_unitary, _theta): + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, _ry(_theta[0]), qubit_idx=1, num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[0, 1], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, _ry(_theta[1]), qubit_idx=1, num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[0, 1], num_qubits=3 + ) + + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation(_unitary, __h, qubit_idx=2, num_qubits=3) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 0], num_qubits=3 + ) + + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[0, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, _rz(_theta[2]), qubit_idx=2, num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[0, 2], num_qubits=3 + ) + return _unitary + + def __block_v(_unitary, _theta): + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[2, 0], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[2, 1], num_qubits=3 + ) + + _unitary = utils.linalg._unitary_transformation( + _unitary, _ry(_theta[0]), qubit_idx=2, num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, _ry(_theta[1]), qubit_idx=2, num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 2], num_qubits=3 + ) + + _unitary = utils.linalg._unitary_transformation(_unitary, __s, qubit_idx=2, num_qubits=3) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[2, 0], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[0, 1], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[1, 0], num_qubits=3 + ) + + _unitary = utils.linalg._unitary_transformation(_unitary, __h, qubit_idx=2, num_qubits=3) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[0, 2], num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, _rz(_theta[2]), qubit_idx=2, num_qubits=3 + ) + _unitary = utils.linalg._unitary_transformation( + _unitary, __cnot, qubit_idx=[0, 2], num_qubits=3 + ) + return _unitary + + unitary = utils.linalg._unitary_transformation( + unitary, _universal2(psi[0]), qubit_idx=[0, 1], num_qubits=3 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _u3(phi[0, 0:3]), qubit_idx=2, num_qubits=3 + ) + unitary = __block_u(unitary, phi[1]) + + unitary = utils.linalg._unitary_transformation( + unitary, _universal2(psi[1]), qubit_idx=[0, 1], num_qubits=3 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _u3(phi[2, 0:3]), qubit_idx=2, num_qubits=3 + ) + unitary = __block_v(unitary, phi[3]) + + unitary = utils.linalg._unitary_transformation( + unitary, _universal2(psi[2]), qubit_idx=[0, 1], num_qubits=3 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _u3(phi[4, 0:3]), qubit_idx=2, num_qubits=3 + ) + unitary = __block_u(unitary, phi[5]) + + unitary = utils.linalg._unitary_transformation( + unitary, _universal2(psi[3]), qubit_idx=[0, 1], num_qubits=3 + ) + unitary = utils.linalg._unitary_transformation( + unitary, _u3(phi[6, 0:3]), qubit_idx=2, num_qubits=3 + ) + return unitary diff --git a/quairkit/core/utils/qinfo.py b/quairkit/core/utils/qinfo.py index b738ad7..764f418 100644 --- a/quairkit/core/utils/qinfo.py +++ b/quairkit/core/utils/qinfo.py @@ -18,7 +18,6 @@ """ -import itertools import math from typing import Callable, List, Optional, Tuple, Union @@ -362,3 +361,265 @@ def _mana_channel( ) # Compute the mana of channels return torch.log2(torch.max(torch.sum(torch.abs(W), dim=-1), dim=-1).values) + + +def _stab_renyi( + density: torch.Tensor, + alpha: torch.Tensor, + num: int, + indices: torch.Tensor, + pauli: torch.Tensor, + n: int, +) -> torch.Tensor: + + density = density.to(torch.complex128) + + # Add new dimensions for broadcasting + # density.unsqueeze(1) Shape: (m, 1, 2^n, 2^n) + # pauli.unsqueeze(0) Shape: (1, 4^n, 2^n, 2^n) + + Chi_func = ( + utils.linalg._trace( + density.unsqueeze(1) @ pauli.unsqueeze(0), axis1=-2, axis2=-1 + ).real + ) ** 2 / ( + 2**n + ) # shape (m,4^n) + + def _compute_p_norm_vector(vec: torch.Tensor, p: torch.Tensor) -> torch.Tensor: + if vec.dim() == 1: + vec = vec.unsqueeze(0) # Convert to (1, P) + # Compute the 1/2-norm + p_norm = vec.abs().pow(p).sum(dim=1).pow(1 / p) + return p_norm + + alpha_norm = _compute_p_norm_vector(Chi_func, alpha) + + # Initialize a result tensor with NaN values + result_counts = torch.full((num,), float("nan"), dtype=torch.float) + + # Fill in the counts for density matrices + result_counts[indices] = alpha_norm.to(result_counts.dtype) + + # Compute the alpha-stabilizer renyi entropy + return alpha / (1 - alpha) * torch.log2(result_counts) - math.log2(2**n) + + +def _stab_nullity( + unitary: torch.Tensor, + num_unitary: int, + unitary_indices: torch.Tensor, + pauli: torch.Tensor, + n: int, +) -> torch.Tensor: + + # Expand dimensions for broadcasting + unitary_expanded = unitary.unsqueeze(1).unsqueeze( + 2 + ) # Shape (batchsize, 1, 1, 2^n, 2^n) + unitary_d_expanded = ( + utils.linalg._dagger(unitary).unsqueeze(1).unsqueeze(2) + ) # Shape (batchsize, 1, 1, 2^n, 2^n) + pauli_expanded_i = pauli.unsqueeze(0).unsqueeze(2) # Shape (1, 4^n, 1, 2^n, 2^n) + pauli_expanded_k = pauli.unsqueeze(0).unsqueeze(1) # Shape (1, 1, 4^n, 2^n, 2^n) + + # Third compute the Pauli function of unitary varing Pauli + paulifunc = utils.linalg._trace( + pauli_expanded_i @ unitary_expanded @ pauli_expanded_k @ unitary_d_expanded, + axis1=-2, + axis2=-1, + ).real / ( + 2**n + ) # Shape (m, 4^n, 4^n, 2^n, 2^n) to Shape (m, 4^n, 4^n) + + # Count the number of +1 and -1 of paulifunc for every unitary to get the s(U) + # Define a small tolerance + tolerance = 1e-6 + # Create the mask with tolerance + mask = (torch.abs(paulifunc - 1) < tolerance) | ( + torch.abs(paulifunc + 1) < tolerance + ) + + # Count the occurrences of True values in the mask + counts = torch.sum(mask, dim=(-2, -1), dtype=torch.float) + + # Initialize a result tensor with NaN values + result_counts = torch.full((num_unitary,), float("nan"), dtype=torch.float) + + # Fill in the counts for unitary matrices + result_counts[unitary_indices] = counts + + # Compute the unitary-stabilizer nullity + return 2 * n - torch.log2(result_counts) + + +def _mana_state(state: torch.Tensor, A: torch.Tensor, dim: int) -> torch.Tensor: + state = state.to(torch.complex128) + # Call trace function to get Wigner function + # If state has shape (d, d), expand its dimensions to (1, d, d) + state = state.unsqueeze(0) if state.dim() == 2 else state + W = 1 / dim * utils.linalg._trace(state.unsqueeze(1) @ A.unsqueeze(0)).real + + return torch.log2((torch.abs(W).sum(dim=-1))) + + +def _mana_channel( + channel: torch.Tensor, + A_a: torch.Tensor, + A_b: torch.Tensor, + out_dim: int, + in_dim: int, +) -> torch.Tensor: + channel = channel.to(torch.complex128) + # Compute the Kronecker product + A_kron = torch.einsum("aij,bkl->abikjl", A_a.transpose(1, 2), A_b).reshape( + in_dim**2, out_dim**2, in_dim * out_dim, in_dim * out_dim + ) + # compute the wigner function of a quantum channel + channel = channel.unsqueeze(0) if channel.dim() == 2 else channel + W = ( + 1 + / out_dim + * utils.linalg._trace( + channel.unsqueeze(1).unsqueeze(2) @ A_kron.unsqueeze(0) + ).real + ) + # Compute the mana of channels + return torch.log2(torch.max(torch.sum(torch.abs(W), dim=-1), dim=-1).values) + +def _general_state_fidelity(rho: torch.Tensor, sigma: torch.Tensor) -> torch.Tensor: + trace_norm_term = _state_fidelity(rho, sigma) + general_fidelity = (trace_norm_term + torch.sqrt( + (1 - utils.linalg._trace(rho)) * (1 - utils.linalg._trace(sigma)) + )).real + return general_fidelity.view(rho.shape[:-2] or sigma.shape[:-2]) + +def _mutual_information(rho: torch.Tensor, dim_A: int, dim_B: int) -> torch.Tensor: + system_dim = [dim_A, dim_B] + rho_A = utils.linalg._partial_trace(rho, [1], system_dim) + rho_B = utils.linalg._partial_trace(rho, [0], system_dim) + return _von_neumann_entropy(rho_A) + _von_neumann_entropy(rho_B) - _von_neumann_entropy(rho) + + +def _link( + JE: Tuple[torch.Tensor, str, List[int], List[int]], + JF: Tuple[torch.Tensor, str, List[int], List[int]] + ) -> Tuple[torch.Tensor, str, List[int], List[int]]: + # FIXME: does not work for comb case, i.e., when PI -> OF and O -> I + # Unpack variables + JE_matrix, JE_entry_exit, JE_input_dims, JE_output_dims = JE + JF_matrix, JF_entry_exit, JF_input_dims, JF_output_dims = JF + + JE_entry, JE_exit = JE_entry_exit.split('->') + JF_entry, JF_exit = JF_entry_exit.split('->') + + # Calculate overlap + overlap_subsystem = set(JE_exit).intersection(set(JF_entry)) + + # Generate index based on overlap for subsequent permutation + new_index = list(range(len(JE_entry) + len(JE_exit))) + overlap_indices = [JE_exit.index(x) + len(JE_entry) for x in overlap_subsystem] + exchange_indices = list(range(len(overlap_subsystem))) + + for old, new in zip(overlap_indices, exchange_indices): + new_index[new], new_index[old] = new_index[old], new_index[new] + + # Permute, partial transpose, and permute back + JE_choi_permuted = utils.linalg._permute_systems( + JE_matrix, + new_index, + dim_list=JE_input_dims + JE_output_dims + ) + + JE_transposed = utils.linalg._partial_transpose( + JE_choi_permuted, [0], + [2 ** len(overlap_subsystem), JE_choi_permuted.shape[0] // (2 ** len(overlap_subsystem))] + ) + + JE_choi_transposed = utils.linalg._permute_systems( + JE_transposed, + new_index, + JE_input_dims + JE_output_dims + ) + + # Generate dictionaries for each system and its corresponding dimension + JE_pairs = list(zip(JE_entry, JE_input_dims)) + list(zip(JE_exit, JE_output_dims)) + JF_pairs = list(zip(JF_entry, JF_input_dims)) + list(zip(JF_exit, JF_output_dims)) + + JE_dim_dict = dict(JE_pairs) + JF_dim_dict = dict(JF_pairs) + + # Remove overlap subsystem from dictionaries + for letter in overlap_subsystem: + JE_dim_dict.pop(letter, None) + JF_dim_dict.pop(letter, None) + + # Get the non-overlapping dimensions + non_overlap_dims_E = list(JE_dim_dict.values()) + non_overlap_dims_F = list(JF_dim_dict.values()) + + # Multiply the two Choi matrices + multiplication = ( + torch.kron(JE_choi_transposed.contiguous(), torch.eye(np.prod(non_overlap_dims_F))) + @ torch.kron(torch.eye(np.prod(non_overlap_dims_E)), JF_matrix.contiguous()) + ) + + # Generate index for subsequent partial trace + total_str = ( + JE_entry + + ''.join([c for c in JE_exit if c not in overlap_subsystem]) + + JF_entry + + JF_exit + ) + + index_dict = {char: idx for idx, char in enumerate(total_str)} + for letter in overlap_subsystem: + index_dict.pop(letter, None) + + # Calculate the partial trace over the joint system + result_matrix = utils.linalg._partial_trace_discontiguous( + multiplication, + list(index_dict.values()) + ) + + # Permute the result matrix to the correct order + combined_str = ( + JE_entry + + ''.join([c for c in JE_exit if c not in overlap_subsystem]) + + ''.join([c for c in JF_entry if c not in overlap_subsystem]) + + JF_exit + ) + index_nonoverlap_dict = {char: idx for idx, char in enumerate(combined_str)} + + permute_str = ( + JE_entry + + ''.join([c for c in JF_entry if c not in overlap_subsystem]) + + ''.join([c for c in JE_exit if c not in overlap_subsystem]) + + JF_exit + ) + permute_list = [index_nonoverlap_dict[char] for char in permute_str] + + all_dims = non_overlap_dims_E + non_overlap_dims_F + permute_dims = [all_dims[i] for i in permute_list] + + result_matrix = utils.linalg._permute_systems(result_matrix, permute_list, permute_dims) + + # Generate the entry and exit string for the final Choi matrix + entry_exit = ( + JE_entry + + ''.join([c for c in JF_entry if c not in overlap_subsystem]) + + '->' + + ''.join([c for c in JE_exit if c not in overlap_subsystem]) + + JF_exit + ) + + # Extract the input and output dimensions + entry, exit = entry_exit.split('->') + + entry_index = [index_nonoverlap_dict[char] for char in entry] + input_dims = [all_dims[i] for i in entry_index] + + exit_index = [index_nonoverlap_dict[char] for char in exit] + output_dims = [all_dims[i] for i in exit_index] + + return result_matrix, entry_exit, input_dims, output_dims diff --git a/quairkit/core/utils/representation.py b/quairkit/core/utils/representation.py new file mode 100644 index 0000000..1a682e4 --- /dev/null +++ b/quairkit/core/utils/representation.py @@ -0,0 +1,227 @@ +# !/usr/bin/env python3 +# Copyright (c) 2023 QuAIR team. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r""" +Representations of channels +""" + +import torch + + +def _bit_flip_kraus(prob: torch.Tensor) -> torch.Tensor: + prob = prob.view([1]) + + _0 = torch.zeros_like(prob) + kraus_oper = [ + # E0 + torch.sqrt(1 - prob), _0, + _0, torch.sqrt(1 - prob), + # E1 + _0, torch.sqrt(prob), + torch.sqrt(prob), _0 + ] + kraus_oper = torch.cat(kraus_oper).view([2, 2, 2]) + return kraus_oper + 0j + + +def _phase_flip_kraus(prob: torch.Tensor) -> torch.Tensor: + prob = prob.view([1]) + _0 = torch.zeros_like(prob) + kraus_oper = [ + # E0 + torch.sqrt(1 - prob), _0, + _0, torch.sqrt(1 - prob), + # E1 + torch.sqrt(prob), _0, + _0, -torch.sqrt(prob) + ] + kraus_oper = torch.cat(kraus_oper).view([2, 2, 2]) + return kraus_oper + 0j + + +def _bit_phase_flip_kraus(prob: torch.Tensor) -> torch.Tensor: + prob = prob.view([1]) + _0 = torch.zeros_like(prob) + kraus_oper = [ + # E0 + torch.sqrt(1 - prob), _0, + _0, torch.sqrt(1 - prob), + # E1 + _0, -1j * torch.sqrt(prob), + 1j * torch.sqrt(prob), _0, + ] + kraus_oper = torch.cat(kraus_oper).view([2, 2, 2]) + return kraus_oper + 0j + + +def _amplitude_damping_kraus(gamma: torch.Tensor) -> torch.Tensor: + gamma = gamma.view([1]) + _0, _1 = torch.zeros_like(gamma), torch.ones_like(gamma) + kraus_oper = [ + # E0 + _1, _0, + _0, torch.sqrt(1 - gamma), + # E1 + _0, torch.sqrt(gamma), + _0, _0, + ] + kraus_oper = torch.cat(kraus_oper).view([2, 2, 2]) + return kraus_oper + 0j + + +def _generalized_amplitude_damping_kraus( + gamma: torch.Tensor, prob: torch.Tensor) -> torch.Tensor: + gamma, prob = gamma.view([1]), prob.view([1]) + _0 = torch.zeros_like(prob) + kraus_oper = [ + # E0 + torch.sqrt(prob), _0, + _0, torch.sqrt(prob) * torch.sqrt(1 - gamma), + # E1 + _0, torch.sqrt(prob) * torch.sqrt(gamma), + _0, _0, + # E2 + torch.sqrt(1 - prob) * torch.sqrt(1 - gamma), _0, + _0, torch.sqrt(1 - prob), + # E3 + _0, _0, + torch.sqrt(1 - prob) * torch.sqrt(gamma), _0, + ] + kraus_oper = torch.cat(kraus_oper).view([4, 2, 2]) + return kraus_oper + 0j + + +def _phase_damping_kraus(gamma: torch.Tensor) -> torch.Tensor: + gamma = gamma.view([1]) + _0, _1=torch.zeros_like(gamma), torch.ones_like(gamma) + kraus_oper = [ + # E0 + _1, _0, + _0, torch.sqrt(1 - gamma), + # E1 + _0, _0, + _0, torch.sqrt(gamma), + ] + kraus_oper = torch.cat(kraus_oper).view([2, 2, 2]) + return kraus_oper + 0j + + +def _depolarizing_kraus(prob: torch.Tensor) -> torch.Tensor: + prob = prob.view([1]) + _0 = torch.zeros_like(prob) + kraus_oper = [ + # E0 + torch.sqrt(1 - 3 * prob / 4), _0, + _0, torch.sqrt(1 - 3 * prob / 4), + # E1 + _0, torch.sqrt(prob / 4), + torch.sqrt(prob / 4), _0, + # E2 + _0, -1j * torch.sqrt(prob / 4), + 1j * torch.sqrt(prob / 4), _0, + # E3 + torch.sqrt(prob / 4), _0, + _0, (-1 * torch.sqrt(prob / 4)), + ] + kraus_oper = torch.cat(kraus_oper).view([4, 2, 2]) + return kraus_oper + + +def _pauli_kraus(prob: torch.Tensor) -> torch.Tensor: + prob_x, prob_y, prob_z = prob.view([3, 1]) + assert (prob_sum := torch.sum(prob)) <= 1, \ + f"The sum of input probabilities should not be greater than 1: received {prob_sum.item()}" + prob_i = (1 - prob_sum).view([1]) + _0 = torch.zeros_like(prob_i) + + kraus_oper = [ + # E0 + torch.sqrt(prob_i), _0, + _0, torch.sqrt(prob_i), + # E1 + _0, torch.sqrt(prob_x), + torch.sqrt(prob_x), _0, + # E2 + _0, -1j * torch.sqrt(prob_y), + 1j * torch.sqrt(prob_y), _0, + # E3 + torch.sqrt(prob_z), _0, + _0, (-torch.sqrt(prob_z)), + ] + kraus_oper = torch.cat(kraus_oper).view([4, 2, 2]) + return kraus_oper + + +def _reset_kraus(prob: torch.Tensor) -> torch.Tensor: + prob_0, prob_1 = prob.view([2, 1]) + assert (prob_sum := torch.sum(prob)) <= 1, \ + f"The sum of input probabilities should not be greater than 1: received {prob_sum.item()}" + prob_i = (1 - prob_sum).view([1]) + _0 = torch.zeros_like(prob_i) + kraus_oper = [ + # E0 + torch.sqrt(prob_0), _0, + _0, _0, + # E1 + _0, torch.sqrt(prob_0), + _0, _0, + # E2 + _0, _0, + torch.sqrt(prob_1), _0, + # E3 + _0, _0, + _0, torch.sqrt(prob_1), + # E4 + torch.sqrt(prob_i), _0, + _0, torch.sqrt(prob_i), + ] + kraus_oper = torch.cat(kraus_oper).view([5, 2, 2]) + return kraus_oper + 0j + + +def _thermal_relaxation_kraus( + const_t: torch.Tensor, exec_time: torch.Tensor) -> torch.Tensor: + + t1, t2 = const_t.view([2, 1]) + assert t2 <= t1, \ + f"The relaxation time T2 and T1 must satisfy T2 <= T1: received T2 {t2} and T1{t1}" + + exec_time = exec_time.view([1]) / 1000 + prob_reset = 1 - torch.exp(-exec_time / t1) + prob_z = (1 - prob_reset) * (1 - torch.exp(-exec_time / t2) * torch.exp(exec_time / t1)) / 2 + prob_z = torch.zeros_like(exec_time) if torch.abs(prob_z) <= 0 else prob_z + prob_i = 1 - prob_reset - prob_z + _0 = torch.zeros_like(exec_time) + kraus_oper = [ + # E0 + torch.sqrt(prob_i), _0, + _0, torch.sqrt(prob_i), + # E1 + torch.sqrt(prob_z), _0, + _0, -torch.sqrt(prob_z), + # E2 + torch.sqrt(prob_reset), _0, + _0, _0, + # E3 + _0, torch.sqrt(prob_reset), + _0, _0, + ] + kraus_oper = torch.cat(kraus_oper).view([4, 2, 2]) + return kraus_oper + 0j + + +def _replacement_choi(sigma: torch.Tensor) -> torch.Tensor: + return torch.kron(torch.eye(sigma.shape[-1]), sigma) + diff --git a/quairkit/database/hamiltonian.py b/quairkit/database/hamiltonian.py index d120dc2..4127659 100644 --- a/quairkit/database/hamiltonian.py +++ b/quairkit/database/hamiltonian.py @@ -39,6 +39,29 @@ def ising_hamiltonian(edges: torch.Tensor, vertices: torch.Tensor) -> Hamiltonia Returns: H_{Ising} + + .. code-block:: python + + edges = torch.tensor([[0, 1, 0.5], + [1, 0, 0.2], + [0.5, 0.2, 0]]) + + vertices = torch.tensor([0.3, 0.4, 0.1]) + + hamiltonian = ising_hamiltonian(edges, vertices) + + print(f'The Ising_Hamiltonian is \n {hamiltonian}.') + + :: + + The Ising_Hamiltonian is + 1.0 Z0, Z1 + 0.5 Z0, Z2 + 0.20000000298023224 Z1, Z2 + 0.30000001192092896 X0 + 0.4000000059604645 X1 + 0.10000000149011612 X2. + """ h_list = [] shape_of_edges = edges.shape @@ -65,6 +88,8 @@ def ising_hamiltonian(edges: torch.Tensor, vertices: torch.Tensor) -> Hamiltonia return Hamiltonian(h_list) + + def xy_hamiltonian(edges: torch.Tensor) -> Hamiltonian: r"""Compute the Ising Hamiltonian @@ -79,6 +104,32 @@ def xy_hamiltonian(edges: torch.Tensor) -> Hamiltonian: Returns: H_{XY} + + .. code-block:: python + + edges = torch.tensor([[ + [0, 0.7, 0], + [0.7, 0, 0.2], + [0, 0.2, 0] + ], + [ + [0, 0.5, 0], + [0.5, 0, 0.3], + [0, 0.3, 0] + ]]) + + H_XY = xy_hamiltonian(edges) + + print(f'The XY Hamiltonian is:\n{H_XY}') + + :: + + The XY Hamiltonian is: + 0.699999988079071 X0, X1 + 0.5 Y0, Y1 + 0.20000000298023224 X1, X2 + 0.30000001192092896 Y1, Y2 + """ h_list = [] shape_of_edges = edges.shape @@ -112,6 +163,41 @@ def heisenberg_hamiltonian(edges: torch.Tensor) -> Hamiltonian: Returns: H_{Heisenberg} + + .. code-block:: python + + edges = torch.tensor([ + [ + [0, 0.5, 0], + [0.5, 0, 0.2], + [0, 0.2, 0] + ], + [ + [0, 0.3, 0], + [0.3, 0, 0.4], + [0, 0.4, 0] + ], + [ + [0, 0.7, 0], + [0.7, 0, 0.1], + [0, 0.1, 0] + ] + ]) + + H_Heisenberg = heisenberg_hamiltonian(edges) + + print(f'The Heisenberg Hamiltonian is:\n{H_Heisenberg}') + + :: + + The Heisenberg Hamiltonian is: + 0.5 X0, X1 + 0.30000001192092896 Y0, Y1 + 0.699999988079071 Z0, Z1 + 0.20000000298023224 X1, X2 + 0.4000000059604645 Y1, Y2 + 0.10000000149011612 Z1, Z2 + """ h_list = [] shape_of_edges = edges.shape diff --git a/quairkit/database/matrix.py b/quairkit/database/matrix.py index 8dadf93..b1c856b 100644 --- a/quairkit/database/matrix.py +++ b/quairkit/database/matrix.py @@ -17,17 +17,14 @@ Gate matrices. """ -import math -from functools import reduce from typing import Callable, Optional -import numpy as np import torch from .. import database -from ..core import get_dtype -from ..core.intrinsic import _get_complex_dtype -from ..core.utils.linalg import _one, _unitary_transformation, _zero +from ..core import get_dtype, utils +from ..core.intrinsic import (_ArrayLike, _ParamLike, _SingleParamLike, + _type_fetch, _type_transform) __all__ = [ "phase", @@ -79,9 +76,20 @@ def phase(dim: int) -> torch.Tensor: Returns: Phase operator for qudit + + .. code-block:: python + + dim = 2 + phase_operator = phase(dim) + print(f'The phase_operator is:\n{phase_operator}') + + :: + + The phase_operator is: + tensor([[ 1.+0.0000e+00j, 0.+0.0000e+00j], + [ 0.+0.0000e+00j, -1.+1.2246e-16j]]) """ - w = np.exp(2 * np.pi * 1j / dim) - return torch.from_numpy(np.diag([w ** i for i in range(dim)])).to(get_dtype()) + return utils.matrix._phase(dim, get_dtype()) def shift(dim: int) -> torch.Tensor: @@ -92,11 +100,25 @@ def shift(dim: int) -> torch.Tensor: Returns: Shift operator for qudit + + .. code-block:: python + + dim = 2 + shift_operator = shift(dim) + print(f'The shift_operator is:\n{shift_operator}') + + :: + + The shift_operator is: + tensor([[0.+0.j, 1.+0.j], + [1.+0.j, 0.+0.j]]) + + """ - return torch.roll(torch.eye(dim), 1, dims=0).to(get_dtype()) + return utils.matrix._shift(dim, get_dtype()) -def grover_matrix(oracle: torch.Tensor) -> torch.Tensor: +def grover_matrix(oracle: _ArrayLike, dtype: Optional[torch.dtype] = None) -> _ArrayLike: r"""Construct the Grover operator based on ``oracle``. Args: @@ -108,24 +130,29 @@ def grover_matrix(oracle: torch.Tensor) -> torch.Tensor: .. math:: G = A (2 |0^n \rangle\langle 0^n| - I^n) A^\dagger \cdot (I - 2|1 \rangle\langle 1|) \otimes I^{n-1} + + .. code-block:: python + + oracle = torch.tensor([[0, 1], [1, 0]], dtype=torch.cfloat) + grover_op = grover_matrix(oracle) + print(f'The grover_matrix is:\n{grover_op}') + + :: + + The grover_matrix is: + tensor([[-1.+0.j, 0.+0.j], + [ 0.+0.j, -1.+0.j]]) """ - complex_dtype = oracle.dtype - dimension = oracle.shape[0] - ket_zero = torch.eye(dimension, 1).to(complex_dtype) - - diffusion_op = (2 + 0j) * ket_zero @ ket_zero.T - torch.eye(dimension).to(complex_dtype) - reflection_op = torch.kron(torch.tensor([[1, 0], [0, -1]], dtype=complex_dtype), torch.eye(dimension // 2)) - - return oracle @ diffusion_op @ oracle.conj().T @ reflection_op + oracle = _type_transform(oracle, "tensor") + return utils.matrix._grover(oracle) -def qft_matrix(num_qubits: int, dtype: torch.dtype=get_dtype()) -> torch.Tensor: +def qft_matrix(num_qubits: int) -> torch.Tensor: r"""Construct the quantum fourier transpose (QFT) gate. Args: num_qubits: number of qubits :math:`n` st. :math:`N = 2^n`. - dtype: the data type you used, default type is torch.complex64 Returns: a gate in below matrix form, here :math:`\omega_N = \text{exp}(\frac{2 \pi i}{N})` @@ -141,26 +168,25 @@ def qft_matrix(num_qubits: int, dtype: torch.dtype=get_dtype()) -> torch.Tensor: 1 & \omega_N^{N-1} & .. & \omega_N^{(N-1)^2} \end{bmatrix} \end{align} - - """ - N = 2 ** num_qubits - omega_N = np.exp(1j * 2 * math.pi / N) - - qft_mat = np.ones([N, N]).astype('complex128') - for i in range(1, N): - for j in range(1, N): - qft_mat[i, j] = omega_N ** ((i * j) % N) - - return torch.tensor(qft_mat / math.sqrt(N)).to(dtype) + + .. code-block:: python + + num_qubits = 1 + qft_gate = qft_matrix(num_qubits) + print(f'The QTF gate is:\n{qft_gate}') + + :: + + The QTF gate is: + tensor([[ 0.7071+0.0000e+00j, 0.7071+0.0000e+00j], + [ 0.7071+0.0000e+00j, -0.7071+8.6596e-17j]]) -# ------------------------------------------------- Split line ------------------------------------------------- -r""" - Belows are single-qubit matrices. -""" + """ + return utils.matrix._qft(num_qubits, get_dtype()) -def h(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def h() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -171,23 +197,24 @@ def h(dtype: Optional[torch.dtype] = None) -> torch.Tensor: 1&-1 \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of H gate. + .. code-block:: python + + H = h() + print(f'The Hadamard gate is:\n{H}') + + :: + + The Hadamard gate is: + tensor([[ 0.7071+0.j, 0.7071+0.j], + [ 0.7071+0.j, -0.7071+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - element = math.sqrt(2) / 2 - gate_matrix = [ - [element, element], - [element, -element], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._h(get_dtype()) -def s(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def s() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -198,22 +225,24 @@ def s(dtype: Optional[torch.dtype] = None) -> torch.Tensor: 0&i \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of S gate. + .. code-block:: python + + S = s() + print(f'The S gate is:\n{S}') + + :: + + The S gate is: + tensor([[1.+0.j, 0.+0.j], + [0.+0.j, 0.+1.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0], - [0, 1j], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._s(get_dtype()) -def sdg(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def sdg() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -224,22 +253,24 @@ def sdg(dtype: Optional[torch.dtype] = None) -> torch.Tensor: 0&-i \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of Sdg gate. - + + .. code-block:: python + + Sdg = sdg() + print(f'The dagger of S gate is:\n{Sdg}') + + :: + + The dagger of S gate is: + tensor([[1.+0.j, 0.+0.j], + [0.+0.j, -0.-1.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0], - [0, -1j], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._sdg(get_dtype()) -def t(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def t() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -249,22 +280,26 @@ def t(dtype: Optional[torch.dtype] = None) -> torch.Tensor: 0&e^\frac{i\pi}{4} \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of T gate. + .. code-block:: python + + T = t() + print(f'The T gate is:\n{T}') + + :: + + The T gate is: + tensor([[1.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.7071+0.7071j]]) + """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0], - [0, math.sqrt(2) / 2 + math.sqrt(2) / 2 * 1j], - ] - return torch.tensor(gate_matrix, dtype=dtype) + + return utils.matrix._t(get_dtype()) -def tdg(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def tdg() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -275,23 +310,27 @@ def tdg(dtype: Optional[torch.dtype] = None) -> torch.Tensor: 0&e^{-\frac{i\pi}{4}} \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: - the matrix of Sdg gate. + the matrix of Tdg gate. + + .. code-block:: python + + Tdg = tdg() + print(f'The dagger of T gate is:\n{Tdg}') + + :: + + The dagger of T gate is: + tensor([[1.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.7071-0.7071j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0], - [0, math.sqrt(2) / 2 - math.sqrt(2) / 2 * 1j], - ] - return torch.tensor(gate_matrix, dtype=dtype) + + return utils.matrix._tdg(get_dtype()) -def eye(dtype: Optional[torch.dtype] = None) -> torch.Tensor: - r"""Generate the matrix +def eye(dim: int = 2) -> torch.Tensor: + r"""Generate the matrix (when dim = 2) .. math:: @@ -301,16 +340,26 @@ def eye(dtype: Optional[torch.dtype] = None) -> torch.Tensor: \end{bmatrix} Args: - dtype: the dtype of this matrix. Defaults to ``None``. + dim: the dimension of the identity matrix. Defaults to the qubit case. Returns: the matrix of X gate. + .. code-block:: python + + I = eye() + print(f'The Identity Matrix is:\n{I}') + + :: + + The Identity Matrix is: + tensor([[1.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j]]) """ - return torch.eye(2, dtype=get_dtype() if dtype is None else dtype) + return utils.matrix._eye(dim, get_dtype()) -def x(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def x() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -320,22 +369,24 @@ def x(dtype: Optional[torch.dtype] = None) -> torch.Tensor: 1 & 0 \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of X gate. + .. code-block:: python + + X = x() + print(f'The Pauli X Matrix is:\n{X}') + + :: + + The Pauli X Matrix is: + tensor([[0.+0.j, 1.+0.j], + [1.+0.j, 0.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [0, 1], - [1, 0], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._x(get_dtype()) -def y(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def y() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -345,22 +396,24 @@ def y(dtype: Optional[torch.dtype] = None) -> torch.Tensor: i & 0 \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of Y gate. + .. code-block:: python + + Y = y() + print(f'The Pauli Y Matrix is:\n{Y}') + + :: + + The Pauli Y Matrix is: + tensor([[0.+0.j, -0.-1.j], + [0.+1.j, 0.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [0, -1j], - [1j, 0], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._y(get_dtype()) -def z(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def z() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -370,22 +423,24 @@ def z(dtype: Optional[torch.dtype] = None) -> torch.Tensor: 0 & -1 \end{bmatrix} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of Z gate. + .. code-block:: python + + Z = z() + print(f'The Pauli Z Matrix is:\n{Z}') + + :: + + The Pauli Z Matrix is: + tensor([[ 1.+0.j, 0.+0.j], + [ 0.+0.j, -1.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0], - [0, -1], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._z(get_dtype()) -def p(theta: torch.Tensor) -> torch.Tensor: +def p(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -401,17 +456,24 @@ def p(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of P gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + p_matrix = p(theta) + print(f'The P Gate is:\n{p_matrix}') + + :: + + The P Gate is: + tensor([[1.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.7071+0.7071j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - gate_matrix = [ - _one(dtype), _zero(dtype), - _zero(dtype), torch.cos(theta) + 1j * torch.sin(theta), - ] - return torch.cat(gate_matrix).view([2, 2]).to(dtype) + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._p(theta) + return _type_transform(mat, type_str) -def rx(theta: torch.Tensor) -> torch.Tensor: +def rx(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -427,17 +489,24 @@ def rx(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of R_X gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + R_x = rx(theta) + print(f'The R_x Gate is:\n{R_x}') + + :: + + The R_x Gate is: + tensor([[0.9239+0.0000j, 0.0000-0.3827j], + [0.0000-0.3827j, 0.9239+0.0000j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - gate_matrix = [ - torch.cos(theta / 2).reshape([1]), -1j * torch.sin(theta / 2).reshape([1]), - -1j * torch.sin(theta / 2).reshape([1]), torch.cos(theta / 2).reshape([1]), - ] - return torch.cat(gate_matrix).view([2, 2]).to(dtype) + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._rx(theta) + return _type_transform(mat, type_str) -def ry(theta: torch.Tensor) -> torch.Tensor: +def ry(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -453,17 +522,24 @@ def ry(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of R_Y gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + R_y = ry(theta) + print(f'The R_y Gate is:\n{R_y}') + + :: + + The R_y Gate is: + tensor([[ 0.9239+0.j, -0.3827+0.j], + [ 0.3827+0.j, 0.9239+0.j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - gate_matrix = [ - torch.cos(theta / 2), (-torch.sin(theta / 2)), - torch.sin(theta / 2), torch.cos(theta / 2), - ] - return torch.cat(gate_matrix).view([2, 2]).to(dtype) + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._ry(theta) + return _type_transform(mat, type_str) -def rz(theta: torch.Tensor) -> torch.Tensor: +def rz(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -479,17 +555,25 @@ def rz(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of R_Z gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + R_z = rz(theta) + print(f'The R_z Gate is:\n{R_z}') + + :: + + The R_z Gate is: + tensor([[0.9239-0.3827j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.9239+0.3827j]]) + """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - gate_matrix = [ - torch.exp(-1j * theta / 2), _zero(dtype), - _zero(dtype), torch.exp(1j * theta / 2) - ] - return torch.cat(gate_matrix).view([2, 2]).to(dtype) + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._rz(theta) + return _type_transform(mat, type_str) -def u3(theta: torch.Tensor) -> torch.Tensor: +def u3(theta: _ParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -508,26 +592,24 @@ def u3(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of U_3 gate. + .. code-block:: python + + theta = torch.tensor([[torch.pi / 4], [torch.pi / 3], [torch.pi / 6]]) + u3_matrix = u3(theta) + print(f'The U_3 Gate is:\n{u3_matrix}') + + :: + + The U_3 Gate is: + tensor([[ 9.2388e-01+0.0000j, -3.3141e-01-0.1913j], + [ 1.9134e-01+0.3314j, -4.0384e-08+0.9239j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([3, 1]) - theta, phi, lam = theta[0], theta[1], theta[2] - gate_matrix = [ - torch.cos(theta / 2), - -torch.exp(1j * lam) * torch.sin(theta / 2), - torch.exp(1j * phi) * torch.sin(theta / 2), - torch.exp(1j * (phi + lam)) * torch.cos(theta / 2) - ] - return torch.cat(gate_matrix).view([2, 2]).to(dtype) - - -# ------------------------------------------------- Split line ------------------------------------------------- -r""" - Belows are multi-qubit matrices. -""" + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._u3(theta) + return _type_transform(mat, type_str) -def cnot(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def cnot() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -543,24 +625,26 @@ def cnot(dtype: Optional[torch.dtype] = None) -> torch.Tensor: \end{bmatrix} \end{align} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of CNOT gate. - + + .. code-block:: python + + CNOT=cnot() + print(f'The CNOT Gate is:\n{CNOT}') + + :: + + The CNOT Gate is: + tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], + [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 0, 1], - [0, 0, 1, 0], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._cnot(get_dtype()) -def cy(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def cy() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -576,24 +660,26 @@ def cy(dtype: Optional[torch.dtype] = None) -> torch.Tensor: \end{bmatrix} \end{align} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of CY gate. + .. code-block:: python + + CY=cy() + print(f'The CY Gate is:\n{CY}') + + :: + + The CY Gate is: + tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, -0.-1.j], + [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 0, -1j], - [0, 0, 1j, 0], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._cy(get_dtype()) -def cz(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def cz() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -609,24 +695,27 @@ def cz(dtype: Optional[torch.dtype] = None) -> torch.Tensor: \end{bmatrix} \end{align} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of CZ gate. + .. code-block:: python + + CZ=cz() + print(f'The CZ Gate is:\n{CZ}') + + :: + + The CZ Gate is: + tensor([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, -1], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._cz(get_dtype()) + -def swap(dtype: Optional[torch.dtype] = None) -> torch.Tensor: +def swap() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -647,18 +736,23 @@ def swap(dtype: Optional[torch.dtype] = None) -> torch.Tensor: Returns: the matrix of SWAP gate. + .. code-block:: python + + SWAP=swap() + print(f'The SWAP Gate is:\n{SWAP}') + + :: + + The SWAP Gate is: + tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0, 0, 0], - [0, 0, 1, 0], - [0, 1, 0, 0], - [0, 0, 0, 1], - ] - return torch.tensor(gate_matrix, dtype=dtype) + return utils.matrix._swap(get_dtype()) -def cp(theta: torch.Tensor) -> torch.Tensor: +def cp(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -679,19 +773,26 @@ def cp(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of CP gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + CP = cp(theta) + print(f'The CP Gate is:\n{CP}') + + :: + + The CP Gate is: + tensor([[1.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 1.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.0000j, 1.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.7071+0.7071j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - gate_matrix = [ - _one(dtype), _zero(dtype), _zero(dtype), _zero(dtype), - _zero(dtype), _one(dtype), _zero(dtype), _zero(dtype), - _zero(dtype), _zero(dtype), _one(dtype), _zero(dtype), - _zero(dtype), _zero(dtype), _zero(dtype), torch.cos(theta) + 1j * torch.sin(theta), - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) - - -def crx(theta: torch.Tensor) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._cp(theta) + return _type_transform(mat, type_str) + + +def crx(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -713,19 +814,26 @@ def crx(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of CR_X gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + CR_X = crx(theta) + print(f'The CR_X Gate is:\n{CR_X}') + + :: + + The CR_X Gate is: + tensor([[1.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 1.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.0000j, 0.9239+0.0000j, 0.0000-0.3827j], + [0.0000+0.0000j, 0.0000+0.0000j, 0.0000-0.3827j, 0.9239+0.0000j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - gate_matrix = [ - _one(dtype), _zero(dtype), _zero(dtype), _zero(dtype), - _zero(dtype), _one(dtype), _zero(dtype), _zero(dtype), - _zero(dtype), _zero(dtype), torch.cos(theta / 2), -1j * torch.sin(theta / 2), - _zero(dtype), _zero(dtype), -1j * torch.sin(theta / 2), torch.cos(theta / 2), - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) - - -def cry(theta: torch.Tensor) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._crx(theta) + return _type_transform(mat, type_str) + + +def cry(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -746,20 +854,28 @@ def cry(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of CR_Y gate. + + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + CR_Y = cry(theta) + print(f'The CR_Y Gate is:\n{CR_Y}') + + :: + + The CR_Y Gate is: + tensor([[ 1.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j], + [ 0.0000+0.j, 1.0000+0.j, 0.0000+0.j, 0.0000+0.j], + [ 0.0000+0.j, 0.0000+0.j, 0.9239+0.j, -0.3827+0.j], + [ 0.0000+0.j, 0.0000+0.j, 0.3827+0.j, 0.9239+0.j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - gate_matrix = [ - _one(dtype), _zero(dtype), _zero(dtype), _zero(dtype), - _zero(dtype), _one(dtype), _zero(dtype), _zero(dtype), - _zero(dtype), _zero(dtype), torch.cos(theta / 2), (-torch.sin(theta / 2)), - _zero(dtype), _zero(dtype), torch.sin(theta / 2), torch.cos(theta / 2), - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) - - -def crz(theta: torch.Tensor) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._cry(theta) + return _type_transform(mat, type_str) + + +def crz(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -781,21 +897,26 @@ def crz(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of CR_Z gate. - """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - one, zero = _one(dtype).to(device=theta.device), _zero(dtype).to(device=theta.device) + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + CR_Z = crz(theta) + print(f'The CR_Z Gate is:\n{CR_Z}') + + :: - gate_matrix = [ - one, zero, zero, zero, - zero, one, zero, zero, - zero, zero, torch.cos(theta / 2) - 1j * torch.sin(theta / 2), zero, - zero, zero, zero,torch.cos(theta / 2) + 1j * torch.sin(theta / 2), - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) + The CR_Z Gate is: + tensor([[1.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 1.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.0000j, 0.9239-0.3827j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.9239+0.3827j]]) + """ + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._crz(theta) + return _type_transform(mat, type_str) -def cu(theta: torch.Tensor) -> torch.Tensor: +def cu(theta: _ParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -812,34 +933,32 @@ def cu(theta: torch.Tensor) -> torch.Tensor: \end{align} Args: - theta: the parameter of this matrix. The shape of param is [3,1] + theta: the parameter of this matrix. The shape of param is [4,1] Returns: the matrix of CU gate. + + .. code-block:: python + + theta = torch.tensor([[torch.pi / 4], [torch.pi / 3], [torch.pi / 6],[torch.pi / 6]]) + CU = cu(theta) + print(f'The CU Gate is:\n{CU}') + + :: + + The CU Gate is: + tensor([[ 1.0000e+00+0.0000j, 0.0000e+00+0.0000j, 0.0000e+00+0.0000j,0.0000e+00+0.0000j], + [ 0.0000e+00+0.0000j, 1.0000e+00+0.0000j, 0.0000e+00+0.0000j,0.0000e+00+0.0000j], + [ 0.0000e+00+0.0000j, 0.0000e+00+0.0000j, 8.0010e-01+0.4619j,-1.9134e-01-0.3314j], + [ 0.0000e+00+0.0000j, 0.0000e+00+0.0000j, -1.6728e-08+0.3827j,-4.6194e-01+0.8001j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([4, 1]) - one, zero = _one(dtype).to(device=theta.device), _zero(dtype).to(device=theta.device) - - param1 = (torch.cos(theta[3]) + 1j * torch.sin(theta[3])) * \ - (torch.cos(theta[0] / 2)) - param2 = (torch.cos(theta[2] + theta[3]) + 1j * torch.sin(theta[2] + theta[3])) * \ - (-torch.sin(theta[0] / 2)) - param3 = (torch.cos(theta[1] + theta[3]) + 1j * torch.sin(theta[1] + theta[3])) * \ - torch.sin(theta[0] / 2) - param4 = (torch.cos(theta[1] + theta[2] + theta[3]) + 1j * \ - torch.sin(theta[1] + theta[2] + theta[3])) * torch.cos(theta[0] / 2) - gate_matrix = [ - one, zero, zero, zero, - zero, one, zero, zero, - zero, zero, param1, param2, - zero, zero, param3, param4, - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) - - -def rxx(theta: torch.Tensor) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._cu(theta) + return _type_transform(mat, type_str) + + +def rxx(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -860,21 +979,26 @@ def rxx(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of RXX gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + R_XX = rxx(theta) + print(f'The R_XX Gate is:\n{R_XX}') + + :: + + The R_XX Gate is: + tensor([[0.9239+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-0.3827j], + [0.0000+0.0000j, 0.9239+0.0000j, 0.0000-0.3827j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000-0.3827j, 0.9239+0.0000j, 0.0000+0.0000j], + [0.0000-0.3827j, 0.0000+0.0000j, 0.0000+0.0000j, 0.9239+0.0000j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - param1 = torch.cos(theta / 2) - param2 = -1j * torch.sin(theta / 2) - gate_matrix = [ - param1, _zero(dtype), _zero(dtype), param2, - _zero(dtype), param1, param2, _zero(dtype), - _zero(dtype), param2, param1, _zero(dtype), - param2, _zero(dtype), _zero(dtype), param1, - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) - - -def ryy(theta: torch.Tensor) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._rxx(theta) + return _type_transform(mat, type_str) + + +def ryy(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -895,22 +1019,26 @@ def ryy(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of RYY gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + R_YY = ryy(theta) + print(f'The R_YY Gate is:\n{R_YY}') + + :: + + The R_YY Gate is: + tensor([[0.9239+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.3827j], + [0.0000+0.0000j, 0.9239+0.0000j, 0.0000-0.3827j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000-0.3827j, 0.9239+0.0000j, 0.0000+0.0000j], + [0.0000+0.3827j, 0.0000+0.0000j, 0.0000+0.0000j, 0.9239+0.0000j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - param1 = torch.cos(theta / 2) - param2 = -1j * torch.sin(theta / 2) - param3 = 1j * torch.sin(theta / 2) - gate_matrix = [ - param1, _zero(dtype), _zero(dtype), param3, - _zero(dtype), param1, param2, _zero(dtype), - _zero(dtype), param2, param1, _zero(dtype), - param3, _zero(dtype), _zero(dtype), param1, - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) - - -def rzz(theta: torch.Tensor) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._ryy(theta) + return _type_transform(mat, type_str) + + +def rzz(theta: _SingleParamLike) -> _ArrayLike: r"""Generate the matrix .. math:: @@ -931,21 +1059,26 @@ def rzz(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of RZZ gate. + .. code-block:: python + + theta = torch.tensor([torch.pi / 4]) + R_ZZ = rzz(theta) + print(f'The R_ZZ Gate is:\n{R_ZZ}') + + :: + + The R_ZZ Gate is: + tensor([[0.9239-0.3827j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.9239+0.3827j, 0.0000+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.0000j, 0.9239+0.3827j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.9239-0.3827j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([1]) - param1 = torch.cos(theta / 2) - 1j * torch.sin(theta / 2) - param2 = torch.cos(theta / 2) + 1j * torch.sin(theta / 2) - gate_matrix = [ - param1, _zero(dtype), _zero(dtype), _zero(dtype), - _zero(dtype), param2, _zero(dtype), _zero(dtype), - _zero(dtype), _zero(dtype), param2, _zero(dtype), - _zero(dtype), _zero(dtype), _zero(dtype), param1, - ] - return torch.cat(gate_matrix).view([4, 4]).to(dtype) - - -def ms(dtype: Optional[torch.dtype] = None) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._rzz(theta) + return _type_transform(mat, type_str) + + +def ms() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -960,26 +1093,26 @@ def ms(dtype: Optional[torch.dtype] = None) -> torch.Tensor: \end{bmatrix} \end{align} - Args: - dtype: the dtype of this matrix. Defaults to ``None``. - Returns: the matrix of MS gate. + .. code-block:: python + + MS = ms() + print(f'The MS Gate is:\n{MS}') + + :: + + The MS Gate is: + tensor([[0.7071+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.7071j], + [0.0000+0.0000j, 0.7071+0.0000j, 0.0000+0.7071j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.0000+0.7071j, 0.7071+0.0000j, 0.0000+0.0000j], + [0.0000+0.7071j, 0.0000+0.0000j, 0.0000+0.0000j, 0.7071+0.0000j]]) """ - dtype = get_dtype() if dtype is None else dtype - val1 = math.sqrt(2) / 2 - val2 = 1j / math.sqrt(2) - gate_matrix = [ - [val1, 0, 0, val2], - [0, val1, val2, 0], - [0, val2, val1, 0], - [val2, 0, 0, val1], - ] - return torch.tensor(gate_matrix, dtype=dtype) - - -def cswap(dtype: Optional[torch.dtype] = None) -> torch.Tensor: + return utils.matrix._ms(get_dtype()) + + +def cswap() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -1004,22 +1137,28 @@ def cswap(dtype: Optional[torch.dtype] = None) -> torch.Tensor: Returns: the matrix of CSWAP gate. + .. code-block:: python + + CSWAP = cswap() + print(f'The CSWAP Gate is:\n{CSWAP}') + + :: + + The CSWAP Gate is: + tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]]) + """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - ] - return torch.tensor(gate_matrix, dtype=dtype) - - -def toffoli(dtype: Optional[torch.dtype] = None) -> torch.Tensor: + return utils.matrix._cswap(get_dtype()) + + +def toffoli() -> torch.Tensor: r"""Generate the matrix .. math:: @@ -1044,22 +1183,27 @@ def toffoli(dtype: Optional[torch.dtype] = None) -> torch.Tensor: Returns: the matrix of Toffoli gate. + .. code-block:: python + + Toffoli = toffoli() + print(f'The Toffoli Gate is:\n{Toffoli}') + + :: + + The Toffoli Gate is: + tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]]) """ - dtype = get_dtype() if dtype is None else dtype - gate_matrix = [ - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0], - ] - return torch.tensor(gate_matrix, dtype=dtype) - - -def universal2(theta: torch.Tensor) -> torch.Tensor: + return utils.matrix._toffoli(get_dtype()) + + +def universal2(theta: _ParamLike) -> _ArrayLike: r"""Generate the matrix Args: @@ -1068,104 +1212,81 @@ def universal2(theta: torch.Tensor) -> torch.Tensor: Returns: the matrix of universal two qubits gate. - """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([15]) - unitary = torch.eye(2 ** 2).to(dtype) - _cnot_gate = cnot(dtype) - - unitary = _unitary_transformation(unitary, u3(theta[[0, 1, 2]]), qubit_idx=0, num_qubits=2) - unitary = _unitary_transformation(unitary, u3(theta[[3, 4, 5]]), qubit_idx=1, num_qubits=2) - unitary = _unitary_transformation(unitary, _cnot_gate, qubit_idx=[1, 0], num_qubits=2) - - unitary = _unitary_transformation(unitary, rz(theta[[6]]), qubit_idx=0, num_qubits=2) - unitary = _unitary_transformation(unitary, ry(theta[[7]]), qubit_idx=1, num_qubits=2) - unitary = _unitary_transformation(unitary, _cnot_gate, qubit_idx=[0, 1], num_qubits=2) - - unitary = _unitary_transformation(unitary, ry(theta[[8]]), qubit_idx=1, num_qubits=2) - unitary = _unitary_transformation(unitary, _cnot_gate, qubit_idx=[1, 0], num_qubits=2) + .. code-block:: python - unitary = _unitary_transformation(unitary, u3(theta[[9, 10, 11]]), qubit_idx=0, num_qubits=2) - unitary = _unitary_transformation(unitary, u3(theta[[12, 13, 14]]), qubit_idx=1, num_qubits=2) + theta = torch.tensor([ + 0.5, 1.0, 1.5, 2.0, 2.5, + 3.0, 3.5, 4.0, 4.5, 5.0, + 5.5, 6.0, 6.5, 7.0, 7.5]) + Universal2 = universal2(theta) - return unitary + print(f'The matrix of universal two qubits gate is:\n{Universal2}') + + :: + + The matrix of universal two qubits gate is: + tensor([[-0.2858-0.0270j, 0.4003+0.3090j, -0.6062+0.0791j, 0.5359+0.0323j], + [-0.0894-0.1008j, -0.5804+0.0194j, 0.3156+0.1677j, 0.7090-0.1194j], + [-0.8151-0.2697j, 0.2345-0.1841j, 0.3835-0.1154j, -0.0720+0.0918j], + [-0.2431+0.3212j, -0.1714+0.5374j, 0.1140+0.5703j, -0.2703+0.3289j]]) + """ + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._universal2(theta) + return _type_transform(mat, type_str) -def universal3(theta: torch.Tensor) -> torch.Tensor: +def universal3(theta: _ParamLike) -> _ArrayLike: r"""Generate the matrix Args: theta: the parameter of this matrix. The shape of param is [81] Returns: - the matrix of universal three qubits gate. - + the matrix of universal three qubits gate. + + .. code-block:: python + + theta = torch.tensor([ + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, + 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, + 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, + 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, + 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, + 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, + 8.1]) + Universal3 = universal3(theta) + + print(f'The matrix of universal three qubits gate is:\n{Universal3}') + + :: + + The matrix of universal three qubits gate is: + tensor([[-0.0675-0.0941j, -0.4602+0.0332j, 0.2635+0.0044j, 0.0825+0.3465j, + -0.0874-0.3635j, -0.1177-0.4195j, -0.2735+0.3619j, -0.1760-0.1052j], + [ 0.0486+0.0651j, -0.1123+0.0494j, 0.1903+0.0057j, -0.2080+0.2926j, + -0.2099+0.0630j, -0.1406+0.5173j, -0.1431-0.3538j, -0.5460-0.1847j], + [ 0.0827-0.0303j, 0.1155+0.1111j, 0.5391-0.0701j, -0.4229-0.2655j, + -0.1546+0.1943j, -0.0455+0.1744j, -0.3242+0.3539j, 0.3118-0.0041j], + [-0.1222+0.3984j, 0.1647-0.1817j, 0.3294-0.1486j, -0.0293-0.1503j, + 0.0100-0.6481j, 0.2424+0.1575j, 0.2485+0.0232j, -0.1053+0.1873j], + [-0.4309-0.0791j, -0.2071-0.0482j, -0.4331+0.0866j, -0.5454-0.1778j, + -0.1401-0.0230j, 0.0170+0.0299j, 0.0078+0.2231j, -0.2324+0.3369j], + [ 0.0330+0.3056j, 0.2612+0.6464j, -0.2138-0.1748j, -0.2322-0.0598j, + 0.1387-0.1573j, 0.0914-0.2963j, -0.2712-0.1351j, -0.1272-0.1940j], + [ 0.0449-0.3844j, 0.1135+0.2846j, -0.0251+0.3854j, 0.0442-0.0149j, + -0.3671-0.1774j, 0.5158+0.1148j, 0.2151+0.1433j, -0.0188-0.3040j], + [-0.4124-0.4385j, 0.2306+0.0894j, 0.0104-0.2180j, -0.0180+0.2869j, + -0.1030-0.2991j, -0.1473+0.0931j, -0.1686-0.3451j, 0.3825+0.1480j]]) """ - dtype = _get_complex_dtype(theta.dtype) - theta = theta.view([81]) - unitary = torch.eye(2 ** 3).to(dtype) - _h, _s, _cnot = h(dtype), s(dtype), cnot(dtype) - - psi = torch.reshape(theta[:60], shape=[4, 15]) - phi = torch.reshape(theta[60:], shape=[7, 3]) - - def __block_u(_unitary, _theta): - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, ry(_theta[0]), qubit_idx=1, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[0, 1], num_qubits=3) - _unitary = _unitary_transformation(_unitary, ry(_theta[1]), qubit_idx=1, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[0, 1], num_qubits=3) - - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, _h, qubit_idx=2, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 0], num_qubits=3) - - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[0, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, rz(_theta[2]), qubit_idx=2, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[0, 2], num_qubits=3) - return _unitary - - def __block_v(_unitary, _theta): - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[2, 0], num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[2, 1], num_qubits=3) - - _unitary = _unitary_transformation(_unitary, ry(_theta[0]), qubit_idx=2, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, ry(_theta[1]), qubit_idx=2, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 2], num_qubits=3) - - _unitary = _unitary_transformation(_unitary, _s, qubit_idx=2, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[2, 0], num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[0, 1], num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[1, 0], num_qubits=3) - - _unitary = _unitary_transformation(_unitary, _h, qubit_idx=2, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[0, 2], num_qubits=3) - _unitary = _unitary_transformation(_unitary, rz(_theta[2]), qubit_idx=2, num_qubits=3) - _unitary = _unitary_transformation(_unitary, _cnot, qubit_idx=[0, 2], num_qubits=3) - return _unitary - - unitary = _unitary_transformation(unitary, universal2(psi[0]), qubit_idx=[0, 1], num_qubits=3) - unitary = _unitary_transformation(unitary, u3(phi[0, 0:3]), qubit_idx=2, num_qubits=3) - unitary = __block_u(unitary, phi[1]) - - unitary = _unitary_transformation(unitary, universal2(psi[1]), qubit_idx=[0, 1], num_qubits=3) - unitary = _unitary_transformation(unitary, u3(phi[2, 0:3]), qubit_idx=2, num_qubits=3) - unitary = __block_v(unitary, phi[3]) - - unitary = _unitary_transformation(unitary, universal2(psi[2]), qubit_idx=[0, 1], num_qubits=3) - unitary = _unitary_transformation(unitary, u3(phi[4, 0:3]), qubit_idx=2, num_qubits=3) - unitary = __block_u(unitary, phi[5]) - - unitary = _unitary_transformation(unitary, universal2(psi[3]), qubit_idx=[0, 1], num_qubits=3) - unitary = _unitary_transformation(unitary, u3(phi[6, 0:3]), qubit_idx=2, num_qubits=3) - return unitary - - -def universal_qudit(theta: torch.Tensor, dimension: int) -> torch.Tensor: + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + mat = utils.matrix._universal3(theta) + return _type_transform(mat, type_str) + + +def universal_qudit(theta: _ParamLike, dimension: int) -> _ArrayLike: + r"""Generalized GellMann matrix basis were used to construct the universal gate for qudits Args: @@ -1173,22 +1294,36 @@ def universal_qudit(theta: torch.Tensor, dimension: int) -> torch.Tensor: dimension: the dimension of the qudit Returns: - the matrix of d-dimensional unitary gate + the matrix of d-dimensional unitary gate References: [wolfram mathworld](https://mathworld.wolfram.com/GeneralizedGell-MannMatrix.html) + + .. code-block:: python + + dimension = 2 + theta = torch.linspace(0.1, 2.5, dimension**2 - 1) + u_qudit_matrix = universal_qudit(theta, dimension) + print(f'The matrix of 2-dimensional unitary gate is:\n{u_qudit_matrix}') + + :: + + The matrix of 2-dimensional unitary gate is: + tensor([[-0.9486+0.2806j, 0.1459+0.0112j], + [-0.1459+0.0112j, -0.9486-0.2806j]]) """ - complex_dtype = _get_complex_dtype(theta.dtype) + type_str, theta = _type_fetch(theta), _type_transform(theta, "tensor") + theta = theta.view([(dimension ** 2) - 1, 1, 1]) - - generalized_gellmann_matrix = database.set.gell_mann(dimension).to(complex_dtype) - hamiltonian = torch.eye(dimension) + torch.sum(torch.mul(theta, generalized_gellmann_matrix), dim=0) - return torch.matrix_exp(1j * hamiltonian) + hamiltonian = torch.sum(torch.mul(theta, database.set.gell_mann(dimension)), dim=0) + mat = torch.matrix_exp(1j * hamiltonian) + + return _type_transform(mat, type_str) -# ------------------------------------------------- Split line ------------------------------------------------- -def Uf(f:Callable[[torch.Tensor], torch.Tensor], n:int) -> torch.Tensor: - r"""Construct the unitary matrix maps :math:`|x\rangle|y\rangle` to :math:`|x\rangle|y\oplus f(x)\rangle` based on a boolean function :math:`f`. +def Uf(f: Callable[[torch.Tensor], torch.Tensor], n: int) -> torch.Tensor: + r"""Construct the unitary matrix maps :math:`|x\rangle|y\rangle` to :math:`|x\rangle|y\oplus f(x)\rangle` + based on a boolean function :math:`f`. Args: f: a boolean function :math:`f` that maps :math:`\{ 0,1 \}^{n}` to :math:`\{ 0,1 \}`; @@ -1201,28 +1336,59 @@ def Uf(f:Callable[[torch.Tensor], torch.Tensor], n:int) -> torch.Tensor: U: U|x\rangle|y\rangle = |x\rangle|y\oplus f(x)\rangle - """ - # note that for a boolean function 'f', 'x = torch.zeros(n)' is a legitimate input, but 'x = torch.zeros((n,1))' is an illegitimate input + .. code-block:: python - dtype = get_dtype() # get the default dtype + n=2 - U = torch.zeros((2**(n+1), 2**(n+1)), dtype=dtype) # initialize the unitary matrix + def xor_function(x: torch.Tensor) -> torch.Tensor: + real_x = x.real + return torch.tensor(int(real_x[0].item()) ^ int(real_x[1].item())) + + f = xor_function + unitary_matrix = Uf(f, n) + + print(f'Unitary matrix in form is:\n{unitary_matrix}') + + :: + + Unitary matrix in form is: + tensor([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], + [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]]) + + Note: + for a boolean function 'f', 'x = torch.zeros(n)' is a legitimate input, + but 'x = torch.zeros((n,1))' is an illegitimate input + + """ + dtype = get_dtype() # get the default dtype + + U = torch.zeros( + (2 ** (n + 1), 2 ** (n + 1)), dtype=dtype + ) # initialize the unitary matrix for i in range(2**n): - temp_bin_i_str = bin(i)[2:].zfill(n) # binary form of 'i' (type: string) - temp_array = torch.zeros(n,dtype=dtype) + temp_bin_i_str = bin(i)[2:].zfill(n) # binary form of 'i' (type: string) + temp_array = torch.zeros(n, dtype=dtype) for j in range(n): - temp_array[j] = complex(temp_bin_i_str[j]) # convert the type of `i`(binary form) into torch.tensor + temp_array[j] = complex( + temp_bin_i_str[j] + ) # convert the type of `i`(binary form) into torch.tensor - f_value = f(temp_array) # compute f(i) - f_value_int = int(f_value) # ensure that the type of 'f(i)' is int - U[(i*2+f_value_int), (i*2)] = 1 # assignment (y=0) - U[(i*2+((f_value_int+1)%2)), ((i*2)+1)] = 1 # assignment (y=1) + f_value = f(temp_array) # compute f(i) + f_value_int = int(f_value) # ensure that the type of 'f(i)' is int + U[(i * 2 + f_value_int), (i * 2)] = 1 # assignment (y=0) + U[(i * 2 + ((f_value_int + 1) % 2)), ((i * 2) + 1)] = 1 # assignment (y=1) return U -def Of(f:Callable[[torch.Tensor], torch.Tensor], n:int) -> torch.Tensor: +def Of(f: Callable[[torch.Tensor], torch.Tensor], n: int) -> torch.Tensor: r"""Construct the unitary matrix maps :math:`|x\rangle` to :math:`(-1)^{f(x)}|x\rangle` based on a boolean function :math:`f`. Args: @@ -1236,29 +1402,50 @@ def Of(f:Callable[[torch.Tensor], torch.Tensor], n:int) -> torch.Tensor: U: U|x\rangle = (-1)^{f(x)}|x\rangle - """ - # note that for a boolean function 'f', 'x = torch.zeros(n)' is a legitimate input, but 'x = torch.zeros((n,1))' is an illegitimate input + .. code-block:: python - dtype = get_dtype() # get the default dtype + n=2 + def xor_function(x: torch.Tensor) -> torch.Tensor: + real_x = x.real + return torch.tensor(int(real_x[0].item()) ^ int(real_x[1].item())) - U = torch.zeros((2**n, 2**n), dtype=dtype) # initialize the unitary matrix + f = xor_function + unitary_matrix = Of(f, n) + print(f'Unitary matrix in form is:\n{unitary_matrix}') + + :: + + Unitary matrix in form is: + tensor([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, -1.+0.j, 0.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, -1.+0.j, 0.+0.j], + [ 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]]) + + Note: + for a boolean function 'f', 'x = torch.zeros(n)' is a legitimate input, but 'x = torch.zeros((n,1))' is an illegitimate input + + """ + dtype = get_dtype() # get the default dtype + U = torch.zeros((2**n, 2**n), dtype=dtype) # initialize the unitary matrix for i in range(2**n): - temp_bin_i_str = bin(i)[2:].zfill(n) # # binary form of 'i' (type: string) + temp_bin_i_str = bin(i)[2:].zfill(n) # binary form of 'i' (type: string) temp_array = torch.zeros(n, dtype=dtype) for j in range(n): - temp_array[j] = complex(temp_bin_i_str[j]) # # convert the type of `i`(binary form) into torch.tensor + temp_array[j] = complex( + temp_bin_i_str[j] + ) # convert the type of `i`(binary form) into torch.tensor - f_value = f(temp_array) # compute f(i) - f_value_int = int(f_value) # ensure that the type of 'f(i)' is int - U[i,i] = (-1)**(f_value_int) # assignment + f_value = f(temp_array) # compute f(i) + f_value_int = int(f_value) # ensure that the type of 'f(i)' is int + U[i, i] = (-1) ** (f_value_int) # assignment return U -for name, func in list(globals().items()): - if callable(func) and '_' not in name: +for name, func in list(locals().items()): + if callable(func) and "_" not in name: # Add '_gate' to the name for functions without an underscore - new_name = f'{name}_gate' + new_name = f"{name}_gate" globals()[new_name] = func __all__ += [new_name] diff --git a/quairkit/database/random.py b/quairkit/database/random.py index da2206f..dfb66a7 100644 --- a/quairkit/database/random.py +++ b/quairkit/database/random.py @@ -18,16 +18,15 @@ """ import math -from typing import List, Optional, Union +from typing import Iterable, List, Optional, Tuple, Union import numpy as np +# TODO this is added due to channel_repr_convert, move it to intrinsic +import quairkit as qkit import scipy import torch from scipy.stats import unitary_group -# TODO this is added due to channel_repr_convert, move it to intrinsic -import quairkit as qkit - from ..core import Hamiltonian, State, get_dtype, get_float_dtype, to_state from ..core.intrinsic import _alias, _format_total_dim from ..core.utils.linalg import _dagger @@ -37,6 +36,7 @@ "random_state", "random_hamiltonian_generator", "random_hermitian", + "random_projector", "random_orthogonal_projection", "random_density_matrix", "random_unitary", @@ -47,6 +47,7 @@ "haar_state_vector", "haar_density_operator", "random_channel", + "random_clifford" ] @@ -54,8 +55,8 @@ def random_pauli_str_generator(num_qubits: int, terms: Optional[int] = 3) -> Lis r"""Generate a random observable in list form. An observable :math:`O=0.3X\otimes I\otimes I+0.5Y\otimes I\otimes Z`'s list form is - ``[[0.3, 'x0'], [0.5, 'y0,z2']]``. Such an observable is generated by - ``random_pauli_str_generator(3, terms=2)`` + ``[[0.3, 'x0'], [0.5, 'y0,z2']]``. Such an observable is generated by + ``random_pauli_str_generator(3, terms=2)`` Args: num_qubits: Number of qubits. @@ -63,59 +64,136 @@ def random_pauli_str_generator(num_qubits: int, terms: Optional[int] = 3) -> Lis Returns: The Hamiltonian of randomly generated observable. + + .. code-block:: python + + observable = random_pauli_str_generator(num_qubits=2, terms=2) + print(f'The Hamiltonian of randomly generated observable is:\n{observable}') + + :: + + The Hamiltonian of randomly generated observable is: + [[-0.6019637631250563, 'y0'], [0.12777564473712655, 'x0,z1']] + """ pauli_str = [] for sublen in np.random.randint(1, high=num_qubits + 1, size=terms): # Tips: -1 <= coeff < 1 coeff = np.random.rand() * 2 - 1 - ops = np.random.choice(['x', 'y', 'z'], size=sublen) + ops = np.random.choice(["x", "y", "z"], size=sublen) pos = np.random.choice(range(num_qubits), size=sublen, replace=False) op_list = [ops[i] + str(pos[i]) for i in range(sublen)] op_list.sort(key=lambda x: int(x[1:])) - pauli_str.append([coeff, ','.join(op_list)]) + pauli_str.append([coeff, ",".join(op_list)]) return pauli_str @_alias({"num_systems": "num_qubits"}) -def random_state(num_systems: int, - rank: Optional[int] = None, - is_real: Optional[bool] = False, - size: Optional[Union[int, List[int]]] = 1, - system_dim: Union[List[int], int] = 2) -> State: +def random_state( + num_systems: int, + rank: Optional[int] = None, + is_real: Optional[bool] = False, + size: Optional[Union[int, List[int]]] = 1, + system_dim: Union[List[int], int] = 2, +) -> State: r"""Generate a random quantum state. - Args: - num_systems: The number of qubits contained in the quantum state. - rank: The rank of the density matrix. Defaults to ``None`` which means full rank. - is_real: If the quantum state only contains the real number. Defaults to ``False``. - size: Batch size. Defaults to 1 - system_dim: dimension of systems. Can be a list of system dimensions - or an int representing the dimension of all systems. Defaults to be qubit case. + Args: + num_systems: The number of qubits contained in the quantum state. + rank: The rank of the density matrix. Defaults to ``None`` which means full rank. + is_real: If the quantum state only contains the real number. Defaults to ``False``. + size: Batch size. Defaults to 1 + system_dim: dimension of systems. Can be a list of system dimensions + or an int representing the dimension of all systems. Defaults to be qubit case. - Raises: - NotImplementedError: If the backend is wrong or not implemented. + Raises: + NotImplementedError: If the backend is wrong or not implemented. - Returns: - The generated quantum state. + Returns: + The generated quantum state. + + .. code-block:: python + + state = random_state(num_systems=1, size=1) + print(f'The generated quantum state is:\n{state}') + + state = random_state(num_systems=1, rank=1) + print(f'The generated quantum state is:\n{state}') + + state = random_state(num_systems=2, system_dim=[1, 2]) + print(f'The generated quantum state is:\n{state}') + + state = random_state(num_systems=3, size=[2, 1], system_dim=[1, 2, 1]) + print(f'The generated quantum state is:\n{state}') + + :: + + The generated quantum state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2] + System sequence: [0] + [-0.33+0.72j -0.28+0.55j] + --------------------------------------------------- + + The generated quantum state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2] + System sequence: [0] + [ 0.83-0.31j -0.45+0.16j] + --------------------------------------------------- + + The generated quantum state is: + + --------------------------------------------------- + Backend: density_matrix + System dimension: [1, 2] + System sequence: [0, 1] + [[ 0.63+0.j -0.12-0.13j] + [-0.12+0.13j 0.37-0.j ]] + --------------------------------------------------- + + The generated quantum state is: + + --------------------------------------------------- + Backend: density_matrix + System dimension: [1, 2, 1] + System sequence: [0, 1, 2] + Batch size: [2, 1] + + # 0: + [[0.43+0.j 0.24-0.37j] + [0.24+0.37j 0.57-0.j ]] + # 1: + [[ 0.88+0.j -0.29-0.11j] + [-0.29+0.11j 0.12-0.j ]] + --------------------------------------------------- """ dim = _format_total_dim(num_systems, system_dim) size = [size] if isinstance(size, int) else list(size) rank = np.random.randint(1, dim + 1) if rank is None else rank total_size = int(np.prod(size)) - + if rank == 1: - list_state = torch.stack([haar_state_vector(dim, is_real) - for _ in range(total_size)]).view(size + [dim, 1]) + list_state = torch.stack( + [haar_state_vector(dim, is_real) for _ in range(total_size)] + ).view(size + [dim, 1]) else: - list_state = torch.stack([haar_density_operator(dim, rank, is_real) - for _ in range(total_size)]).view(size + [dim, dim]) - + list_state = torch.stack( + [haar_density_operator(dim, rank, is_real) for _ in range(total_size)] + ).view(size + [dim, dim]) + list_state = list_state if total_size > 1 else list_state.squeeze() return to_state(list_state, system_dim) -def random_hamiltonian_generator(num_qubits: int, terms: Optional[int] = 3) -> Hamiltonian: - r"""Generate a random Hamiltonian. +def random_hamiltonian_generator( + num_qubits: int, terms: Optional[int] = 3 +) -> Hamiltonian: + r"""Generate a random Hamiltonian. Args: num_qubits: Number of qubits. @@ -123,12 +201,24 @@ def random_hamiltonian_generator(num_qubits: int, terms: Optional[int] = 3) -> H Returns: The randomly generated Hamiltonian. + + .. code-block:: python + + Hamiltonian=random_hamiltonian_generator(3,2) + print(f'The randomly generated Hamiltonian is:\n{Hamiltonian}') + + :: + + The randomly generated Hamiltonian is: + 0.11801365595625102 Z0, X2 + 0.9059897222160238 X0, Z1, Z2 + """ return Hamiltonian(random_pauli_str_generator(num_qubits, terms)) def random_hermitian(num_qubits: int) -> torch.Tensor: - r"""randomly generate a :math:`2^n \times 2^n` hermitian matrix + r"""randomly generate a normalized :math:`2^n \times 2^n` hermitian matrix Args: num_qubits: number of qubits :math:`n` @@ -136,9 +226,19 @@ def random_hermitian(num_qubits: int) -> torch.Tensor: Returns: a :math:`2^n \times 2^n` hermitian matrix + .. code-block:: python + + Hermitian=random_hermitian(1) + print(f'The randomly generated hermitian matrix is:\n{Hermitian}') + + :: + + The randomly generated hermitian matrix is: + tensor([[0.1038+0.0000j, 0.4251+0.2414j], + [0.4251-0.2414j, 0.7333+0.0000j]]) """ assert num_qubits > 0 - n = 2 ** num_qubits + n = 2**num_qubits mat = np.random.randn(n, n) + 1j * np.random.randn(n, n) for i in range(n): @@ -146,30 +246,50 @@ def random_hermitian(num_qubits: int) -> torch.Tensor: for j in range(i): mat[i, j] = np.conj(mat[j, i]) - eigval= np.linalg.eigvalsh(mat) + eigval = np.linalg.eigvalsh(mat) max_eigval = np.max(np.abs(eigval)) return torch.tensor(mat / max_eigval, dtype=get_dtype()) -def random_orthogonal_projection(num_qubits: int) -> torch.Tensor: - r"""randomly generate a :math:`2^n \times 2^n` rank-1 orthogonal projector +@_alias({"num_systems": "num_qubits"}) +def random_projector(num_systems: int, + system_dim: Union[List[int], int] = 2) -> torch.Tensor: + r"""randomly generate a :math:`d \times d` rank-1 orthogonal projector Args: - num_qubits: number of qubits :math:`n` + num_systems: number of systems + system_dim: dimension of systems. Can be a list of system dimensions + or an int representing the dimension of all systems. Defaults to be qubit case. Returns: a :math:`2^n \times 2^n` orthogonal projector + + .. code-block:: python + + Orthogonal_projector=random_orthogonal_projection(1) + print(f'The randomly generated Orthogonal_projector is:\n{Orthogonal_projector}') + + :: + + The randomly generated Orthogonal_projector is: + tensor([[0.9704+1.1123e-10j, 0.1692+7.7007e-03j], + [0.1692-7.7008e-03j, 0.0296-1.1123e-10j]]) """ - assert num_qubits > 0 - n = 2 ** num_qubits + assert num_systems > 0 + n = 2**num_systems float_dtype = get_float_dtype() - vec = torch.randn([n, 1], dtype=float_dtype) + 1j * torch.randn([n, 1], dtype=float_dtype) + vec = torch.randn([n, 1], dtype=float_dtype) + 1j * torch.randn( + [n, 1], dtype=float_dtype + ) mat = vec @ _dagger(vec) return mat / torch.trace(mat) +random_orthogonal_projection = random_projector + + def random_density_matrix(num_qubits: int) -> torch.Tensor: - r""" randomly generate an num_qubits-qubit state in density matrix form + r"""randomly generate an num_qubits-qubit state in density matrix form Args: num_qubits: number of qubits :math:`n` @@ -177,32 +297,76 @@ def random_density_matrix(num_qubits: int) -> torch.Tensor: Returns: a :math:`2^n \times 2^n` density matrix + .. code-block:: python + + Density_matrix=random_density_matrix(1) + print(f'The randomly generated density matrix is:\n{Density_matrix}') + + :: + + The randomly generated density matrix is: + tensor([[0.3380+0.0000j, 0.4579+0.1185j], + [0.4579-0.1185j, 0.6620+0.0000j]]) """ - dim = 2 ** num_qubits + dim = 2**num_qubits return haar_density_operator(dim, rank=np.random.randint(1, dim + 1)) @_alias({"num_systems": "num_qubits"}) -def random_unitary(num_systems: int, - size: Optional[Union[int, List[int]]] = 1, - system_dim: Union[List[int], int] = 2) -> torch.Tensor: +def random_unitary( + num_systems: int, + size: Optional[Union[int, List[int]]] = 1, + system_dim: Union[List[int], int] = 2, +) -> torch.Tensor: r"""randomly generate a :math:`d \times d` unitary Args: num_systems: number of systems in this unitary. Alias of ``num_qubits``. size: batch size. Defaults to 1 - system_dim: dimension of systems. Can be a list of system dimensions + system_dim: dimension of systems. Can be a list of system dimensions or an int representing the dimension of all systems. Defaults to be qubit case. Returns: (a) :math:`d \times d` unitary matrix + .. code-block:: python + + unitary_matrix_1 = random_unitary(num_systems=1, system_dim=2) + print(f'The randomly generated unitary_matrix_1 is:\n{unitary_matrix_1}') + + unitary_matrix_2 = random_unitary(num_systems=2, system_dim=[1, 2]) + print(f'The randomly generated unitary_matrix_2 is:\n{unitary_matrix_2}') + + + unitary_matrix_3 = random_unitary(num_systems=1, size=[1,2]) + print(f'The randomly generated unitary_matrix_3 is:\n{unitary_matrix_3}') + + :: + + The randomly generated unitary_matrix_1 is: + tensor([[-0.5288+0.5296j, -0.5277-0.4019j], + [-0.5321-0.3959j, -0.3627+0.6546j]]) + The randomly generated unitary_matrix_2 is: + tensor([[ 0.6996-0.1504j, 0.3414+0.6095j], + [ 0.4954-0.4925j, -0.6315-0.3364j]]) + The randomly generated unitary_matrix_3 is: + tensor([[[[ 0.3240+0.1404j, 0.4166-0.8377j], + [ 0.6068+0.7121j, -0.2804+0.2146j]], + + [[-0.2620-0.0886j, -0.3587+0.8916j], + [ 0.5196-0.8084j, 0.2238+0.1624j]]]]) + + """ dim = _format_total_dim(num_systems, system_dim) size = [size] if isinstance(size, int) else list(size) total_size = math.prod(size) - list_unitary = torch.stack([torch.tensor(unitary_group.rvs(dim), dtype=get_dtype()) - for _ in range(total_size)]).view(size + [dim, dim]) + list_unitary = torch.stack( + [ + torch.tensor(unitary_group.rvs(dim), dtype=get_dtype()) + for _ in range(total_size) + ] + ).view(size + [dim, dim]) return list_unitary if total_size > 1 else list_unitary.squeeze() @@ -214,14 +378,27 @@ def random_unitary_hermitian(num_qubits: int) -> torch.Tensor: Returns: a :math:`2^n \times 2^n` hermitian unitary matrix + + .. code-block:: python + + Unitary_hermitian=random_unitary_hermitian(1) + print(f'The randomly generated hermitian unitary is:\n{Unitary_hermitian}') + + :: + + The randomly generated hermitian unitary is: + tensor([[ 0.2298+2.2018e-09j, -0.8408+4.9013e-01j], + [-0.8408-4.9013e-01j, -0.2298-2.2018e-09j]]) """ proj_mat = random_orthogonal_projection(num_qubits) - id_mat = torch.eye(2 ** num_qubits) + id_mat = torch.eye(2**num_qubits) return (2 + 0j) * proj_mat - id_mat -def random_unitary_with_hermitian_block(num_qubits: int, is_unitary: bool = False) -> torch.Tensor: +def random_unitary_with_hermitian_block( + num_qubits: int, is_unitary: bool = False +) -> torch.Tensor: r"""randomly generate a unitary :math:`2^n \times 2^n` matrix that is a block encoding of a :math:`2^{n/2} \times 2^{n/2}` Hermitian matrix Args: @@ -231,6 +408,35 @@ def random_unitary_with_hermitian_block(num_qubits: int, is_unitary: bool = Fals Returns: a :math:`2^n \times 2^n` unitary matrix that its upper-left block is a Hermitian matrix + .. code-block:: python + + unitary_matrix_1 = random_unitary_with_hermitian_block(num_qubits=2, is_unitary=False) + print(f'The randomly generated unitary matrix 1 with hermitian block is:\n{unitary_matrix_1}') + + unitary_matrix_2 = random_unitary_with_hermitian_block(num_qubits=2, is_unitary=True) + print(f'The randomly generated unitary matrix 2 with hermitian block is:\n{unitary_matrix_2}') + + :: + + The randomly generated unitary matrix 1 with hermitian block is: + tensor([[ 5.7873e-01+0.0000j, 2.2460e-01+0.2711j, -1.5514e-08+0.5646j, + 3.6316e-01-0.3009j], + [ 2.2460e-01-0.2711j, 7.0578e-01+0.0000j, -3.6316e-01-0.3009j, + -2.2489e-08+0.3944j], + [-1.5514e-08+0.5646j, 3.6316e-01-0.3009j, 5.7873e-01+0.0000j, + 2.2460e-01+0.2711j], + [-3.6316e-01-0.3009j, -2.2489e-08+0.3944j, 2.2460e-01-0.2711j, + 7.0578e-01+0.0000j]]) + The randomly generated unitary matrix 2 with hermitian block is: + tensor([[-1.8185e-01-1.6847e-09j, 3.0894e-01+3.4855e-01j, + 2.2516e-09+8.6603e-01j, -1.4451e-09-9.3500e-11j], + [ 3.0894e-01-3.4855e-01j, 1.8185e-01+1.6847e-09j, + 1.7456e-09-9.3500e-11j, 2.4038e-09+8.6603e-01j], + [ 2.2516e-09+8.6603e-01j, -1.4451e-09-9.3500e-11j, + -1.8185e-01-1.6847e-09j, 3.0894e-01+3.4855e-01j], + [ 1.7456e-09-9.3500e-11j, 2.4038e-09+8.6603e-01j, + 3.0894e-01-3.4855e-01j, 1.8185e-01+1.6847e-09j]]) + """ assert num_qubits > 0 @@ -247,7 +453,7 @@ def random_unitary_with_hermitian_block(num_qubits: int, is_unitary: bool = Fals def haar_orthogonal(dim: int) -> torch.Tensor: - r""" randomly generate an orthogonal matrix following Haar random, referenced by arXiv:math-ph/0609050v2 + r"""randomly generate an orthogonal matrix following Haar random, referenced by arXiv:math-ph/0609050v2 Args: dim: dimension of orthogonal matrix @@ -255,9 +461,19 @@ def haar_orthogonal(dim: int) -> torch.Tensor: Returns: a :math:`2^n \times 2^n` orthogonal matrix + .. code-block:: python + + Haar_orthogonal=haar_orthogonal(2) + print(f'The randomly generated orthogonal matrix is:\n{Haar_orthogonal}') + + :: + + The randomly generated orthogonal matrix is: + tensor([[-0.6859+0.j, 0.7277+0.j], + [ 0.7277+0.j, 0.6859+0.j]]) """ # Step 1: sample from Ginibre ensemble - ginibre = (np.random.randn(dim, dim)) + ginibre = np.random.randn(dim, dim) # Step 2: perform QR decomposition of G mat_q, mat_r = np.linalg.qr(ginibre) # Step 3: make the decomposition unique @@ -267,7 +483,7 @@ def haar_orthogonal(dim: int) -> torch.Tensor: def haar_unitary(dim: int) -> torch.Tensor: - r""" randomly generate a unitary following Haar random, referenced by arXiv:math-ph/0609050v2 + r"""randomly generate a unitary following Haar random, referenced by arXiv:math-ph/0609050v2 Args: dim: dimension of unitary @@ -275,6 +491,16 @@ def haar_unitary(dim: int) -> torch.Tensor: Returns: a :math:`d \times d` unitary + .. code-block:: python + + Haar_unitary=haar_unitary(2) + print(f'The randomly generated unitary is:\n{Haar_unitary}') + + :: + + The randomly generated unitary is: + tensor([[ 0.2800+0.6235j, 0.7298+0.0160j], + [-0.7289-0.0396j, 0.3267-0.6003j]]) """ # Step 1: sample from Ginibre ensemble ginibre = (np.random.randn(dim, dim) + 1j * np.random.randn(dim, dim)) / np.sqrt(2) @@ -287,15 +513,25 @@ def haar_unitary(dim: int) -> torch.Tensor: def haar_state_vector(dim: int, is_real: Optional[bool] = False) -> torch.Tensor: - r""" randomly generate a state vector following Haar random + r"""randomly generate a state vector following Haar random Args: dim: dimension of density matrix is_real: whether the vector is real, default to be False Returns: - a :math:`2^n \times 1` state vector + a :math:`d \times 1` state vector + .. code-block:: python + + Haar_state_vector=haar_state_vector(3,is_real=True) + print(f'The randomly generated state vector is:\n{Haar_state_vector}') + + :: + + The randomly generated state vector is: + tensor([[ 0.9908+0.j], + [-0.1356+0.j]]) """ if is_real: # Generate a Haar random orthogonal matrix @@ -311,8 +547,10 @@ def haar_state_vector(dim: int, is_real: Optional[bool] = False) -> torch.Tensor return phi.view([-1, 1]) -def haar_density_operator(dim: int, rank: int, is_real: Optional[bool] = False) -> torch.Tensor: - r""" randomly generate a density matrix following Haar random +def haar_density_operator( + dim: int, rank: int, is_real: Optional[bool] = False +) -> torch.Tensor: + r"""randomly generate a density matrix following Haar random Args: dim: dimension of density matrix @@ -320,9 +558,27 @@ def haar_density_operator(dim: int, rank: int, is_real: Optional[bool] = False) is_real: whether the density matrix is real, default to be False Returns: - a :math:`2^n \times 2^n` density matrix + a :math:`d \times d` density matrix + + .. code-block:: python + + rho1 = haar_density_operator(dim=2, rank=2) + print(f'The randomly generated density matrix 1 is:\n{rho1}') + + rho2 = haar_density_operator(dim=2, rank=1, is_real=True) + print(f'The randomly generated density matrix 2 is:\n{rho2}') + + :: + + The randomly generated density matrix 1 is: + tensor([[ 0.8296+1.1215e-18j, -0.0430+3.5193e-01j], + [-0.0430-3.5193e-01j, 0.1704-1.1215e-18j]]) + The randomly generated density matrix 2 is: + tensor([[ 0.6113+0.j, -0.4875+0.j], + [-0.4875+0.j, 0.3887+0.j]]) + """ - assert 0 < rank <= dim, 'rank is an invalid number' + assert 0 < rank <= dim, "rank is an invalid number" if is_real: ginibre_matrix = np.random.randn(dim, rank) rho = ginibre_matrix @ ginibre_matrix.T @@ -334,43 +590,279 @@ def haar_density_operator(dim: int, rank: int, is_real: Optional[bool] = False) @_alias({"num_systems": "num_qubits"}) -def random_channel(num_systems: int, rank: int = None, - target: str = 'kraus', - size: Optional[int] = 1, - system_dim: Union[List[int], int] = 2) -> torch.Tensor: +def random_channel( + num_systems: int, + rank: int = None, + target: str = "kraus", + size: Optional[int] = 1, + system_dim: Union[List[int], int] = 2, +) -> torch.Tensor: r"""Generate a random channel from its Stinespring representation Args: num_systems: number of systems rank: rank of this Channel. Defaults to be random sampled from :math:`[1, d]` - target: target representation, should to be ``'choi'``, ``'kraus'`` or ``'stinespring'`` + target: target representation, should be ``'choi'``, ``'kraus'`` or ``'stinespring'`` size: batch size. Defaults to 1 - system_dim: dimension of systems. Can be a list of system dimensions + system_dim: dimension of systems. Can be a list of system dimensions or an int representing the dimension of all systems. Defaults to be qubit case. Returns: the target representation of a random channel. + + .. code-block:: python + + channel_kraus = random_channel(num_systems=1, target="kraus",system_dim=2) + print(f'The randomly generated kraus channel is:\n{channel_kraus}') + + channel_choi = random_channel(num_systems=1, target="choi",system_dim=2) + print(f'The randomly generated choi channel is:\n{channel_choi}') + + channel_stinespring = random_channel(num_systems=1, target="stinespring",system_dim=2,size=1,rank=1) + print(f'The randomly generated stinespring channel is:\n{channel_stinespring}') + batch_channels = random_channel(num_systems=2, size=2, target="kraus",system_dim=[1,2],rank=2) + print(f'The randomly generated kraus channel is:\n{batch_channels}') + + :: + + The randomly generated kraus channel is: + tensor([[[ 0.2361+0.7497j, 0.0224+0.6178j], + [ 0.5942-0.1706j, -0.7860+0.0085j]]]) + The randomly generated choi channel is: + tensor([[ 0.5136+0.0000j, -0.4784-0.1446j, -0.2850-0.4106j, -0.1583-0.4886j], + [-0.4784+0.1446j, 0.4864+0.0000j, 0.3811+0.3023j, 0.2850+0.4106j], + [-0.2850+0.4106j, 0.3811-0.3023j, 0.4864+0.0000j, 0.4784+0.1446j], + [-0.1583+0.4886j, 0.2850-0.4106j, 0.4784-0.1446j, 0.5136+0.0000j]]) + The randomly generated stinespring channel is: + tensor([[ 0.1652+0.5347j, 0.6310+0.5372j], + [ 0.4751+0.6790j, -0.5167-0.2150j]]) + The randomly generated kraus channel is: + tensor([[[[-0.3189-0.6385j, -0.1873+0.1634j], + [ 0.2218+0.0440j, -0.6294+0.0947j]], + + [[-0.0072+0.0749j, -0.0790+0.6740j], + [-0.5121-0.4142j, -0.0357-0.2671j]]], + + + [[[-0.1163-0.1931j, 0.2001-0.5852j], + [-0.5174+0.5253j, 0.1128-0.2459j]], + + [[-0.1362+0.3280j, -0.2677+0.5444j], + [ 0.4328-0.3033j, -0.3862-0.1646j]]]]) """ target = target.lower() dim = _format_total_dim(num_systems, system_dim) rank = np.random.randint(dim) + 1 if rank is None else rank - assert 1 <= rank <= dim, \ - f"rank must be positive and no larger than the dimension {dim} of the channel: received {rank}" + assert ( + 1 <= rank <= dim + ), f"rank must be positive and no larger than the dimension {dim} of the channel: received {rank}" list_repr = [] - + for _ in range(size): - + unitary = unitary_group.rvs(rank * dim) - stinespring_mat = torch.tensor(unitary[:, :dim], dtype=get_dtype()).reshape([rank, dim, dim]) + stinespring_mat = torch.tensor(unitary[:, :dim], dtype=get_dtype()).reshape( + [rank, dim, dim] + ) list_kraus = stinespring_mat[:rank] - if target == 'choi': - list_repr.append(qkit.qinfo.channel_repr_convert(list_kraus, source='kraus', target='choi')) - elif target == 'stinespring': - list_repr.append(qkit.qinfo.channel_repr_convert(list_kraus, source='kraus', target='stinespring')) + if target == "choi": + list_repr.append( + qkit.qinfo.channel_repr_convert( + list_kraus, source="kraus", target="choi" + ) + ) + elif target == "stinespring": + list_repr.append( + qkit.qinfo.channel_repr_convert( + list_kraus, source="kraus", target="stinespring" + ) + ) else: list_repr.append(list_kraus) - + return torch.stack(list_repr) if size > 1 else list_repr[0] + + +def random_clifford(num_qubits: int) -> torch.Tensor: + r"""Generate a random Clifford unitary. + + Args: + num_qubits: The number of qubits (n). + + Returns: + The matrix form of a random Clifford unitary. + + Reference: + Sergey Bravyi and Dmitri Maslov, *Hadamard-free circuits expose the structure of the Clifford group*. + `IEEE Transactions on Information Theory 67(7), 4546-4563 (2021)` + + .. code-block:: python + + num_qubits = 1 + clifford_matrix = random_clifford(num_qubits) + print(f'The randomly generated Clifford unitary is:\n{clifford_matrix}') + + :: + + The randomly generated Clifford unitary is: + tensor([[ 0.7071+0.0000j, -0.7071+0.0000j], + [ 0.0000+0.7071j, 0.0000+0.7071j]]) + + """ + # Generate a random Clifford operator (stabilizer tableaux) and the elements of the canonical form + _, gamma_matrices, delta_matrices, hadamard_layer, permutation = __generate_random_clifford(num_qubits) + + gamma1, gamma2 = gamma_matrices[0], gamma_matrices[1] + delta1, delta2 = delta_matrices[0].T, delta_matrices[1].T + phase = np.random.randint(0, 2, size=2 * num_qubits) + + # Initialize the circuit + circuit = qkit.Circuit(num_qubits) + + __apply_circuit_layers(circuit, delta2, gamma2) + + # Apply Pauli gates based on the phase vector + x_indices, y_indices, z_indices = [], [], [] + for idx in range(num_qubits): + if phase[idx] == 1 and phase[idx + num_qubits] == 0: + x_indices.append(idx) + elif phase[idx] == 0 and phase[idx + num_qubits] == 1: + y_indices.append(idx) + elif phase[idx] == 1 and phase[idx + num_qubits] == 1: + z_indices.append(idx) + if x_indices: + circuit.x(x_indices) + if y_indices: + circuit.y(y_indices) + if z_indices: + circuit.z(z_indices) + + # Apply SWAP gates based on the permutation + swapped_indices, swap_gate_indices = [], [] + for idx in range(num_qubits): + if permutation[idx] == idx: + continue + swapped_indices.append(permutation[idx]) + if idx in swapped_indices: + continue + swap_gate_indices.append([idx, permutation[idx]]) + if swap_gate_indices: + circuit.swap(swap_gate_indices) + + if hadamard_gate_indices := np.argwhere(hadamard_layer == 1).tolist(): + circuit.h(hadamard_gate_indices) + + __apply_circuit_layers(circuit, delta1, gamma1) + + # Return the Clifford unitary matrix + return circuit.unitary_matrix() + + +def __apply_circuit_layers(circuit, delta: Iterable[int], gamma: Iterable[int]) -> None: + r"""Apply CNOT, CZ, and S gates to the circuit based on Delta and Gamma matrices.""" + if cnot_gate_indices := np.argwhere(np.triu(delta, k=1) == 1).tolist(): + circuit.cnot(cnot_gate_indices) + if cz_gate_indices := np.argwhere(np.triu(gamma, k=1) == 1).tolist(): + circuit.cz(cz_gate_indices) + if s_gate_indices := np.argwhere(np.diag(gamma) == 1).tolist(): + circuit.s(s_gate_indices) + +def __generate_random_clifford( + num_qubits: int, +) -> Tuple[np.ndarray, List[np.ndarray], List[np.ndarray], np.ndarray]: + r"""Generate a random Clifford operator and its canonical form elements. + TODO: bad code quality, need to eliminate the for loops. + """ + # Constant matrices + zero_matrix = np.zeros((num_qubits, num_qubits), dtype=int) + zero_matrix_2n = np.zeros((2 * num_qubits, 2 * num_qubits), dtype=int) + identity_matrix = np.eye(num_qubits, dtype=int) + + # Sample from the quantum Mallows distribution + hadamard_layer, permutation = __sample_quantum_mallows(num_qubits) + + gamma1 = np.copy(zero_matrix) + delta1 = np.copy(identity_matrix) + gamma2 = np.copy(zero_matrix) + delta2 = np.copy(identity_matrix) + + # Generate random diagonal elements for Gamma matrices + for i in range(num_qubits): + gamma2[i, i] = np.random.randint(2) + if hadamard_layer[i]: + gamma1[i, i] = np.random.randint(2) + + # Generate random elements for Gamma and Delta matrices based on canonical form constraints + for j in range(num_qubits): + for i in range(j + 1, num_qubits): + b = np.random.randint(2) + gamma2[i, j] = b + gamma2[j, i] = b + delta2[i, j] = np.random.randint(2) + if hadamard_layer[i] == 1 and hadamard_layer[j] == 1: + b = np.random.randint(2) + gamma1[i, j] = b + gamma1[j, i] = b + if hadamard_layer[i] == 1 and hadamard_layer[j] == 0 and permutation[i] < permutation[j]: + b = np.random.randint(2) + gamma1[i, j] = b + gamma1[j, i] = b + if hadamard_layer[i] == 0 and hadamard_layer[j] == 1 and permutation[i] > permutation[j]: + b = np.random.randint(2) + gamma1[i, j] = b + gamma1[j, i] = b + if hadamard_layer[i] == 0 and hadamard_layer[j] == 1: + delta1[i, j] = np.random.randint(2) + if hadamard_layer[i] == 1 and hadamard_layer[j] == 1 and permutation[i] > permutation[j]: + delta1[i, j] = np.random.randint(2) + if hadamard_layer[i] == 0 and hadamard_layer[j] == 0 and permutation[i] < permutation[j]: + delta1[i, j] = np.random.randint(2) + + # Compute stabilizer tableaux + prod1 = np.matmul(gamma1, delta1) + prod2 = np.matmul(gamma2, delta2) + inv1 = np.linalg.inv(np.transpose(delta1)) + inv2 = np.linalg.inv(np.transpose(delta2)) + f1 = np.block([[delta1, zero_matrix], [prod1, inv1]]) + f2 = np.block([[delta2, zero_matrix], [prod2, inv2]]) + f1 = f1.astype(int) % 2 + f2 = f2.astype(int) % 2 + + # Compute the full stabilizer tableaux + stabilizer_tableaux = np.copy(zero_matrix_2n) + # Apply qubit permutation to F2 + for i in range(num_qubits): + stabilizer_tableaux[i, :] = f2[permutation[i], :] + stabilizer_tableaux[i + num_qubits, :] = f2[permutation[i] + num_qubits, :] + # Apply Hadamard layer + for i in range(num_qubits): + if hadamard_layer[i] == 1: + stabilizer_tableaux[(i, i + num_qubits), :] = stabilizer_tableaux[(i + num_qubits, i), :] + + gamma_matrices = [gamma1, gamma2] + delta_matrices = [delta1, delta2] + + return np.matmul(f1, stabilizer_tableaux) % 2, gamma_matrices, delta_matrices, hadamard_layer, permutation + + +def __sample_quantum_mallows(n: int) -> Tuple[np.ndarray, np.ndarray]: + r"""Sample from the quantum Mallows distribution.""" + # Initialize Hadamard layer and permutation layer + hadamard_layer = np.zeros(n, dtype=int) + permutation = np.zeros(n, dtype=int) + + remaining_indices = list(range(n)) + + for i in range(n): + m = n - i # Number of remaining indices + r = np.random.uniform(0, 1) + index = -1 * int(np.ceil(np.log2(r + (1 - r) * (4 ** (-1 * float(m)))))) + hadamard_layer[i] = 1 * (index < m) + k = index if index < m else 2 * m - index - 1 + permutation[i] = remaining_indices[k] + del remaining_indices[k] + + return hadamard_layer, permutation diff --git a/quairkit/database/representation.py b/quairkit/database/representation.py index 50d75f7..010f57c 100644 --- a/quairkit/database/representation.py +++ b/quairkit/database/representation.py @@ -22,9 +22,10 @@ import numpy as np import torch -from ..core import State, get_dtype, to_state -from ..core.intrinsic import _get_float_dtype -from ..core.utils.linalg import _one, _zero +from ..core import State, get_dtype, to_state, utils +from ..core.intrinsic import (_ArrayLike, _get_float_dtype, _SingleParamLike, + _StateLike, _type_fetch, _type_transform) +from ..core.utils.matrix import _one, _zero from .set import pauli_basis __all__ = [ @@ -46,7 +47,7 @@ ] -def bit_flip_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: +def bit_flip_kraus(prob: _SingleParamLike) -> List[_ArrayLike]: r"""Kraus representation of a bit flip channel with form .. math:: @@ -61,26 +62,31 @@ def bit_flip_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: str = No Returns: a list of Kraus operators + .. code-block:: python + + prob = torch.tensor([0.5]) + kraus_operators = bit_flip_kraus(prob) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[0.7071+0.j, 0.0000+0.j], + [0.0000+0.j, 0.7071+0.j]], + + [[0.0000+0.j, 0.7071+0.j], + [0.7071+0.j, 0.0000+0.j]]], dtype=torch.complex128) + """ - dtype = get_dtype() if dtype is None else dtype - prob = prob if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=_get_float_dtype(dtype)) - prob = prob.view([1]) - kraus_oper = [ - [ - torch.sqrt(1 - prob).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(1 - prob).to(dtype), - ], - [ - _zero(dtype), torch.sqrt(prob).to(dtype), - torch.sqrt(prob).to(dtype), _zero(dtype), - ] - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def phase_flip_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: + type_str, prob = _type_fetch(prob), _type_transform(prob, "tensor") + mat = utils.representation._bit_flip_kraus(prob) + return _type_transform(mat, type_str) + + + + + +def phase_flip_kraus(prob: _SingleParamLike) -> List[_ArrayLike]: r"""Kraus representation of a phase flip channel with form .. math:: @@ -94,26 +100,28 @@ def phase_flip_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: str = Returns: a list of Kraus operators + + .. code-block:: python + + prob = torch.tensor([0.1]) + kraus_operators = phase_flip_kraus(prob) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[ 0.9487+0.j, 0.0000+0.j], + [ 0.0000+0.j, 0.9487+0.j]], + + [[ 0.3162+0.j, 0.0000+0.j], + [ 0.0000+0.j, -0.3162+0.j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - prob = prob if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=_get_float_dtype(dtype)) - prob = prob.view([1]) - kraus_oper = [ - [ - torch.sqrt(1 - prob).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(1 - prob).to(dtype), - ], - [ - torch.sqrt(prob).to(dtype), _zero(dtype), - _zero(dtype), (-torch.sqrt(prob)).to(dtype), - ] - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def bit_phase_flip_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: + type_str, prob = _type_fetch(prob), _type_transform(prob, "tensor") + mat = utils.representation._phase_flip_kraus(prob) + return _type_transform(mat, type_str) + + +def bit_phase_flip_kraus(prob: _SingleParamLike ) -> List[_ArrayLike]: r"""Kraus representation of a bit-phase flip channel with form .. math:: @@ -127,26 +135,29 @@ def bit_phase_flip_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: st Returns: a list of Kraus operators + + .. code-block:: python + + prob = torch.tensor([0.1]) + kraus_operators = bit_phase_flip_kraus(prob) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[0.9487+0.0000j, 0.0000+0.0000j], + [0.0000+0.0000j, 0.9487+0.0000j]], + + [[0.0000+0.0000j, 0.0000-0.3162j], + [0.0000+0.3162j, 0.0000+0.0000j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - prob = prob if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=_get_float_dtype(dtype)) - prob = prob.view([1]) - kraus_oper = [ - [ - torch.sqrt(1 - prob).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(1 - prob).to(dtype), - ], - [ - _zero(dtype), -1j * torch.sqrt(prob), - 1j * torch.sqrt(prob), _zero(dtype), - ] - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def amplitude_damping_kraus(gamma: Union[float, np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: + type_str, prob = _type_fetch(prob), _type_transform(prob, "tensor") + mat = utils.representation._bit_phase_flip_kraus(prob) + return _type_transform(mat, type_str) + + + +def amplitude_damping_kraus(gamma: _SingleParamLike ) -> List[_ArrayLike]: r"""Kraus representation of an amplitude damping channel with form .. math:: @@ -168,29 +179,32 @@ def amplitude_damping_kraus(gamma: Union[float, np.ndarray, torch.Tensor], dtype Returns: a list of Kraus operators + + .. code-block:: python + + gamma = torch.tensor(0.2) + kraus_operators = amplitude_damping_kraus(gamma) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[1.0000+0.j, 0.0000+0.j], + [0.0000+0.j, 0.8944+0.j]], + + [[0.0000+0.j, 0.4472+0.j], + [0.0000+0.j, 0.0000+0.j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - gamma = gamma if isinstance(gamma, torch.Tensor) else torch.tensor(gamma, dtype=_get_float_dtype(dtype)) - gamma = gamma.view([1]) - kraus_oper = [ - [ - _one(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(1 - gamma).to(dtype), - ], - [ - _zero(dtype), torch.sqrt(gamma).to(dtype), - _zero(dtype), _zero(dtype)], - - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) + type_str, gamma = _type_fetch(gamma), _type_transform(gamma, "tensor") + mat = utils.representation._amplitude_damping_kraus(gamma) + return _type_transform(mat, type_str) + def generalized_amplitude_damping_kraus( - gamma: Union[float, np.ndarray, torch.Tensor], - prob: Union[float, np.ndarray, torch.Tensor], dtype: str = None -) -> List[torch.Tensor]: + gamma: _SingleParamLike, + prob: _SingleParamLike +) -> List[_ArrayLike]: r"""Kraus representation of a generalized amplitude damping channel with form .. math:: @@ -207,36 +221,38 @@ def generalized_amplitude_damping_kraus( Returns: a list of Kraus operators + + .. code-block:: python + + gamma = torch.tensor(0.2) + prob = torch.tensor(0.1) + kraus_operators = generalized_amplitude_damping_kraus(gamma,prob) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[0.3162+0.j, 0.0000+0.j], + [0.0000+0.j, 0.2828+0.j]], + + [[0.0000+0.j, 0.1414+0.j], + [0.0000+0.j, 0.0000+0.j]], + + [[0.8485+0.j, 0.0000+0.j], + [0.0000+0.j, 0.9487+0.j]], + + [[0.0000+0.j, 0.0000+0.j], + [0.4243+0.j, 0.0000+0.j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - float_dtype = _get_float_dtype(dtype) - gamma = gamma if isinstance(gamma, torch.Tensor) else torch.tensor(gamma, dtype=float_dtype) - prob = prob if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=float_dtype) - gamma, prob = gamma.view([1]), prob.view([1]) - kraus_oper = [ - [ - torch.sqrt(prob).to(dtype), _zero(dtype), - _zero(dtype), (torch.sqrt(prob).to(dtype) * torch.sqrt(1 - gamma)).to(dtype), - ], - [ - _zero(dtype), (torch.sqrt(prob) * torch.sqrt(gamma)).to(dtype), - _zero(dtype), _zero(dtype), - ], - [ - (torch.sqrt(1 - prob) * torch.sqrt(1 - gamma)).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(1 - prob).to(dtype), - ], - [ - _zero(dtype), _zero(dtype), - (torch.sqrt(1 - prob) * torch.sqrt(gamma)).to(dtype), _zero(dtype), - ], - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def phase_damping_kraus(gamma: Union[float, np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: + type_str, gamma, prob = _type_fetch(gamma), _type_transform(gamma, "tensor"),_type_transform(prob, "tensor") + mat = utils.representation._generalized_amplitude_damping_kraus(gamma,prob) + return _type_transform(mat, type_str) + + + + +def phase_damping_kraus(gamma: _SingleParamLike ) -> List[_ArrayLike]: + r"""Kraus representation of a phase damping channel with form .. math:: @@ -258,26 +274,28 @@ def phase_damping_kraus(gamma: Union[float, np.ndarray, torch.Tensor], dtype: st Returns: a list of Kraus operators + + .. code-block:: python + + gamma = torch.tensor(0.2) + kraus_operators = phase_damping_kraus(gamma) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[1.0000+0.j, 0.0000+0.j], + [0.0000+0.j, 0.8944+0.j]], + + [[0.0000+0.j, 0.0000+0.j], + [0.0000+0.j, 0.4472+0.j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - gamma = gamma if isinstance(gamma, torch.Tensor) else torch.tensor(gamma, dtype=_get_float_dtype(dtype)) - gamma = gamma.view([1]) - kraus_oper = [ - [ - _one(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(1 - gamma).to(dtype), - ], - [ - _zero(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(gamma).to(dtype), - ] - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def depolarizing_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: + type_str, gamma = _type_fetch(gamma), _type_transform(gamma, "tensor") + mat = utils.representation._phase_damping_kraus(gamma) + return _type_transform(mat, type_str) + + +def depolarizing_kraus(prob: _SingleParamLike ) -> List[_ArrayLike]: r"""Kraus representation of a depolarizing channel with form .. math:: @@ -293,34 +311,35 @@ def depolarizing_kraus(prob: Union[float, np.ndarray, torch.Tensor], dtype: str Returns: a list of Kraus operators + + .. code-block:: python + + prob = torch.tensor(0.1) + kraus_operators = depolarizing_kraus(prob) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[ 0.9618+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, 0.9618+0.0000j]], + + [[ 0.0000+0.0000j, 0.1581+0.0000j], + [ 0.1581+0.0000j, 0.0000+0.0000j]], + + [[ 0.0000+0.0000j, 0.0000-0.1581j], + [ 0.0000+0.1581j, 0.0000+0.0000j]], + + [[ 0.1581+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, -0.1581+0.0000j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - prob = prob if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=_get_float_dtype(dtype)) - prob = prob.view([1]) - kraus_oper = [ - [ - torch.sqrt(1 - 3 * prob / 4).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(1 - 3 * prob / 4).to(dtype), - ], - [ - _zero(dtype), torch.sqrt(prob / 4).to(dtype), - torch.sqrt(prob / 4).to(dtype), _zero(dtype), - ], - [ - _zero(dtype), -1j * torch.sqrt(prob / 4).to(dtype), - 1j * torch.sqrt(prob / 4).to(dtype), _zero(dtype), - ], - [ - torch.sqrt(prob / 4).to(dtype), _zero(dtype), - _zero(dtype), (-1 * torch.sqrt(prob / 4)).to(dtype), - ], - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def generalized_depolarizing_kraus(prob: float, num_qubits: int, dtype: str = None) -> List[torch.Tensor]: + type_str, prob = _type_fetch(prob), _type_transform(prob, "tensor") + mat = utils.representation._depolarizing_kraus(prob) + return _type_transform(mat, type_str) + + + +def generalized_depolarizing_kraus(prob: _SingleParamLike, num_qubits: int,dtype: torch.dtype=torch.complex128 ) -> List[_ArrayLike]: r"""Kraus representation of a generalized depolarizing channel with form .. math:: @@ -335,22 +354,48 @@ def generalized_depolarizing_kraus(prob: float, num_qubits: int, dtype: str = No Returns: a list of Kraus operators + + .. code-block:: python + + prob = torch.tensor(0.1) + num_qubits=1 + kraus_operators = generalized_depolarizing_kraus(prob,num_qubits) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[ 1.3601+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, 1.3601+0.0000j]], + + [[ 0.0000+0.0000j, 0.2236+0.0000j], + [ 0.2236+0.0000j, 0.0000+0.0000j]], + + [[ 0.0000+0.0000j, 0.0000-0.2236j], + [ 0.0000+0.2236j, 0.0000+0.0000j]], + + [[ 0.2236+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, -0.2236+0.0000j]]]) """ - dtype = get_dtype() if dtype is None else dtype - prob = prob if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=_get_float_dtype(dtype)) + type_str, prob = _type_fetch(prob), _type_transform(prob, "tensor") + dtype = get_dtype() prob = prob.view([1]) basis = [ele.to(dtype) * (2 ** num_qubits + 0j) for ele in pauli_basis(num_qubits)] I, other_elements = basis[0], basis[1:] dim = 4 ** num_qubits - return torch.stack( - [I * (torch.sqrt(1 - (dim - 1) * prob / dim) + 0j)] + - [ele * (torch.sqrt(prob / dim) + 0j) for ele in other_elements] - ) + mat= torch.stack([I * (torch.sqrt(1 - (dim - 1) * prob / dim) + 0j)] + + [ele * (torch.sqrt(prob / dim) + 0j) for ele in other_elements]) + + return _type_transform(mat, type_str) + + + -def pauli_kraus(prob: Union[List[float], np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: + +def pauli_kraus(prob: _SingleParamLike ) -> List[_ArrayLike]: r"""Kraus representation of a pauli channel Args: @@ -359,40 +404,35 @@ def pauli_kraus(prob: Union[List[float], np.ndarray, torch.Tensor], dtype: str = Returns: a list of Kraus operators + + .. code-block:: python + + prob_list = torch.tensor([0.1, 0.2, 0.3]) + kraus_operators = pauli_kraus(prob_list) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[ 0.6325+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, 0.6325+0.0000j]], + + [[ 0.0000+0.0000j, 0.3162+0.0000j], + [ 0.3162+0.0000j, 0.0000+0.0000j]], + + [[ 0.0000+0.0000j, 0.0000-0.4472j], + [ 0.0000+0.4472j, 0.0000+0.0000j]], + + [[ 0.5477+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, -0.5477+0.0000j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - float_dtype = _get_float_dtype(dtype) - prob = prob.to(float_dtype) if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=float_dtype) - prob_x, prob_y, prob_z = prob[0].view([1]), prob[1].view([1]), prob[2].view([1]) - prob_sum = torch.sum(prob) - assert prob_sum <= 1, \ - f"The sum of input probabilities should not be greater than 1: received {prob_sum.item()}" - prob_i = 1 - prob_sum - prob_i = prob_i.view([1]) - kraus_oper = [ - [ - torch.sqrt(prob_i).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(prob_i).to(dtype), - ], - [ - _zero(dtype), torch.sqrt(prob_x).to(dtype), - torch.sqrt(prob_x).to(dtype), _zero(dtype), - ], - [ - _zero(dtype), -1j * torch.sqrt(prob_y).to(dtype), - 1j * torch.sqrt(prob_y).to(dtype), _zero(dtype), - ], - [ - torch.sqrt(prob_z).to(dtype), _zero(dtype), - _zero(dtype), (-torch.sqrt(prob_z)).to(dtype), - ], - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def reset_kraus(prob: Union[List[float], np.ndarray, torch.Tensor], dtype: str = None) -> List[torch.Tensor]: + type_str, prob = _type_fetch(prob), _type_transform(prob, "tensor") + mat = utils.representation._pauli_kraus(prob) + return _type_transform(mat, type_str) + + + +def reset_kraus(prob: _SingleParamLike ) -> List[_ArrayLike]: r"""Kraus representation of a reset channel with form .. math:: @@ -425,47 +465,40 @@ def reset_kraus(prob: Union[List[float], np.ndarray, torch.Tensor], dtype: str = Returns: a list of Kraus operators + + .. code-block:: python + + prob_list = torch.tensor([0.1, 0.2]) + kraus_operators = reset_kraus(prob_list) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[0.3162+0.j, 0.0000+0.j], + [0.0000+0.j, 0.0000+0.j]], + + [[0.0000+0.j, 0.3162+0.j], + [0.0000+0.j, 0.0000+0.j]], + + [[0.0000+0.j, 0.0000+0.j], + [0.4472+0.j, 0.0000+0.j]], + + [[0.0000+0.j, 0.0000+0.j], + [0.0000+0.j, 0.4472+0.j]], + + [[0.8367+0.j, 0.0000+0.j], + [0.0000+0.j, 0.8367+0.j]]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - float_dtype = _get_float_dtype(dtype) - prob = prob.to(float_dtype) if isinstance(prob, torch.Tensor) else torch.tensor(prob, dtype=float_dtype) - prob_0, prob_1 = prob[0].view([1]), prob[1].view([1]) - prob_sum = torch.sum(prob) - assert prob_sum <= 1, \ - f"The sum of input probabilities should not be greater than 1: received {prob_sum.item()}" - prob_i = 1 - prob_sum - prob_i = prob_i.view([1]) - kraus_oper = [ - [ - torch.sqrt(prob_0).to(dtype), _zero(dtype), - _zero(dtype), _zero(dtype), - ], - [ - _zero(dtype), torch.sqrt(prob_0).to(dtype), - _zero(dtype), _zero(dtype), - ], - [ - _zero(dtype), _zero(dtype), - torch.sqrt(prob_1).to(dtype), _zero(dtype), - ], - [ - _zero(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(prob_1).to(dtype), - ], - [ - torch.sqrt(prob_i).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(prob_i).to(dtype), - ], - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) + type_str, prob = _type_fetch(prob), _type_transform(prob, "tensor") + mat = utils.representation._reset_kraus(prob) + return _type_transform(mat, type_str) def thermal_relaxation_kraus( - const_t: Union[List[float], np.ndarray, torch.Tensor], - exec_time: Union[List[float], np.ndarray, torch.Tensor], dtype: str = None -) -> List[torch.Tensor]: + const_t: _SingleParamLike, + exec_time: _SingleParamLike +) -> List[_ArrayLike]: r"""Kraus representation of a thermal relaxation channel Args: @@ -475,44 +508,39 @@ def thermal_relaxation_kraus( Returns: a list of Kraus operators. + + .. code-block:: python + + const_t = torch.tensor([50, 30]) + exec_time = torch.tensor([100]) + kraus_operators = thermal_relaxation_kraus(const_t, exec_time) + print(f'The Kraus operators are:\n{kraus_operators}') + + :: + + The Kraus operators are: + tensor([[[ 0.9987+0.j, 0.0000+0.j], + [ 0.0000+0.j, 0.9987+0.j]], + + [[ 0.0258+0.j, 0.0000+0.j], + [ 0.0000+0.j, -0.0258+0.j]], + + [[ 0.0447+0.j, 0.0000+0.j], + [ 0.0000+0.j, 0.0000+0.j]], + + [[ 0.0000+0.j, 0.0447+0.j], + [ 0.0000+0.j, 0.0000+0.j]]], dtype=torch.complex128) + """ - dtype = get_dtype() if dtype is None else dtype - float_dtype = _get_float_dtype(dtype) - - const_t = const_t.to(float_dtype) if isinstance(const_t, torch.Tensor) else torch.tensor(const_t, dtype=float_dtype) - t1, t2 = const_t[0].view([1]), const_t[1].view([1]) - assert t2 <= t1, \ - f"The relaxation time T2 and T1 must satisfy T2 <= T1: received T2 {t2} and T1{t1}" - - exec_time = exec_time.to(float_dtype) / 1000 if isinstance(exec_time, torch.Tensor) else torch.tensor(exec_time / 1000, dtype=float_dtype) - prob_reset = 1 - torch.exp(-exec_time / t1) - prob_z = (1 - prob_reset) * (1 - torch.exp(-exec_time / t2) * torch.exp(exec_time / t1)) / 2 - prob_z = _zero(float_dtype) if torch.abs(prob_z) <= 0 else prob_z - prob_i = 1 - prob_reset - prob_z - kraus_oper = [ - [ - torch.sqrt(prob_i).to(dtype), _zero(dtype), - _zero(dtype), torch.sqrt(prob_i).to(dtype), - ], - [ - torch.sqrt(prob_z).to(dtype), _zero(dtype), - _zero(dtype), (-torch.sqrt(prob_z)).to(dtype), - ], - [ - torch.sqrt(prob_reset).to(dtype), _zero(dtype), - _zero(dtype), _zero(dtype), - ], - [ - _zero(dtype), torch.sqrt(prob_reset).to(dtype), - _zero(dtype), _zero(dtype), - ], - ] - for idx, oper in enumerate(kraus_oper): - kraus_oper[idx] = torch.cat(oper).view([2, 2]) - return torch.stack(kraus_oper) - - -def replacement_choi(sigma: Union[np.ndarray, torch.Tensor, State], dtype: str = None) -> torch.Tensor: + type_str, const_t,exec_time = _type_fetch(const_t), _type_transform(const_t, "tensor"),_type_transform(exec_time, "tensor") + mat = utils.representation._thermal_relaxation_kraus(const_t,exec_time) + return _type_transform(mat, type_str) + + + + + +def replacement_choi(sigma: _StateLike ) -> _StateLike: r"""Choi representation of a replacement channel Args: @@ -521,12 +549,24 @@ def replacement_choi(sigma: Union[np.ndarray, torch.Tensor, State], dtype: str = Returns: a Choi operator. + + .. code-block:: python + + sigma= torch.tensor([[0.8, 0.0], [0.0, 0.2]]) + choi_operator = replacement_choi(sigma) + print(f'The Choi operator is :\n{choi_operator}') + + :: + + The Choi operator is : + tensor([[0.8000+0.j, 0.0000+0.j, 0.0000+0.j, 0.0000+0.j], + [0.0000+0.j, 0.2000+0.j, 0.0000+0.j, 0.0000+0.j], + [0.0000+0.j, 0.0000+0.j, 0.8000+0.j, 0.0000+0.j], + [0.0000+0.j, 0.0000+0.j, 0.0000+0.j, 0.2000+0.j]], dtype=torch.complex128) """ - dtype = get_dtype() if dtype is None else dtype - - # sanity check - sigma = sigma if isinstance(sigma, State) else to_state(sigma) - sigma = sigma.density_matrix - - dim = sigma.shape[0] - return torch.kron(torch.eye(dim), sigma).to(dtype) + + type_str, sigma = _type_fetch(sigma), _type_transform(sigma, "tensor") + mat = utils.representation._replacement_choi(sigma) + return mat if type_str == "numpy" else mat + + \ No newline at end of file diff --git a/quairkit/database/set.py b/quairkit/database/set.py index 2b6b784..1e053da 100644 --- a/quairkit/database/set.py +++ b/quairkit/database/set.py @@ -49,18 +49,39 @@ def pauli_basis(num_qubits: int) -> torch.Tensor: Returns: The Pauli basis of :math:`\mathbb{C}^{2^n \times 2^n}`, where each tensor is accessible along the first dimension. + .. code-block:: python + + num_qubits = 1 + basis = pauli_basis(num_qubits) + print(f'The Pauli basis is:\n{basis}') + + :: + + The Pauli basis is: + tensor([[[ 0.7071+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, 0.7071+0.0000j]], + + [[ 0.0000+0.0000j, 0.7071+0.0000j], + [ 0.7071+0.0000j, 0.0000+0.0000j]], + + [[ 0.0000+0.0000j, 0.0000-0.7071j], + [ 0.0000+0.7071j, 0.0000+0.0000j]], + + [[ 0.7071+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, -0.7071+0.0000j]]]) + """ - single_pauli_basis = torch.stack([database.matrix.eye(torch.complex128), - database.matrix.x(torch.complex128), - database.matrix.y(torch.complex128), - database.matrix.z(torch.complex128)]) * math.sqrt(2) / 2 + single_pauli_basis = torch.stack([database.matrix.eye(), + database.matrix.x(), + database.matrix.y(), + database.matrix.z()]) * math.sqrt(2) / 2 if num_qubits == 1: return single_pauli_basis return reduce( lambda result, index: torch.kron(result, index), [single_pauli_basis for _ in range(num_qubits - 2)], torch.kron(single_pauli_basis, single_pauli_basis), - ).to(get_dtype()) + ) def pauli_group(num_qubits: int) -> torch.Tensor: @@ -72,6 +93,27 @@ def pauli_group(num_qubits: int) -> torch.Tensor: Returns: The Pauli group of :math:`\mathbb{C}^{2^n \times 2^n}`, where each tensor is accessible along the first dimension. + .. code-block:: python + + num_qubits = 1 + group = pauli_group(num_qubits) + print(f'The Pauli group is:\n{group}') + + :: + + The Pauli group is: + tensor([[[ 1.0000+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, 1.0000+0.0000j]], + + [[ 0.0000+0.0000j, 1.0000+0.0000j], + [ 1.0000+0.0000j, 0.0000+0.0000j]], + + [[ 0.0000+0.0000j, 0.0000-1.0000j], + [ 0.0000+1.0000j, 0.0000+0.0000j]], + + [[ 1.0000+0.0000j, 0.0000+0.0000j], + [ 0.0000+0.0000j, -1.0000+0.0000j]]]) + """ return pauli_basis(num_qubits) * (math.sqrt(2) ** num_qubits) @@ -84,6 +126,33 @@ def pauli_str_basis(pauli_str: Union[str, List[str]]) -> State: Returns: The state basis of the observable given by the Pauli string + + .. code-block:: python + + pauli_str = ['x','z'] + state_basis = pauli_str_basis(pauli_str) + print(f'The state basis of the observable is:\n{state_basis}') + + :: + + The state basis of the observable is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2] + System sequence: [0] + Batch size: [2, 2] + + # 0: + [0.71+0.j 0.71+0.j] + # 1: + [ 0.71+0.j -0.71+0.j] + # 2: + [1.+0.j 0.+0.j] + # 3: + [0.+0.j 1.+0.j] + --------------------------------------------------- + """ x_basis = torch.tensor([[1, 1], @@ -113,7 +182,28 @@ def pauli_str_povm(pauli_str: Union[str, List[str]]) -> torch.Tensor: Returns: The POVM of the observable given by the Pauli string - """ + .. code-block:: python + + pauli_str = ['x','y'] + POVM = pauli_str_povm(pauli_str) + print(f'The POVM of the observable is:\n{POVM}') + + :: + + The POVM of the observable is: + tensor([[[[ 0.5000+0.0000j, 0.5000+0.0000j], + [ 0.5000+0.0000j, 0.5000+0.0000j]], + + [[ 0.5000+0.0000j, -0.5000+0.0000j], + [-0.5000+0.0000j, 0.5000+0.0000j]]], + + + [[[ 0.5000+0.0000j, 0.0000-0.5000j], + [ 0.0000+0.5000j, 0.5000+0.0000j]], + + [[ 0.5000+0.0000j, 0.0000+0.5000j], + [ 0.0000-0.5000j, 0.5000+0.0000j]]]]) + """ return pauli_str_basis(pauli_str).density_matrix @@ -126,9 +216,32 @@ def qft_basis(num_qubits: int) -> State: Returns: A tensor where the first index gives the eigenvector of the QFT matrix. + .. code-block:: python + + num_qubits = 2 + qft_state = qft_basis(num_qubits) + print(f'The eigenvectors of the QFT matrix is:\n{qft_state}') + + :: + + The eigenvectors of the QFT matrix is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2] + System sequence: [0] + Batch size: [2] + + # 0: + [0.92+0.j 0.38+0.j] + # 1: + [-0.38-0.j 0.92+0.j] + --------------------------------------------------- + + """ #TODO numerically unstable, needs a more precise implementation instead of using eig decomposition - _, eigvec = torch.linalg.eig(database.matrix.qft_matrix(num_qubits, dtype=torch.complex128)) + _, eigvec = torch.linalg.eig(database.matrix.qft_matrix(num_qubits)) return to_state(eigvec.T.unsqueeze(-1).to(get_dtype())) @@ -144,6 +257,29 @@ def std_basis(num_systems: int, system_dim: Union[List[int], int] = 2) -> State: Returns: A tensor where the first index gives the computational vector + .. code-block:: python + + num_systems = 2 + system_dim=[1,2] + basis = std_basis(num_systems,system_dim) + print(f'The standard basis states are:\n{basis}') + + :: + + The standard basis states are: + + --------------------------------------------------- + Backend: state_vector + System dimension: [1, 2] + System sequence: [0, 1] + Batch size: [2] + + # 0: + [1.+0.j 0.+0.j] + # 1: + [0.+0.j 1.+0.j] + --------------------------------------------------- + """ dim = system_dim ** num_systems if isinstance(system_dim, int) else math.prod(system_dim) return to_state(torch.eye(dim).unsqueeze(-1).to(get_dtype()), system_dim) @@ -156,6 +292,30 @@ def bell_basis() -> State: Returns: A tensor of shape (4, 4, 1), representing the four Bell basis states. + .. code-block:: python + + basis=bell_basis() + print(f'The Bell basis for a 2-qubit system are:\n{basis}') + + :: + + The Bell basis for a 2-qubit system are: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2, 2] + System sequence: [0, 1] + Batch size: [4] + + # 0: + [0.71+0.j 0. +0.j 0. +0.j 0.71+0.j] + # 1: + [ 0.71+0.j 0. +0.j 0. +0.j -0.71+0.j] + # 2: + [0. +0.j 0.71+0.j 0.71+0.j 0. +0.j] + # 3: + [ 0. +0.j 0.71+0.j -0.71+0.j 0. +0.j] + --------------------------------------------------- """ mat = torch.tensor([ [ 1, 0, 0, 1], # |Φ+⟩ = (|00⟩ + |11⟩) / √2 @@ -168,13 +328,35 @@ def bell_basis() -> State: def heisenberg_weyl(dim: int) -> torch.Tensor: r"""Generate Heisenberg-Weyl operator for qudit. - The Heisenberg-Weyl operators are defined as T(a,b) = e^{-(d+1) \pi i a b/ d}Z^a X^b. + The Heisenberg-Weyl operators are defined as :math:`T(a,b) = e^{-(d+1) \pi i a b/ d}Z^a X^b`. Args: dim: dimension of qudit Returns: Heisenberg-Weyl operator for qudit + + .. code-block:: python + + dim=2 + operator=heisenberg_weyl(dim) + print(f'The Heisenberg-Weyl operator for qudit is:\n{operator}') + + :: + + The Heisenberg-Weyl operator for qudit is: + tensor([[[ 1.0000e+00+0.0000e+00j, 0.0000e+00+0.0000e+00j], + [ 0.0000e+00+0.0000e+00j, 1.0000e+00+0.0000e+00j]], + + [[ 1.0000e+00+0.0000e+00j, 0.0000e+00+0.0000e+00j], + [ 0.0000e+00+0.0000e+00j, -1.0000e+00+1.2246e-16j]], + + [[ 0.0000e+00+0.0000e+00j, 1.0000e+00+0.0000e+00j], + [ 1.0000e+00+0.0000e+00j, 0.0000e+00+0.0000e+00j]], + + [[-0.0000e+00+0.0000e+00j, -1.8370e-16+1.0000e+00j], + [ 6.1232e-17-1.0000e+00j, -0.0000e+00+0.0000e+00j]]], + dtype=torch.complex128) """ complex_dtype = get_dtype() _phase = database.matrix.phase(dim) @@ -208,6 +390,27 @@ def phase_space_point(dim: int) -> torch.Tensor: Returns: Phase space point operator for qudit + + .. code-block:: python + + dim=2 + operator=phase_space_point(dim) + print(f'The phase space point operator for qudit is:\n{operator}') + + :: + + The phase space point operator for qudit is: + tensor([[[ 1.0000+0.0000e+00j, 0.5000+5.0000e-01j], + [ 0.5000-5.0000e-01j, 0.0000+6.1232e-17j]], + + [[ 1.0000+0.0000e+00j, -0.5000-5.0000e-01j], + [-0.5000+5.0000e-01j, 0.0000+6.1232e-17j]], + + [[ 0.0000+6.1232e-17j, 0.5000-5.0000e-01j], + [ 0.5000+5.0000e-01j, 1.0000+0.0000e+00j]], + + [[ 0.0000+6.1232e-17j, -0.5000+5.0000e-01j], + [-0.5000-5.0000e-01j, 1.0000+0.0000e+00j]]], dtype=torch.complex128) """ hw = heisenberg_weyl(dim) @@ -249,6 +452,24 @@ def gell_mann(dim: int) -> torch.Tensor: Returns: A set of Gell-Mann matrices. + + .. code-block:: python + + dim=2 + matrices=gell_mann(dim) + print(f'The Gell-Mann matrices are:\n{matrices}') + + :: + + The Gell-Mann matrices are: + tensor([[[ 0.+0.j, 1.+0.j], + [ 1.+0.j, 0.+0.j]], + + [[ 0.+0.j, -0.-1.j], + [ 0.+1.j, 0.+0.j]], + + [[ 1.+0.j, 0.+0.j], + [ 0.+0.j, -1.+0.j]]]) """ list_gell_mann = [ __gell_mann(idx1, idx2, dim).unsqueeze(0) diff --git a/quairkit/database/state.py b/quairkit/database/state.py index cab25c9..d547c55 100644 --- a/quairkit/database/state.py +++ b/quairkit/database/state.py @@ -52,6 +52,25 @@ def zero_state(num_systems: int, system_dim: Union[List[int], int] = 2) -> State Returns: The generated quantum state. + + .. code-block:: python + + num_systems = 2 + system_dim=[2,3] + state = zero_state(num_systems,system_dim) + print(f'The zero state is:\n{state}') + + :: + + The zero state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2, 3] + System sequence: [0, 1] + [1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j] + --------------------------------------------------- + """ return computational_state(num_systems, 0, system_dim) @@ -67,6 +86,25 @@ def one_state(num_systems: int, system_dim: Union[List[int], int] = 2) -> State: Returns: The generated quantum state. + + .. code-block:: python + + num_systems = 2 + system_dim=[1,3] + state = one_state(num_systems,system_dim) + print(f'The one state is:\n{state}') + + :: + + The one state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [1, 3] + System sequence: [0, 1] + [0.+0.j 1.+0.j 0.+0.j] + --------------------------------------------------- + """ return computational_state(num_systems, 1, system_dim) @@ -79,12 +117,31 @@ def computational_state(num_systems: int, index: int, Args: num_systems: number of systems in this state. Alias of ``num_qubits``. - index: Index :math:`i` of the computational basis state :math`|e_{i}rangle` . + index: Index :math:`i` of the computational basis state :math:`|e_{i}rangle` . system_dim: dimension of systems. Can be a list of system dimensions or an int representing the dimension of all systems. Defaults to be qubit case. Returns: The generated quantum state. + + .. code-block:: python + + num_systems = 2 + system_dim=[2,3] + index=4 + state = computational_state(num_systems,index,system_dim) + print(f'The state is:\n{state}') + + :: + + The state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2, 3] + System sequence: [0, 1] + [0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j] + --------------------------------------------------- """ dim = _format_total_dim(num_systems, system_dim) @@ -110,6 +167,24 @@ def bell_state(num_systems: int, system_dim: Union[List[int], int] = 2) -> State Returns: The generated quantum state. + + .. code-block:: python + + num_systems = 2 + system_dim=[2,2] + state = bell_state(num_systems,system_dim) + print(f'The Bell state is:\n{state}') + + :: + + The Bell state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2, 2] + System sequence: [0, 1] + [0.71+0.j 0. +0.j 0. +0.j 0.71+0.j] + --------------------------------------------------- """ assert num_systems % 2 == 0, \ f"Number of systems must be even to form a Bell state. Received: {num_systems}" @@ -148,6 +223,26 @@ def bell_diagonal_state(prob: List[float]) -> State: Returns: The generated quantum state. + + .. code-block:: python + + prob=[0.2,0.3,0.4,0.1] + state = bell_diagonal_state(prob) + print(f'The Bell diagonal state is:\n{state}') + + :: + + The Bell diagonal state is: + + --------------------------------------------------- + Backend: density_matrix + System dimension: [2, 2] + System sequence: [0, 1] + [[ 0.3+0.j 0. +0.j 0. +0.j -0.1+0.j] + [ 0. +0.j 0.2+0.j 0.1+0.j 0. +0.j] + [ 0. +0.j 0.1+0.j 0.2+0.j 0. +0.j] + [-0.1+0.j 0. +0.j 0. +0.j 0.3+0.j]] + --------------------------------------------------- """ p1, p2, p3, p4 = prob assert 0 <= p1 <= 1 and 0 <= p2 <= 1 and 0 <= p3 <= 1 and 0 <= p4 <= 1, \ @@ -189,6 +284,24 @@ def w_state(num_qubits: int) -> State: Returns: The generated quantum state. + + .. code-block:: python + + num_qubits = 2 + W_state =w_state(num_qubits) + print(f'The W-state is:\n{W_state}') + + :: + + The W-state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2, 2] + System sequence: [0, 1] + [0. +0.j 0.71+0.j 0.71+0.j 0. +0.j] + --------------------------------------------------- + """ dim = 2 ** num_qubits coeff = 1 / math.sqrt(num_qubits) @@ -211,6 +324,23 @@ def ghz_state(num_qubits: int) -> State: Returns: The generated quantum state. + + .. code-block:: python + + num_qubits = 2 + GHZ_state =ghz_state(num_qubits) + print(f'The GHZ-state is:\n{GHZ_state}') + + :: + + The GHZ-state is: + + --------------------------------------------------- + Backend: state_vector + System dimension: [2, 2] + System sequence: [0, 1] + [0.71+0.j 0. +0.j 0. +0.j 0.71+0.j] + --------------------------------------------------- """ dim = 2 ** num_qubits data = torch.zeros(dim) @@ -231,6 +361,24 @@ def completely_mixed_computational(num_qubits: int) -> State: Returns: The generated quantum state. + + .. code-block:: python + + num_qubits = 1 + state =completely_mixed_computational(num_qubits) + print(f'The density matrix of the completely mixed state is:\n{state}') + + :: + + The density matrix of the completely mixed state is: + + --------------------------------------------------- + Backend: density_matrix + System dimension: [2] + System sequence: [0] + [[0.5+0.j 0. +0.j] + [0. +0.j 0.5+0.j]] + --------------------------------------------------- """ data = torch.eye(2 ** num_qubits) / (2 ** num_qubits) return to_state(data) @@ -254,6 +402,27 @@ def r_state(prob: float) -> State: Returns: The generated quantum state. + + .. code-block:: python + + prob = 0.5 + R_state =r_state(prob) + print(f'The R-state is:\n{R_state}') + + :: + + The R-state is: + + --------------------------------------------------- + Backend: density_matrix + System dimension: [2, 2] + System sequence: [0, 1] + [[0. +0.j 0. +0.j 0. +0.j 0. +0.j] + [0. +0.j 0.25+0.j 0.25+0.j 0. +0.j] + [0. +0.j 0.25+0.j 0.25+0.j 0. +0.j] + [0. +0.j 0. +0.j 0. +0.j 0.5 +0.j]] + --------------------------------------------------- + """ assert 0 <= prob <= 1, "Probability must be in [0, 1]" @@ -287,6 +456,27 @@ def s_state(prob: float) -> State: Returns: The generated quantum state. + + .. code-block:: python + + prob = 0.5 + S_state =s_state(prob) + print(f'The S-state is:\n{S_state}') + + :: + + The S-state is: + + --------------------------------------------------- + Backend: density_matrix + System dimension: [2, 2] + System sequence: [0, 1] + [[0.75+0.j 0. +0.j 0. +0.j 0.25+0.j] + [0. +0.j 0. +0.j 0. +0.j 0. +0.j] + [0. +0.j 0. +0.j 0. +0.j 0. +0.j] + [0.25+0.j 0. +0.j 0. +0.j 0.25+0.j]] + --------------------------------------------------- + """ assert 0 <= prob <= 1, "Probability must be in [0, 1]" @@ -317,6 +507,27 @@ def isotropic_state(num_qubits: int, prob: float) -> State: Returns: The generated quantum state. + + .. code-block:: python + + num_qubits=2 + prob = 0.5 + state =isotropic_state(num_qubits,prob) + print(f'The isotropic state is:\n{state}') + + :: + + The isotropic state is: + + --------------------------------------------------- + Backend: density_matrix + System dimension: [2, 2] + System sequence: [0, 1] + [[0.38+0.j 0. +0.j 0. +0.j 0.25+0.j] + [0. +0.j 0.12+0.j 0. +0.j 0. +0.j] + [0. +0.j 0. +0.j 0.12+0.j 0. +0.j] + [0.25+0.j 0. +0.j 0. +0.j 0.38+0.j]] + --------------------------------------------------- """ assert 0 <= prob <= 1, "Probability must be in [0, 1]" diff --git a/quairkit/loss/distance.py b/quairkit/loss/distance.py index b31f024..5924ed4 100644 --- a/quairkit/loss/distance.py +++ b/quairkit/loss/distance.py @@ -35,6 +35,11 @@ class TraceDistance(Operator): def __init__(self, target_state: State): super().__init__() self.target_state = target_state + + def __call__(self, state: State) -> torch.Tensor: + r"""Same as forward of Neural Network + """ + return self.forward(state) def forward(self, state: State) -> torch.Tensor: r"""Compute the trace distance between the input state and the target state. @@ -74,6 +79,11 @@ class StateFidelity(Operator): def __init__(self, target_state: State): super().__init__() self.target_state = target_state + + def __call__(self, state: State) -> torch.Tensor: + r"""Same as forward of Neural Network + """ + return self.forward(state) def forward(self, state: State) -> torch.Tensor: r"""Compute the state fidelity between the input state and the target state. diff --git a/quairkit/loss/measure.py b/quairkit/loss/measure.py index 7846cec..618dfe8 100644 --- a/quairkit/loss/measure.py +++ b/quairkit/loss/measure.py @@ -132,8 +132,8 @@ def __check_measure_op(self, state: State, system_idx: List[int]) -> bool: f"received shape {measure_op.shape}, expected {expected_shape}" ) if ((measure_batch_dim := list(measure_op.shape[:-3])) and - state.batch_dim and - (state.batch_dim != measure_batch_dim)): + state._batch_dim and + (state._batch_dim != measure_batch_dim)): raise ValueError( f"The batch dimensions of input state do not match with measurement operator: " f"expected None or {measure_batch_dim}, received {state.batch_dim}" @@ -187,6 +187,6 @@ def forward( for res in desired_result] prob_array = torch.index_select(prob_array, dim=-1, index=torch.tensor(desired_result)) - measured_state = measured_state.index_select(dim=-1, index=torch.tensor(desired_result)) + measured_state = measured_state.prob_select(torch.tensor(desired_result)) return (prob_array, measured_state) if keep_state else prob_array diff --git a/quairkit/operator/channel/base.py b/quairkit/operator/channel/base.py index 305a27e..de727f1 100644 --- a/quairkit/operator/channel/base.py +++ b/quairkit/operator/channel/base.py @@ -34,7 +34,7 @@ class Channel(Operator): r"""Basic class for quantum channels. Args: - type_repr: type of a representation. should be ``'choi'``, ``'kraus'``, ``'stinespring'``. + type_repr: type of a representation, should be ``'choi'``, ``'kraus'``, ``'stinespring'`` or ``'gate'``. representation: the representation of this channel. Defaults to ``None`` i.e. not specified. system_idx: indices of the system on which this channel acts on. Defaults to ``None``. i.e. list(range(number of acted systems)). @@ -148,7 +148,7 @@ def __gate_init(self, mat: torch.Tensor, if check_legality: identity = torch.eye(input_dim).to(device=mat.device).expand_as(mat) err = torch.norm(torch.abs(utils.linalg._dagger(mat) @ mat - identity)).item() - if err > min(1e-6 * input_dim, 0.01): + if err > min(1e-5 * input_dim, 0.01): warnings.warn( f"\nThe input gate matrix may not be a unitary: norm(U * U^d - I) = {err}.", UserWarning) diff --git a/quairkit/operator/channel/common.py b/quairkit/operator/channel/common.py index 17096ad..eec1010 100644 --- a/quairkit/operator/channel/common.py +++ b/quairkit/operator/channel/common.py @@ -346,4 +346,4 @@ def __init__( self, sigma: State, system_idx: Union[Iterable[int], int, str] = None ): - super().__init__('choi', replacement_choi(sigma), system_idx, acted_system_dim=sigma.dim) + super().__init__('choi', replacement_choi(sigma.density_matrix), system_idx, acted_system_dim=sigma.dim) diff --git a/quairkit/operator/gate/custom.py b/quairkit/operator/gate/custom.py index c5f4d27..56bc64d 100644 --- a/quairkit/operator/gate/custom.py +++ b/quairkit/operator/gate/custom.py @@ -19,12 +19,12 @@ import math from functools import partial -from typing import Callable, Iterable, List, Optional, Union +from typing import Callable, Dict, Iterable, List, Optional, Union import matplotlib import torch -from ...core import get_device, get_dtype +from ...core import get_device, get_dtype, utils from ...database.set import gell_mann from .base import Gate, ParamGate from .visual import _c_oracle_like_display, _oracle_like_display @@ -41,7 +41,7 @@ class Oracle(Gate): """ def __init__( self, oracle: torch.Tensor, system_idx: Union[Iterable[Iterable[int]], Iterable[int], int] = None, - acted_system_dim: Union[List[int], int] = 2, gate_info: dict = None, + acted_system_dim: Union[List[int], int] = 2, gate_info: Dict = None, ): super().__init__(oracle, system_idx, acted_system_dim, gate_info=gate_info) @@ -54,27 +54,36 @@ class ControlOracle(Gate): Args: oracle: Unitary oracle to be implemented. - system_idx: Indices of the systems on which the gates are applied. + system_idx: Indices of the systems on which the gates are applied. The first element in the list is the control system, + defaulting to :math:`|d-1\rangle \langle d-1|` as the control qubit, + while the remaining elements represent the oracle system. acted_system_dim: dimension of systems that this gate acts on. Can be a list of system dimensions or an int representing the dimension of all systems. Defaults to be qubit case. + proj: Projector matrix for the control qubit. Defaults to ``None``. """ - def __init__( - self, oracle: torch.Tensor, system_idx: Union[Iterable[Iterable[int]], Iterable[int], int] = None, - acted_system_dim: Union[List[int], int] = 2, gate_info: dict = None, + self, oracle: torch.Tensor, system_idx: List[Union[List[int], int]], + acted_system_dim: Union[List[int], int] = 2, proj: Union[torch.Tensor] = None, gate_info: Dict = None, ) -> None: - ctrl_dim = acted_system_dim if isinstance(acted_system_dim, int) else acted_system_dim[0] - - #TODO: support more control types - _zero, _other = torch.zeros([ctrl_dim, ctrl_dim]), torch.eye(ctrl_dim) - _zero[0, 0] += 1 - _other -= _zero - - _eye = torch.eye(oracle.shape[-1]) - if len(oracle.shape) > 2: - _zero, _other = _zero.unsqueeze(0), _other.unsqueeze(0) - _eye = _eye.expand_as(oracle) - oracle = torch.kron(_zero, _eye) + torch.kron(_other, oracle) + if isinstance(acted_system_dim, int): + ctrl_dim = acted_system_dim + elif isinstance(system_idx[0], int): + ctrl_dim = acted_system_dim[0] + else: + ctrl_dim = math.prod(acted_system_dim[:len(system_idx[0])]) + system_idx = system_idx[0] + system_idx[1:] + + if proj is None: + proj = torch.zeros([ctrl_dim, ctrl_dim]) + proj[-1, -1] += 1 + else: + assert proj.shape == (ctrl_dim, ctrl_dim), \ + f"Input project does not match the control dimension: expected {ctrl_dim}, received {proj.shape}" + assert utils.check._is_projector(proj), \ + "Input matrix is not a projector." + + _eye = torch.eye(oracle.shape[-1]).expand_as(oracle) + oracle = utils.linalg._kron(torch.eye(ctrl_dim) - proj, _eye) + utils.linalg._kron(proj, oracle) default_gate_info = { 'gatename': 'cO', @@ -108,7 +117,7 @@ def __init__( self, generator: Callable[[torch.Tensor], torch.Tensor], param: Union[torch.Tensor, float, List[float]] = None, num_acted_param: int = 1, param_sharing: bool = False, system_idx: Union[Iterable[Iterable[int]], Iterable[int], int] = None, - acted_system_dim: Union[List[int], int] = 2, gate_info: dict = None + acted_system_dim: Union[List[int], int] = 2, gate_info: Dict = None ): super().__init__(generator, param, num_acted_param, param_sharing, system_idx, acted_system_dim, gate_info) diff --git a/quairkit/operator/gate/multi_qubit_gate.py b/quairkit/operator/gate/multi_qubit_gate.py index 9aee463..0487dff 100644 --- a/quairkit/operator/gate/multi_qubit_gate.py +++ b/quairkit/operator/gate/multi_qubit_gate.py @@ -22,9 +22,9 @@ import matplotlib import torch -from ...database.matrix import (cnot, cp, crx, cry, crz, cswap, cu, cy, cz, ms, - rxx, ryy, rzz, swap, toffoli, universal2, - universal3) +from ...core.utils.matrix import (_cnot, _cp, _crx, _cry, _crz, _cswap, _cu, + _cy, _cz, _ms, _rxx, _ryy, _rzz, _swap, + _toffoli, _universal2, _universal3) from .base import Gate, ParamGate from .visual import (_cnot_display, _crx_like_display, _cswap_display, _cx_like_display, _oracle_like_display, _rxx_like_display, @@ -55,7 +55,7 @@ class CNOT(Gate): """ - __matrix = cnot(torch.complex128) + __matrix = _cnot(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -145,7 +145,7 @@ class CY(Gate): """ - __matrix = cy(torch.complex128) + __matrix = _cy(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -189,7 +189,7 @@ class CZ(Gate): """ - __matrix = cz(torch.complex128) + __matrix = _cz(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -232,7 +232,7 @@ class SWAP(Gate): """ - __matrix = swap(torch.complex128) + __matrix = _swap(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -288,7 +288,7 @@ def __init__( } super().__init__( - cp, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _cp, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _crx_like_display(self, ax, x) @@ -333,7 +333,7 @@ def __init__( } super().__init__( - crx, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _crx, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _crx_like_display(self, ax, x) @@ -378,7 +378,7 @@ def __init__( } super().__init__( - cry, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _cry, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _crx_like_display(self, ax, x, ) @@ -423,7 +423,7 @@ def __init__( } super().__init__( - crz, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _crz, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _crx_like_display(self, ax, x) @@ -467,7 +467,7 @@ def __init__( 'plot_width': 1.65, } super().__init__( - cu, param, 4, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _cu, param, 4, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _crx_like_display(self, ax, x) @@ -510,7 +510,7 @@ def __init__( 'plot_width': 1.0, } super().__init__( - rxx, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _rxx, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _rxx_like_display(self, ax, x) @@ -554,7 +554,7 @@ def __init__( } super().__init__( - ryy, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _ryy, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _rxx_like_display(self, ax, x) @@ -597,7 +597,7 @@ def __init__( 'plot_width': 1.0, } super().__init__( - rzz, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _rzz, param, 1, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _rxx_like_display(self, ax, x) @@ -625,7 +625,7 @@ class MS(Gate): """ - __matrix = ms(torch.complex128) + __matrix = _ms(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None @@ -671,7 +671,7 @@ class CSWAP(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first three qubits. """ - __matrix = cswap(torch.complex128) + __matrix = _cswap(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None @@ -716,7 +716,7 @@ class CCX(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first three qubits. """ - __matrix = toffoli(torch.complex128) + __matrix = _toffoli(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None @@ -764,7 +764,7 @@ def __init__( 'plot_width': 0.8, } super().__init__( - universal2, param, 15, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) + _universal2, param, 15, param_sharing, qubits_idx, [2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _oracle_like_display(self, ax, x) @@ -793,7 +793,7 @@ def __init__( 'plot_width': 0.8, } super().__init__( - universal3, param, 81, param_sharing, qubits_idx, [2, 2, 2], check_legality=False, gate_info=gate_info) + _universal3, param, 81, param_sharing, qubits_idx, [2, 2, 2], check_legality=False, gate_info=gate_info) def display_in_circuit(self, ax: matplotlib.axes.Axes, x: float, ) -> float: return _oracle_like_display(self, ax, x) diff --git a/quairkit/operator/gate/single_qubit_gate.py b/quairkit/operator/gate/single_qubit_gate.py index 8a87a8e..1cc5129 100644 --- a/quairkit/operator/gate/single_qubit_gate.py +++ b/quairkit/operator/gate/single_qubit_gate.py @@ -21,7 +21,8 @@ import torch -from ...database.matrix import h, p, rx, ry, rz, s, sdg, t, tdg, u3, x, y, z +from ...core.utils.matrix import (_h, _p, _rx, _ry, _rz, _s, _sdg, _t, _tdg, + _u3, _x, _y, _z) from .base import Gate, ParamGate @@ -42,7 +43,7 @@ class H(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first qubit. """ - __matrix = h(torch.complex128) + __matrix = _h(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None @@ -77,7 +78,7 @@ class S(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first qubit. """ - __matrix = s(torch.complex128) + __matrix = _s(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -112,7 +113,7 @@ class Sdg(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first qubit. """ - __matrix = sdg(torch.complex128) + __matrix = _sdg(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -147,7 +148,7 @@ class T(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first qubit. """ - __matrix = t(torch.complex128) + __matrix = _t(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -182,7 +183,7 @@ class Tdg(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first qubit. """ - __matrix = tdg(torch.complex128) + __matrix = _tdg(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -217,7 +218,7 @@ class X(Gate): """ - __matrix = x(torch.complex128) + __matrix = _x(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -251,7 +252,7 @@ class Y(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first qubit. """ - __matrix = y(torch.complex128) + __matrix = _y(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -285,7 +286,7 @@ class Z(Gate): qubits_idx: Indices of the qubits on which the gates are applied. Defaults to the first qubit. """ - __matrix = z(torch.complex128) + __matrix = _z(torch.complex128) def __init__( self, qubits_idx: Optional[Union[Iterable, int, str]] = None, @@ -334,7 +335,7 @@ def __init__( } super().__init__( - p, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) + _p, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) class RX(ParamGate): @@ -368,7 +369,7 @@ def __init__( } super().__init__( - rx, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) + _rx, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) class RY(ParamGate): @@ -401,7 +402,7 @@ def __init__( 'plot_width': 0.9, } super().__init__( - ry, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) + _ry, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) class RZ(ParamGate): @@ -435,7 +436,7 @@ def __init__( } super().__init__( - rz, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) + _rz, param, 1, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) class U3(ParamGate): @@ -472,4 +473,4 @@ def __init__( } super().__init__( - u3, param, 3, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) + _u3, param, 3, param_sharing, qubits_idx, check_legality=False, gate_info=gate_info) diff --git a/quairkit/operator/special.py b/quairkit/operator/special.py index f5cf239..3361f5b 100644 --- a/quairkit/operator/special.py +++ b/quairkit/operator/special.py @@ -17,13 +17,14 @@ The source file of the class for the special quantum operator. """ -from typing import Iterable, Optional, Union +from typing import Iterable, List, Optional, Union import numpy as np import torch from ..core import Operator, State from ..core.intrinsic import _alias, _digit_to_int, _int_to_digit +from . import Channel, Gate class ResetState(Operator): @@ -46,9 +47,10 @@ class Collapse(Operator): Args: system_idx: list of systems to be collapsed. - desired_result: The desired result you want to collapse. Defaults to ``None`` meaning randomly choose one. + desired_result: The desired result you want to collapse. Defaults to ``None`` meaning preserving all results, + and activate probabilistic computation. if_print: whether print the information about the collapsed state. Defaults to ``False``. - measure_basis: The basis of the measurement. The quantum state will collapse to the corresponding eigenstate. + measure_basis: The basis of the measurement. Defaults to the computational basis. Raises: NotImplementedError: If the basis of measurement is not z. Other bases will be implemented in future. @@ -73,6 +75,11 @@ def __init__(self, system_idx: Union[int, Iterable[int]], self.measure_basis = measure_basis + def __call__(self, state: State) -> State: + r"""Same as forward of Neural Network + """ + return self.forward(state) + def forward(self, state: State) -> State: r"""Compute the collapse of the input state. @@ -83,17 +90,14 @@ def forward(self, state: State) -> State: The collapsed quantum state. """ system_dim = [state.system_dim[idx] for idx in self.system_idx] - dim = int(np.prod(system_dim)) + desired_result = self.desired_result prob_array, measured_state = state.measure(self.measure_basis, self.system_idx, keep_state=True) - desired_result = self.desired_result if desired_result is None: - assert measured_state.batch_dim is None, \ - f"batch computation is not supported for random collapse: received {desired_result}" - desired_result = np.random.choice(range(dim), p=prob_array) - digits_str = _int_to_digit(desired_result, base=system_dim) - elif isinstance(desired_result, str): + return measured_state + + if isinstance(desired_result, str): digits_str = desired_result desired_result = _digit_to_int(desired_result, system_dim) else: @@ -111,4 +115,100 @@ def forward(self, state: State) -> State: prob = prob_collapse.mean().item() print(f"systems {self.system_idx} collapse to the state {state_str} with (average) probability {prob}") - return measured_state.index_select(dim=-1, index=desired_result) + return measured_state.prob_select(desired_result) + + +class OneWayLOCC(Operator): + r"""A one-way LOCC protocol, where quantum measurement is modelled by a PVM and all channels are unitary channels. + + Args: + list_unitary: a batched tensor that represents all unitaries. + system_idx: Indices of the systems on which the protocol is applied. The first element in the list + indexes systems to be measured. + acted_system_dim: dimension of systems that unitary channels act on. Can be a list of system dimensions + or an int representing the dimension of all systems. Defaults to be qubit case. + measure_basis: The basis of the measurement. Defaults to the computational basis. + + """ + @_alias({'system_idx': 'qubits_idx'}) + def __init__( + self, list_unitary: torch.Tensor, system_idx: Union[Iterable[int], int] = None, + acted_system_dim: Union[List[int], int] = 2, measure_basis: Optional[torch.Tensor] = None + ): + super().__init__() + measure_idx, act_idx = system_idx[0], system_idx[1:] + acted_system_dim = acted_system_dim if isinstance(acted_system_dim, int) else acted_system_dim[len(measure_idx):] + + self.measure = Collapse(measure_idx, measure_basis=measure_basis) + self.list_gate = Gate(list_unitary, act_idx, acted_system_dim) + + def __call__(self, state: State) -> State: + r"""Same as forward of Neural Network + """ + return self.forward(state) + + def forward(self, state: State) -> State: + r"""Compute the input state passing through the LOCC protocol. + + Args: + state: The input state. + + Returns: + The collapsed quantum state. + + """ + matrix, sys_idx = self.list_gate.matrix, self.list_gate.system_idx[0] + + measured_state = self.measure(state) + measured_state._evolve(matrix, sys_idx, on_batch=False) + return measured_state + + +class QuasiOperation(Operator): + r"""A quantum protocol containing quasi-operations. + + Args: + list_channels: a batched tensor that represents all unitaries. + quasi_prob: the quasi-probability distribution for this quasi-operation. + system_idx: indices of the systems on which the protocol is applied. + type_repr: one of ``'choi'``, ``'kraus'``, ``'stinespring'`` or ``'gate'``. Defaults to ``'gate'``. + acted_system_dim: dimension of systems that these channels act on. Can be a list of system dimensions + or an int representing the dimension of all systems. Defaults to be qubit case. + """ + def __init__( + self, list_channels: torch.Tensor, quasi_prob: torch.Tensor, + system_idx: Union[Iterable[int], int] = None, + type_repr: str = 'gate', acted_system_dim: Union[List[int], int] = 2 + ): + super().__init__() + + # TODO: support other types of representations + if type_repr != 'gate': + raise NotImplementedError("Only 'gate' type is supported for now.") + + assert np.abs((s := quasi_prob.sum().item()) - 1) < 1e-4, \ + f"The quasi-probability distribution should sum to 1: received sum {s}" + + if type_repr == 'gate': + self.channel = Gate(list_channels, system_idx, acted_system_dim) + else: + self.channel = Channel(type_repr, list_channels, system_idx, acted_system_dim) + self.prob = quasi_prob.view([-1]) + + def forward(self, state: State) -> State: + r"""Compute the input state passing through the quasi-operation. + + Args: + state: The input state. + + Returns: + The collapsed quantum state. + """ + state, prob = state.clone(), self.prob + + if state._prob: + last_prob = state._prob[-1] + prob = prob.view([1] * last_prob.ndim() + [-1]) + state._prob.append(self.prob) + state._evolve(self.channel.matrix, self.channel.system_idx[0], on_batch=False) + return state diff --git a/quairkit/qinfo/check.py b/quairkit/qinfo/check.py index daab338..6f83760 100644 --- a/quairkit/qinfo/check.py +++ b/quairkit/qinfo/check.py @@ -22,8 +22,8 @@ from quairkit.core import utils from quairkit.core.intrinsic import _is_sample_linear -from ..core import State, utils -from ..core.intrinsic import _type_transform +from ..core import utils +from ..core.intrinsic import _ArrayLike, _StateLike, _type_transform __all__ = [ "is_choi", @@ -40,7 +40,7 @@ ] -def is_choi(op: Union[np.ndarray, torch.Tensor]) -> Union[bool, List[bool]]: +def is_choi(op: _ArrayLike) -> Union[bool, List[bool]]: r"""Check if the input op is a Choi operator of a physical operation. Support batch input. @@ -63,7 +63,7 @@ def is_choi(op: Union[np.ndarray, torch.Tensor]) -> Union[bool, List[bool]]: def is_density_matrix( - rho: Union[np.ndarray, torch.Tensor], eps: Optional[float] = 1e-6 + rho: _ArrayLike, eps: float = 1e-6 ) -> Union[bool, List[bool]]: r"""Verify whether ``rho`` is a legal quantum density matrix Support batch input @@ -85,7 +85,7 @@ def is_density_matrix( def is_hermitian( - mat: Union[np.ndarray, torch.Tensor], eps: Optional[float] = 1e-6 + mat: _ArrayLike, eps: float = 1e-6 ) -> Union[bool, List[bool]]: r"""Verify whether ``mat`` is Hermitian. Support batch input. @@ -135,7 +135,7 @@ def is_linear( def is_positive( - mat: Union[np.ndarray, torch.Tensor], eps: Optional[float] = 1e-6 + mat: _ArrayLike, eps: float = 1e-6 ) -> Union[bool, List[bool]]: r"""Verify whether ``mat`` is a positive semi-definite matrix. Support batch input. @@ -159,7 +159,7 @@ def is_positive( def is_povm( set_op: Union[torch.Tensor, np.ndarray], - eps: Optional[float] = 1e-6 + eps: float = 1e-6 ) -> Union[bool, List[bool]]: r"""Check if a set of operators forms a positive operator-valued measure (POVM). @@ -176,7 +176,7 @@ def is_povm( def is_projector( - mat: Union[np.ndarray, torch.Tensor], eps: Optional[float] = 1e-6 + mat: _ArrayLike, eps: float = 1e-6 ) -> Union[bool, List[bool]]: r"""Verify whether ``mat`` is a projector. Support batch input. @@ -198,7 +198,7 @@ def is_projector( return utils.check._is_projector(mat, eps).tolist() -def is_ppt(density_op: Union[np.ndarray, torch.Tensor, State]) -> Union[bool, List[bool]]: +def is_ppt(density_op: _StateLike) -> Union[bool, List[bool]]: r"""Check if the input quantum state is PPT. Support batch input. @@ -215,7 +215,7 @@ def is_ppt(density_op: Union[np.ndarray, torch.Tensor, State]) -> Union[bool, Li def is_pvm( set_op: Union[torch.Tensor, np.ndarray], - eps: Optional[float] = 1e-6 + eps: float = 1e-6 ) -> Union[bool, List[bool]]: r"""Check if a set of operators forms a projection-valued measure (PVM). @@ -232,7 +232,7 @@ def is_pvm( def is_state_vector( - vec: Union[np.ndarray, torch.Tensor], eps: Optional[float] = 1e-6 + vec: _ArrayLike, eps: float = 1e-6 ) -> Union[bool, List[bool]]: r"""Verify whether ``vec`` is a legal quantum state vector. Support batch input. @@ -256,7 +256,7 @@ def is_state_vector( def is_unitary( - mat: Union[np.ndarray, torch.Tensor], eps: Optional[float] = 1e-4 + mat: _ArrayLike, eps: Optional[float] = 1e-4 ) -> Union[bool, List[bool]]: r"""Verify whether ``mat`` is a unitary. Support batch input. diff --git a/quairkit/qinfo/linalg.py b/quairkit/qinfo/linalg.py index 228da1e..e70f13f 100644 --- a/quairkit/qinfo/linalg.py +++ b/quairkit/qinfo/linalg.py @@ -22,8 +22,9 @@ from quairkit.core import utils -from ..core import State, get_dtype, tensor_state, to_state, utils -from ..core.intrinsic import (_format_system_dim, _is_sample_linear, +from ..core import get_dtype, tensor_state, to_state, utils +from ..core.intrinsic import (_ArrayLike, _format_system_dim, + _is_sample_linear, _SingleParamLike, _StateLike, _type_fetch, _type_transform) from ..database import pauli_basis @@ -36,7 +37,9 @@ "gradient", "hessian", "herm_transform", + "kron_power", "logm", + "nkron", "NKron", "p_norm", "partial_trace", @@ -52,7 +55,7 @@ ] -def abs_norm(mat: Union[np.ndarray, torch.Tensor, State]) -> float: +def abs_norm(mat: _StateLike) -> float: r"""tool for calculation of matrix norm Args: @@ -68,8 +71,8 @@ def abs_norm(mat: Union[np.ndarray, torch.Tensor, State]) -> float: def block_enc_herm( - mat: Union[np.ndarray, torch.Tensor], num_block_qubits: int = 1 -) -> Union[np.ndarray, torch.Tensor]: + mat: _ArrayLike, num_block_qubits: int = 1 +) -> _ArrayLike: r"""generate a (qubitized) block encoding of hermitian ``mat`` Args: @@ -92,12 +95,10 @@ def block_enc_herm( def create_matrix( - linear_map: Callable[ - [Union[torch.Tensor, np.ndarray]], Union[torch.Tensor, np.ndarray] - ], + linear_map: Callable[[_ArrayLike], _ArrayLike], input_dim: int, - input_dtype: torch.dtype = None, -) -> Union[torch.Tensor, np.ndarray]: + input_dtype: Optional[torch.dtype] = None, +) -> _ArrayLike: r"""Create a matrix representation of a linear map without needing to specify the output dimension. This function constructs a matrix representation for a given linear map and input dimension. @@ -128,7 +129,7 @@ def create_matrix( ) -def dagger(mat: Union[np.ndarray, torch.Tensor]) -> Union[np.ndarray, torch.Tensor]: +def dagger(mat: _ArrayLike) -> _ArrayLike: r"""tool for calculation of matrix dagger Args: @@ -147,8 +148,8 @@ def dagger(mat: Union[np.ndarray, torch.Tensor]) -> Union[np.ndarray, torch.Tens def direct_sum( - A: Union[np.ndarray, torch.Tensor], B: Union[np.ndarray, torch.Tensor] -) -> Union[np.ndarray, torch.Tensor]: + A: _ArrayLike, B: _ArrayLike +) -> _ArrayLike: r"""calculate the direct sum of A and B Args: @@ -169,7 +170,7 @@ def direct_sum( return _type_transform(mat, type_A) if type_A == type_B else mat -def gradient(loss_function: Callable[[torch.Tensor], torch.Tensor], var: Union[torch.Tensor, np.ndarray], n: int) -> Union[torch.Tensor, np.ndarray]: +def gradient(loss_function: Callable[[torch.Tensor], torch.Tensor], var: _ArrayLike, n: int) -> _ArrayLike: r""" Computes the gradient of a given loss function with respect to its input variable. @@ -194,7 +195,7 @@ def gradient(loss_function: Callable[[torch.Tensor], torch.Tensor], var: Union[t return _type_transform(utils.linalg._gradient(loss_function, var, n), type_str) -def hessian(loss_function: Callable[[torch.Tensor], torch.Tensor], var: Union[torch.Tensor, np.ndarray]) -> Union[torch.Tensor, np.ndarray]: +def hessian(loss_function: Callable[[torch.Tensor], torch.Tensor], var: _ArrayLike) -> _ArrayLike: r""" Computes the Hessian matrix of a given loss function with respect to its input variables. @@ -219,9 +220,9 @@ def hessian(loss_function: Callable[[torch.Tensor], torch.Tensor], var: Union[to def herm_transform( fcn: Callable[[float], float], - mat: Union[torch.Tensor, np.ndarray, State], + mat: _StateLike, ignore_zero: Optional[bool] = False, -) -> torch.Tensor: +) -> _ArrayLike: r"""function transformation for Hermitian matrix Args: @@ -249,7 +250,22 @@ def herm_transform( return mat.detach().numpy() if type_str == "numpy" else mat -def logm(mat: Union[np.ndarray, torch.Tensor, State]) -> Union[np.ndarray, torch.Tensor]: +def kron_power(matrix: _StateLike, n: int) -> _ArrayLike: + r"""Calculate Kronecker product of identical matirces + + Args: + matrix: the matrix to be powered + n: the number of identical matrices + + Returns: + Kronecker product of n identical matrices + """ + if n == 0: + return np.array([[1.0]]) if isinstance(matrix, np.ndarray) else torch.tensor([[1.0]]) + return nkron(matrix, *[matrix for _ in range(n - 1)]) + + +def logm(mat: _StateLike) -> _ArrayLike: r"""Calculate log of a matrix Args: @@ -269,17 +285,12 @@ def logm(mat: Union[np.ndarray, torch.Tensor, State]) -> Union[np.ndarray, torch return _type_transform(utils.linalg._logm(mat), type_str) -def NKron( - matrix_A: Union[torch.Tensor, np.ndarray], - matrix_B: Union[torch.Tensor, np.ndarray], - *args: Union[torch.Tensor, np.ndarray], -) -> Union[torch.Tensor, np.ndarray]: - r"""calculate Kronecker product of at least two density matrices +def nkron(matrix_1st: _StateLike, *args: _StateLike) -> _StateLike: + r"""calculate Kronecker product of matirces Args: - matrix_A: density matrix - matrix_B: density matrix - args: other density matrices + matrix_1: the first matrix + args: other matrices Returns: Kronecker product of matrices @@ -296,27 +307,30 @@ def NKron( Note: ``result`` from above code block should be A \otimes B \otimes C """ - type_A, type_B = _type_fetch(matrix_A), _type_fetch(matrix_B) - type_list = [type_A, type_B] + [_type_fetch(arg) for arg in args] + if not args: + return matrix_1st + + type_1st = _type_fetch(matrix_1st) + type_list = [type_1st] + [_type_fetch(arg) for arg in args] if all(type_arg == "state" for type_arg in type_list): - return tensor_state(matrix_A, matrix_B, *args) + return tensor_state(matrix_1st, *args) if all(type_arg == "numpy" for type_arg in type_list): return_type = "numpy" else: return_type = "tensor" - matrix_A = _type_transform(matrix_A, "tensor") - matrix_B = _type_transform(matrix_B, "tensor") + matrix_1st = _type_transform(matrix_1st, "tensor") args = [_type_transform(mat, "tensor") for mat in args] - result = utils.linalg._nkron(matrix_A, matrix_B, *args) + result = utils.linalg._nkron(matrix_1st, *args) return _type_transform(result, return_type) +NKron = nkron + -def p_norm(mat: Union[np.ndarray, torch.Tensor, State], - p: Union[np.ndarray, torch.Tensor, float]) -> Union[np.ndarray, torch.Tensor]: +def p_norm(mat: _StateLike, p: _SingleParamLike) -> _ArrayLike: r"""tool for calculation of Schatten p-norm Args: @@ -337,9 +351,9 @@ def p_norm(mat: Union[np.ndarray, torch.Tensor, State], def partial_trace( - state: Union[np.ndarray, torch.Tensor, State], trace_idx: Union[List[int], int], + state: _StateLike, trace_idx: Union[List[int], int], system_dim: Union[List[int], int] = 2 -) -> Union[np.ndarray, torch.Tensor, State]: +) -> _StateLike: r"""Calculate the partial trace of the quantum state Args: @@ -368,8 +382,8 @@ def partial_trace( def partial_trace_discontiguous( - state: Union[np.ndarray, torch.Tensor, State], preserve_qubits: List[int] = None -) -> Union[np.ndarray, torch.Tensor, State]: + state: _StateLike, preserve_qubits: List[int] = None +) -> _StateLike: r"""Calculate the partial trace of the quantum state with arbitrarily selected subsystem Args: @@ -396,9 +410,9 @@ def partial_trace_discontiguous( def partial_transpose( - state: Union[np.ndarray, torch.Tensor, State], transpose_idx: Union[List[int], int], + state: _StateLike, transpose_idx: Union[List[int], int], system_dim: Union[List[int], int] = 2 -) -> Union[np.ndarray, torch.Tensor]: +) -> _ArrayLike: r"""Calculate the partial transpose :math:`\rho^{T_A}` of the input quantum state. Args: @@ -427,9 +441,7 @@ def partial_transpose( return state.detach().numpy() if type_str == "numpy" else state -def pauli_decomposition( - mat: Union[np.ndarray, torch.Tensor] -) -> Union[np.ndarray, torch.Tensor]: +def pauli_decomposition(mat: _ArrayLike) -> _ArrayLike: r"""Decompose the matrix by the Pauli basis. Args: @@ -454,10 +466,8 @@ def pauli_decomposition( def permute_systems( - state: Union[np.ndarray, torch.Tensor, State], - perm_list: List[int], - system_dim: Union[List[int], int] = 2, -) -> Union[np.ndarray, torch.Tensor, State]: + state: _StateLike, perm_list: List[int], system_dim: Union[List[int], int] = 2, +) -> _StateLike: r"""Permute quantum system based on a permute list Args: @@ -479,7 +489,7 @@ def permute_systems( return _type_transform(perm_mat, type_str) -def prob_sample(distribution: torch.Tensor, shots: int = 1024, +def prob_sample(distribution: _ArrayLike, shots: int = 1024, binary: bool = True, proportional: bool = False) -> Dict[str, Union[int, float]]: r"""Sample from a probability distribution. @@ -507,7 +517,7 @@ def prob_sample(distribution: torch.Tensor, shots: int = 1024, def schmidt_decompose( - psi: Union[np.ndarray, torch.Tensor, State], sys_A: List[int] = None + psi: _StateLike, sys_A: List[int] = None ) -> Union[ Tuple[torch.Tensor, torch.Tensor, torch.Tensor], Tuple[np.ndarray, np.ndarray, np.ndarray], @@ -545,7 +555,7 @@ def schmidt_decompose( ) -def sqrtm(mat: Union[np.ndarray, torch.Tensor, State]) -> Union[np.ndarray, torch.Tensor]: +def sqrtm(mat: _StateLike) -> _ArrayLike: r"""Calculate square root of a matrix Args: @@ -563,7 +573,7 @@ def sqrtm(mat: Union[np.ndarray, torch.Tensor, State]) -> Union[np.ndarray, torc return _type_transform(utils.linalg._sqrtm(mat), type_str) -def trace(mat: Union[np.ndarray, torch.Tensor, State], axis1: Optional[int]=-2, axis2: Optional[int]=-1) -> Union[np.ndarray, torch.Tensor]: +def trace(mat: _StateLike, axis1: int = -2, axis2: int = -1) -> _ArrayLike: r"""Return the sum along diagonals of the tensor. If :math:`mat` is 2-D tensor, the sum along its diagonal is returned. @@ -602,7 +612,7 @@ def trace(mat: Union[np.ndarray, torch.Tensor, State], axis1: Optional[int]=-2, return _type_transform(trace_mat, type_str) -def trace_norm(mat: Union[np.ndarray, torch.Tensor, State]) -> Union[np.ndarray, torch.Tensor]: +def trace_norm(mat: _StateLike) -> _ArrayLike: r"""tool for calculation of trace norm Args: diff --git a/quairkit/qinfo/qinfo.py b/quairkit/qinfo/qinfo.py index de123ad..db0ff09 100644 --- a/quairkit/qinfo/qinfo.py +++ b/quairkit/qinfo/qinfo.py @@ -20,8 +20,9 @@ import numpy as np import torch -from ..core import State, utils -from ..core.intrinsic import _is_sample_linear, _type_fetch, _type_transform +from ..core import utils +from ..core.intrinsic import (_ArrayLike, _is_sample_linear, _SingleParamLike, + _StateLike, _type_fetch, _type_transform) from ..database import pauli_basis, phase_space_point from ..operator import Channel @@ -32,8 +33,11 @@ "decomp_ctrl_1qubit", "diamond_norm", "gate_fidelity", + "general_state_fidelity", + "link", "logarithmic_negativity", "mana", + "mutual_information", "negativity", "pauli_str_convertor", "purity", @@ -47,11 +51,11 @@ def channel_repr_convert( - representation: Union[torch.Tensor, np.ndarray, List[torch.Tensor], List[np.ndarray]], + representation: Union[_ArrayLike, List[torch.Tensor], List[np.ndarray]], source: str, target: str, tol: float = 1e-6, -) -> Union[torch.Tensor, np.ndarray]: +) -> _ArrayLike: r"""convert the given representation of a channel to the target implementation Args: @@ -119,12 +123,10 @@ def channel_repr_convert( def create_choi_repr( - linear_map: Callable[ - [Union[torch.Tensor, np.ndarray]], Union[torch.Tensor, np.ndarray] - ], + linear_map: Callable[[_ArrayLike], _ArrayLike], input_dim: int, - input_dtype: torch.dtype = None, -) -> torch.Tensor: + input_dtype: Optional[torch.dtype] = None, +) -> _ArrayLike: r"""Create the Choi representation of a linear map with input checks. This function verifies if the map is linear and if the output is a square matrix. @@ -152,7 +154,7 @@ def create_choi_repr( # Check if the output is a square matrix sample = linear_map(torch.randn(input_dim, input_dim, dtype=input_dtype)) - if sample.shape[0] != sample.shape[1]: + if sample.shape[-2] != sample.shape[-1]: warnings.warn( f"The output of this linear map is not a square matrix: received {sample.shape}", RuntimeWarning, @@ -162,13 +164,11 @@ def create_choi_repr( return _type_transform( utils.qinfo._create_choi_repr( linear_map=linear_map, input_dim=input_dim, input_dtype=input_dtype - ), - type_str, - ) + ), type_str) def decomp_1qubit( - unitary: Union[np.ndarray, torch.Tensor], return_global: bool = False + unitary: _ArrayLike, return_global: bool = False ) -> Union[Tuple[np.ndarray, ...], Tuple[torch.Tensor, ...]]: r"""Decompose a single-qubit unitary operator into Z-Y-Z rotation angles. @@ -198,7 +198,7 @@ def decomp_1qubit( def decomp_ctrl_1qubit( - unitary: Union[np.ndarray, torch.Tensor] + unitary: _ArrayLike ) -> Union[Tuple[np.ndarray, ...], Tuple[torch.Tensor, ...]]: r"""Decompose a controlled single-qubit unitary operator into its components. @@ -271,8 +271,8 @@ def diamond_norm( def gate_fidelity( - U: Union[np.ndarray, torch.Tensor], V: Union[np.ndarray, torch.Tensor] -) -> Union[np.ndarray, torch.Tensor]: + U: _ArrayLike, V: _ArrayLike +) -> _ArrayLike: r"""calculate the fidelity between gates .. math:: @@ -300,11 +300,130 @@ def gate_fidelity( if type_u == "numpy" and type_v == "numpy" else fidelity ) + + +def general_state_fidelity(rho: _StateLike, sigma: _StateLike) -> _ArrayLike: + r"""Calculate the fidelity measure of two general states. + + .. math:: + + F_*(\rho, \sigma) = F(\rho, \sigma) + \sqrt{(1 - \text{tr}[\rho])(1 - \text{tr}[\sigma])} + + where :math:`F(\rho, \sigma)` is the state fidelity without square. + + Args: + rho: a subnormalized quantum state. + sigma: a subnormalized quantum state. + + Returns: + The general state fidelity of the input subnormalized states. + + """ + type_rho, type_sigma = _type_fetch(rho), _type_fetch(sigma) + rho = _type_transform(rho, "state").density_matrix + sigma = _type_transform(sigma, "state").density_matrix + + fidelity = utils.qinfo._general_state_fidelity(rho, sigma) + + return ( + fidelity.detach().numpy() + if type_rho == "numpy" and type_sigma == "numpy" + else fidelity + ) + + +def link( + JE: Tuple[_ArrayLike, str, Union[List[int], int], Union[List[int], int]], + JF: Tuple[_ArrayLike, str, Union[List[int], int], Union[List[int], int]], +) -> Tuple[_ArrayLike, str, List[int], List[int]]: + r"""Calculate the link product of two Choi matrices of quantum channels. + + Args: + JE: Tuple containing the Choi representation of channel E, its label, input dimensions, and output dimensions. + JF: Tuple containing the Choi representation of channel F, its label, input dimensions, and output dimensions. + + Returns: + The resulting Choi matrix after the link product, its label, and input/output dimensions. + + Note: + The identification convention for input label is exemplified by "AB->CD", where the same letter in different cases (uppercase vs lowercase) is recognized as the same system, and an apostrophe indicates a different system. When input and output dimensions are specified as an int, it implies that each system has the same dimensionality. + + """ + JE_matrix_type = _type_fetch(JE[0]) + JE_matrix = _type_transform(JE[0], "tensor") + + JF_matrix_type = _type_fetch(JF[0]) + JF_matrix = _type_transform(JF[0], "tensor") + + # Allow lowercase and recognize characters with apostrophes + def map_to_lower_if_apostrophe(s: str) -> str: + result = "" + i = 0 + while i < len(s): + if i + 1 < len(s) and s[i + 1] == "'": + result += s[i].lower() # Convert to lowercase if followed by an apostrophe + i += 1 # Skip the apostrophe + else: + result += s[i].upper() # Convert to uppercase otherwise + i += 1 + return result + + JE_entry_exit = map_to_lower_if_apostrophe(JE[1]) + JF_entry_exit = map_to_lower_if_apostrophe(JF[1]) + + JE_entry, JE_exit = JE_entry_exit.split("->") + JF_entry, JF_exit = JF_entry_exit.split("->") + + # Check if the input and output dimensions are integers or lists + JE_dims = ( + [JE[2]] * len(JE_entry) if isinstance(JE[2], int) else JE[2], + [JE[3]] * len(JE_exit) if isinstance(JE[3], int) else JE[3], + ) + JF_dims = ( + [JF[2]] * len(JF_entry) if isinstance(JF[2], int) else JF[2], + [JF[3]] * len(JF_exit) if isinstance(JF[3], int) else JF[3], + ) + + # Check the shape of the input choi matrices + expected_JE_shape = (np.prod(JE_dims[0] + JE_dims[1]), np.prod(JE_dims[0] + JE_dims[1])) + expected_JF_shape = (np.prod(JF_dims[0] + JF_dims[1]), np.prod(JF_dims[0] + JF_dims[1])) + + assert ( + JE_matrix.shape == expected_JE_shape + ), f"JE_matrix shape mismatch: expected {expected_JE_shape}, got {JE_matrix.shape}" + assert ( + JF_matrix.shape == expected_JF_shape + ), f"JF_matrix shape mismatch: expected {expected_JF_shape}, got {JF_matrix.shape}" + + # Check if the overlapping subsystems have the same dimension + overlap_subsystem = set(JE_exit).intersection(set(JF_entry)) + for subsystem in overlap_subsystem: + JE_subsystem_index = JE_exit.index(subsystem) + JF_subsystem_index = JF_entry.index(subsystem) + + JE_subsystem_dim = JE[3][JE_subsystem_index] + JF_subsystem_dim = JF[2][JF_subsystem_index] + + assert ( + JE_subsystem_dim == JF_subsystem_dim + ), f"JE and JF overlap system '{subsystem}' dimension mismatch: JE has dimension {JE_subsystem_dim}, JF has dimension {JF_subsystem_dim}." + + # Update JE and JF tuples with processed labels and dimensions + JE = (JE_matrix, JE_entry_exit) + JE_dims + JF = (JF_matrix, JF_entry_exit) + JF_dims + + result = utils.qinfo._link(JE, JF) + + # Transform the result back to the original type + if JE_matrix_type == "numpy" and JF_matrix_type == "numpy": + result = (_type_transform(result[0], "numpy"),) + result[1:] + + return result def logarithmic_negativity( - density_op: Union[np.ndarray, torch.Tensor, State] -) -> Union[np.ndarray, torch.Tensor]: + density_op: _StateLike +) -> _ArrayLike: r"""Calculate the Logarithmic Negativity :math:`E_N = ||\rho^{T_A}||` of the input quantum state. Args: @@ -322,8 +441,8 @@ def logarithmic_negativity( return log_neg.detach().numpy() if type_str == "numpy" else log_neg -def mana(matrix: Union[np.ndarray, torch.Tensor, State], input_str: str, - out_dim: Optional[int]=None) -> Union[np.ndarray, torch.Tensor, State]: +def mana(matrix: _StateLike, input_str: str, + out_dim: Optional[int]=None) -> _StateLike: r"""Compute the mana of states or channels Args: @@ -353,9 +472,30 @@ def mana(matrix: Union[np.ndarray, torch.Tensor, State], input_str: str, raise ValueError("Invalid input. Please enter 'state' or 'channel'.") -def negativity( #Todo - density_op: Union[np.ndarray, torch.Tensor, State] -) -> Union[np.ndarray, torch.Tensor]: +def mutual_information(state: _StateLike, dim_A: int, dim_B: int) -> _ArrayLike: + r"""Compute the mutual information of a bipartite state. + + Args: + state: input bipartite quantum state with system AB. + dim_A: Dimension of system A. + dim_B: Dimension of system B. + + Returns: + The mutual information of the input quantum state + + """ + type_str = _type_fetch(state) + rho = _type_transform(state, "state").density_matrix + + assert rho.shape[0] == dim_A * dim_B, \ + f"The shape of the input quantum state is not compatible with the given dimensions: received {rho.shape}, expected ({dim_A * dim_B}, {dim_A * dim_B})" + + mi = utils.qinfo._mutual_information(rho, dim_A, dim_B) + + return mi.detach().numpy() if type_str == "numpy" else mi + + +def negativity(density_op: _StateLike) -> _ArrayLike: r"""Compute the Negativity :math:`N = ||\frac{\rho^{T_A}-1}{2}||` of the input quantum state. Args: @@ -393,9 +533,7 @@ def pauli_str_convertor(observable: List) -> List: return [[1, term] for term in observable] -def purity( - rho: Union[np.ndarray, torch.Tensor, State] -) -> Union[np.ndarray, torch.Tensor]: +def purity(rho: _StateLike) -> _ArrayLike: r"""Calculate the purity of a quantum state. .. math:: @@ -417,10 +555,10 @@ def purity( def relative_entropy( - rho: Union[np.ndarray, torch.Tensor, State], - sigma: Union[np.ndarray, torch.Tensor, State], + rho: _StateLike, + sigma: _StateLike, base: Optional[int] = 2, -) -> Union[np.ndarray, torch.Tensor]: +) -> _ArrayLike: r"""Calculate the relative entropy of two quantum states. .. math:: @@ -449,7 +587,7 @@ def relative_entropy( ) -def stab_nullity(unitary: Union[np.ndarray, torch.Tensor]) -> Union[np.ndarray, torch.Tensor]: +def stab_nullity(unitary: _ArrayLike) -> _ArrayLike: r"""Tool for calculation of unitary-stabilizer nullity. Args: @@ -498,7 +636,7 @@ def stab_nullity(unitary: Union[np.ndarray, torch.Tensor]) -> Union[np.ndarray, ) -def stab_renyi(density: Union[np.ndarray, torch.Tensor,State],alpha: Union[np.ndarray, torch.Tensor, float]) -> Union[np.ndarray, torch.Tensor]: +def stab_renyi(density: _StateLike, alpha: _SingleParamLike) -> _ArrayLike: r"""Tool for calculation of stabilizer renyi entropy. Args: @@ -553,11 +691,8 @@ def stab_renyi(density: Union[np.ndarray, torch.Tensor,State],alpha: Union[np.nd return renyi.detach().numpy() if type_str == "numpy" else renyi -def state_fidelity( - rho: Union[np.ndarray, torch.Tensor, State], - sigma: Union[np.ndarray, torch.Tensor, State], -) -> Union[np.ndarray, torch.Tensor]: - r"""Calculate the fidelity of two quantum states. +def state_fidelity(rho: _StateLike, sigma: _StateLike) -> _ArrayLike: + r"""Calculate the fidelity of two quantum states, no extra square is taken. .. math:: F(\rho, \sigma) = \text{tr}(\sqrt{\sqrt{\rho}\sigma\sqrt{\rho}}) @@ -568,6 +703,10 @@ def state_fidelity( Returns: The fidelity between the input quantum states. + + Note: + The fidelity equation is based on Equation (9.53) in Quantum Computation & Quantum Information, 10th edition. + """ type_rho, type_sigma = _type_fetch(rho), _type_fetch(sigma) rho = _type_transform(rho, "state").density_matrix @@ -582,10 +721,7 @@ def state_fidelity( ) -def trace_distance( - rho: Union[np.ndarray, torch.Tensor, State], - sigma: Union[np.ndarray, torch.Tensor, State], -) -> Union[np.ndarray, torch.Tensor]: +def trace_distance(rho: _StateLike, sigma: _StateLike) -> _ArrayLike: r"""Calculate the trace distance of two quantum states. .. math:: @@ -609,9 +745,7 @@ def trace_distance( ) -def von_neumann_entropy( - rho: Union[np.ndarray, torch.Tensor, State], base: Optional[int] = 2 -) -> Union[np.ndarray, torch.Tensor]: +def von_neumann_entropy(rho: _StateLike, base: int = 2) -> _ArrayLike: r"""Calculate the von Neumann entropy of a quantum state. .. math:: diff --git a/setup.py b/setup.py index ec7aec4..788bda5 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setuptools.setup( name='quairkit', - version='0.2.0', + version='0.3.0', author='QuAIR team.', author_email='leizhang116.4@gmail.com', description='QuAIRKit is a Python research toolbox for developing quantum computing, quantum information, and quantum machine learning algorithms.', @@ -46,6 +46,9 @@ 'quairkit.operator.channel', 'quairkit.operator.gate', 'quairkit.qinfo', + 'quairkit.application', + 'quairkit.application.comb', + 'quairkit.application.locc', ], install_requires=[ 'torch>=2.0.0', diff --git a/tutorials/feature/batch.ipynb b/tutorials/feature/batch.ipynb index 68f64c0..fd5616c 100644 --- a/tutorials/feature/batch.ipynb +++ b/tutorials/feature/batch.ipynb @@ -56,19 +56,19 @@ "output_type": "stream", "text": [ "Quantum circuit output: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [1, 0]\n", " Batch size: [3]\n", "\n", " # 0:\n", - "[ 0.95+0.j 0. -0.29j 0. -0.14j -0.04+0.j ]\n", + "[ 0.87+0.j 0. -0.11j 0. -0.47j -0.06+0.j ]\n", " # 1:\n", - "[ 0.87+0.j 0. -0.46j 0. -0.17j -0.09+0.j ]\n", + "[ 0.87+0.j 0. -0.38j 0. -0.3j -0.13+0.j ]\n", " # 2:\n", - "[ 0.98+0.j 0. -0.05j 0. -0.19j -0.01+0.j ]\n", - "---------------------------------------------------\n", + "[ 0.92+0.j 0. -0.16j 0. -0.36j -0.06+0.j ]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -107,19 +107,19 @@ "text": [ "The shape of oracle unitary: torch.Size([3, 2, 2])\n", "Quantum circuit output: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [1, 0]\n", " Batch size: [3]\n", "\n", " # 0:\n", - "[-0.41+0.38j 0. +0.j -0.11-0.82j 0. +0.j ]\n", + "[-0.94-0.08j 0. +0.j -0.06+0.32j 0. +0.j ]\n", " # 1:\n", - "[0.51+0.52j 0. +0.j 0.69+0.06j 0. +0.j ]\n", + "[ 0.13-0.86j 0. +0.j -0.15+0.47j 0. +0.j ]\n", " # 2:\n", - "[ 0.84-0.01j 0. +0.j -0.25+0.48j 0. +0.j ]\n", - "---------------------------------------------------\n", + "[-0.69-0.53j 0. +0.j -0.16-0.46j 0. +0.j ]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -156,28 +156,28 @@ "output_type": "stream", "text": [ "Kraus channel: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", " Batch size: [3]\n", "\n", " # 0:\n", - "[[0.66+0.j 0. +0.j 0.3 -0.j 0. +0.j]\n", - " [0. +0.j 0. +0.j 0. +0.j 0. +0.j]\n", - " [0.3 +0.j 0. +0.j 0.34+0.j 0. +0.j]\n", - " [0. +0.j 0. +0.j 0. +0.j 0. +0.j]]\n", + "[[ 0.52+0.j 0. +0.j -0.5 -0.06j 0. +0.j ]\n", + " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", + " [-0.5 +0.06j 0. +0.j 0.48+0.j 0. +0.j ]\n", + " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", " # 1:\n", - "[[0.82+0.j 0. +0.j 0.3 -0.08j 0. +0.j ]\n", + "[[0.23+0.j 0. +0.j 0.31+0.28j 0. +0.j ]\n", " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", - " [0.3 +0.08j 0. +0.j 0.18+0.j 0. +0.j ]\n", + " [0.31-0.28j 0. +0.j 0.77+0.j 0. +0.j ]\n", " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", " # 2:\n", - "[[ 0.35+0.j 0. +0.j -0.43+0.17j 0. +0.j ]\n", - " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", - " [-0.43-0.17j 0. +0.j 0.65+0.j 0. +0.j ]\n", - " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", - "---------------------------------------------------\n", + "[[0.61+0.j 0. +0.j 0.07-0.48j 0. +0.j ]\n", + " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", + " [0.07+0.48j 0. +0.j 0.39+0.j 0. +0.j ]\n", + " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -206,28 +206,28 @@ "output_type": "stream", "text": [ "Choi channel: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", " Batch size: [3]\n", "\n", " # 0:\n", - "[[0.07+0.j 0.11-0.24j 0. +0.j 0. +0.j ]\n", - " [0.11+0.24j 0.93+0.j 0. +0.j 0. +0.j ]\n", - " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", - " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", - " # 1:\n", - "[[ 0.54+0.j -0.44-0.23j 0. +0.j 0. +0.j ]\n", - " [-0.44+0.23j 0.46+0.j 0. +0.j 0. +0.j ]\n", + "[[ 0.5 +0.j -0.23-0.44j 0. +0.j 0. +0.j ]\n", + " [-0.23+0.44j 0.5 +0.j 0. +0.j 0. +0.j ]\n", " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", + " # 1:\n", + "[[ 0.32+0.j -0.26+0.3j 0. +0.j 0. +0.j ]\n", + " [-0.26-0.3j 0.68+0.j 0. +0.j 0. +0.j ]\n", + " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", + " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", " # 2:\n", - "[[ 0.27+0.j -0.14+0.42j 0. +0.j 0. +0.j ]\n", - " [-0.14-0.42j 0.73+0.j 0. +0.j 0. +0.j ]\n", + "[[ 0.42+0.j -0.06-0.41j 0. +0.j 0. +0.j ]\n", + " [-0.06+0.41j 0.58+0.j 0. +0.j 0. +0.j ]\n", " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", "\n" ] } @@ -305,22 +305,22 @@ "output_type": "stream", "text": [ "Output state: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [3]\n", "\n", " # 0:\n", - "[[0.44-0.j 0.04+0.05j]\n", - " [0.04-0.05j 0.56+0.j ]]\n", + "[[0.5 -0.j 0.08+0.04j]\n", + " [0.08-0.04j 0.5 +0.j ]]\n", " # 1:\n", - "[[0.27+0.j 0.25+0.22j]\n", - " [0.25-0.22j 0.73+0.j ]]\n", + "[[0.49+0.j 0.18+0.21j]\n", + " [0.18-0.21j 0.51+0.j ]]\n", " # 2:\n", - "[[0.45+0.j 0.13+0.03j]\n", - " [0.13-0.03j 0.55+0.j ]]\n", - "---------------------------------------------------\n", + "[[0.49-0.j 0.18+0.22j]\n", + " [0.18-0.22j 0.51+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -359,7 +359,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Hamiltonian: [[-0.09066232223158144, 'Z0'], [-0.7931476010024183, 'X1'], [0.7190023895147757, 'Y0']]\n" + "Hamiltonian: [[-0.5048868288610004, 'Y0'], [-0.26312841520515695, 'X0'], [-0.28006427149436375, 'Z1']]\n" ] } ], @@ -385,34 +385,34 @@ "output_type": "stream", "text": [ "Output state: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", " Batch size: [3]\n", "\n", " # 0:\n", - "[[0.66+0.j 0. +0.j 0.3 -0.j 0. +0.j]\n", - " [0. +0.j 0. +0.j 0. +0.j 0. +0.j]\n", - " [0.3 +0.j 0. +0.j 0.34+0.j 0. +0.j]\n", - " [0. +0.j 0. +0.j 0. +0.j 0. +0.j]]\n", + "[[ 0.52+0.j 0. +0.j -0.5 -0.06j 0. +0.j ]\n", + " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", + " [-0.5 +0.06j 0. +0.j 0.48+0.j 0. +0.j ]\n", + " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", " # 1:\n", - "[[0.82+0.j 0. +0.j 0.3 -0.08j 0. +0.j ]\n", + "[[0.23+0.j 0. +0.j 0.31+0.28j 0. +0.j ]\n", " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", - " [0.3 +0.08j 0. +0.j 0.18+0.j 0. +0.j ]\n", + " [0.31-0.28j 0. +0.j 0.77+0.j 0. +0.j ]\n", " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", " # 2:\n", - "[[ 0.35+0.j 0. +0.j -0.43+0.17j 0. +0.j ]\n", - " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", - " [-0.43-0.17j 0. +0.j 0.65+0.j 0. +0.j ]\n", - " [ 0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", - "---------------------------------------------------\n", + "[[0.61+0.j 0. +0.j 0.07-0.48j 0. +0.j ]\n", + " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]\n", + " [0.07+0.48j 0. +0.j 0.39+0.j 0. +0.j ]\n", + " [0. +0.j 0. +0.j 0. +0.j 0. +0.j ]]\n", + "-----------------------------------------------------\n", "\n", - "expectation value: tensor([-0.0246, 0.0647, -0.2120])\n", - "expectation value: tensor([-0.0246, 0.0647, -0.2120])\n", - "expectation value of each Pauli term: tensor([[-0.0292, -0.0574, 0.0271],\n", - " [-0.0000, -0.0000, -0.0000],\n", - " [ 0.0047, 0.1221, -0.2391]])\n" + "expectation value: tensor([-0.0830, -0.1589, -0.8059])\n", + "expectation value: tensor([-0.0830, -0.1589, -0.8059])\n", + "expectation value of each Pauli term: tensor([[-0.0638, 0.2860, -0.4882],\n", + " [ 0.2609, -0.1648, -0.0377],\n", + " [-0.2801, -0.2801, -0.2801]])\n" ] } ], @@ -448,12 +448,12 @@ "output_type": "stream", "text": [ "The shape of PVM: torch.Size([2, 2, 2])\n", - "expectation value: tensor([[0.3801, 0.6199],\n", - " [0.3868, 0.6132],\n", - " [0.4948, 0.5052]])\n", - "expectation value: tensor([[0.3801, 0.6199],\n", - " [0.3868, 0.6132],\n", - " [0.4948, 0.5052]])\n" + "expectation value: tensor([[0.4802, 0.5198],\n", + " [0.8258, 0.1742],\n", + " [0.2648, 0.7352]])\n", + "expectation value: tensor([[0.4802, 0.5198],\n", + " [0.8258, 0.1742],\n", + " [0.2648, 0.7352]])\n" ] } ], @@ -511,13 +511,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -546,7 +546,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/feature/custom.ipynb b/tutorials/feature/custom.ipynb index a194902..4631870 100644 --- a/tutorials/feature/custom.ipynb +++ b/tutorials/feature/custom.ipynb @@ -51,7 +51,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -82,7 +82,7 @@ "outputs": [ { "data": { - "image/png": "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oTpazWaz20vzgNZeEJSWlgoAm9vNly5dkuDgYIe34Js7sby83ONta5abmytDhgyxWf/QQw/JqFGjlMcZGRliMplk+PDh8tNPP1nt26dPH/n000+Vx01NTfLiiy9Kly5dJDw8XEaOHCnHjx9Xtk+bNk0yMzOVx+vWrZOQkBA5e/as3TYeOXJEsrKypEuXLhIRESE333yz1QvzgQMHJCEhQS5duuTwfJu50rd79+5tc8r1559/brPcuXPnJCgoSHbt2mV3+8GDBwWAHDx40Gbb+fPnpUuXLvL555975PluzWQyCWB7u//8+fMSGBgoX331lYi0PU3w0ksvWZXr3bu33YG1pdWrV0t0dLRs3brVav3Ro0clMTFRSktLlXWuJHRtHV+N+vp6CQsLky+++EJZ197UhjvHtcfdvnH2owfNXH2tef/99yUkJMTqeujUqZPcfPPNHfKaao+7MezMVJejj4C4On0m4l78O4pRdxM6NdeUmnP3xzh2Nu60MGbm5+dLUlKShIWFSXJysrz88svS2NiobHd2zHT19aGtRQ2/+wzd2rVrJTg42KbTtm3bJoGBge1+7kptHZ4s157nn39e7rvvPsnLy7PZtnXrVrnlllvafDfR0SZMmCDvv/++U2Vc7aO33npLAgMDJTw8XABISEiIbNq0yWG5+++/X5577jm725pfUMrLy222bdiwQXr06GF1MbbmzvNdVFQkAGzuqr3zzjuSkJAgDQ0NIiIyffp0m8+IpKamyowZM6zWpaWltZvQLVu2TGJiYmTHjh0225YvXy7BwcESFxenLAAkMjJScnJyVJ1Pe8dXo6GhQcLDw+Xzzz9X1uXl5UlKSopb8W3vuK15om9mzZolY8eOdbp9rsZQU1OTTJ48WYKCgiQsLEwASHx8vPzwww9ea4M7MZycnCyLFy9WHldVVUlISEibb7bPnTsnAKw+vysicssttyjJorPHbOZO/DuKUXcSOmeuKUfn7o9x3BHjpci1NWZ2VB+1x+8SutzcXBk0aJDN+ldffVXS09M9Uocny7Vn/fr10rNnT7l8+bLHjulL7vRReXm5/P3vfxcAVu8021NYWCgxMTFSW1tr93htJXR33XWXvPrqq+0e251zqampkZiYGHn88cfl3LlzUlVVJatWrZKIiAhZsWKFsp+9aYIFCxZIt27dZP/+/dLY2Cjvv/++dO7c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", + "image/png": "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amqq222wxd0YFvnuD7g//elPDs9bR2UGDRokb775prJObW2tAJDCwkJV27zzzjvlN7/5jap1O1ITY67GoTtlO8ew2nPUlRgW8V5C58k+s7q6WgBYfc6IiAwYMEBWrVrV7XYuXrwoQUFB8s9//rPLMk/3mb5I6FR/D11NTY3aVd3ehtFohMlkQnx8vNX8hoYGTJkyxaN1ubJ+WVkZLl++jGHDhgEAYmNj8dJLLyErKwsrV65ETEwMDh06hNdff115UOGpp55CVlYWJkyYgOHDh+PEiRNdtpuXl4cXX3wR//znPzF69Gin2h8QEICAgADlMnFSUhI2bNigLP/qq6/w7LPPYsyYMcq84uJiq0vWanV3rC5evIiEhATU1dXZXF5bW6v823kbwcHBCAoKwvnz5xEYGGiz/J49exAUFISWlhar+S0tLfjoo4/wox/9yO19UMNoNNoc9j98+LAy/+jRo/jv//5vl+sAHA8r3H333Vbr2xpKUKN96D48PByjR4/Gq6++qnp4sDNxMHRx1113ubRdtTrequDM8cvIyMA777zjUp32YslkMiE2NrbbdeydE3q9HpWVlXa372ocuxPDO3fuxKOPPgqz2YyAgAA8//zziImJsVufvTLz589HXl4eHn74YcTFxeGtt97C7bff7vC2FACor6/HoUOHMHr0aIwYMQIlJSW4/fbbsXTpUqdu+/Antm63UXOOuhPDgHOx5GzcebrPjIqKQkpKCgoLC5Xz22w249y5c11u1epozZo1MBgMVg9DtOupPtMTuRMAREZGOl5JbeaHTldF3JkcZayJiYmyaNEiKS8vt5oGDx4sf/jDH+yWbc+Ke6ptIiJbtmyR3r17W12JamlpkejoaOWSd1NTk/Tv319ERI4cOSLTp09X1t2zZ48YDAar8u1DZZ3/4ujO5s2blaHniooKmTVrlqSkpChDKKdOnZIrV66IxWKR4uJiGT58uGRnZ1ttY9SoUbJ27VpV9Ym4f2z9cXLlryeDwWB11addRkaGLF68WETsD6ur/cvd2WGF7oYS7HE0dN8de/ugZujCEVeubnS+VcGZ4+fs7Qci/nU+OBvH7sawyHdXWf74xz/K1q1bVddrq0xJSYmMHz9eAEhgYKAkJibKF198oWp77Vc4k5KSlGHLNWvWSFhYmJw7d85uWX+8Qmfrdhu156grMSziXhyrjbue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YMeOHbh27Vq3X5Ny8OBB/O53v0NVVRUSExMxe/ZsLFq0SFl+8uRJfPPNN5g5c6b6AwXv5iIBIh0e6+hhNTU1iIqKgtls7nYH58+fj3379uHQoUNW83//+99j8+bNOH78uNt1EBERkWt6qp+dN28eSktLMWDAACxevNhqWX5+Pl544QUUFhZaJYbeMn36dEydOhVPPPGEqvV9kYv4XUKnhTqIiIi+r3qqn92+fTuee+45fP3118p3xGmVL3IRv3zKlYiIiL5f9u/fj1WrVmk+mfMVJnRERETkMxcuXMBDDz2EwMBAPPjgg75ujmb55RcLExER0fdD3759sX37dl83Q/N4hY6IiIhI45jQEREREWkcEzoiIiIijWNCR0RERKRxTOiIiIiINI4JHREREZHGMaEjIiIi0jgmdEREREQax4SOiIiISOOY0BERERFpHBM6IiIiIo3zyW+51tTUaHLbRERE9B32t93zxbHxakKn0+mQlJQEg8HQo/UkJSVBp9P1aB1ERETfR97qy7XO27lIgIiI12oD0NjYiObm5h6tQ6fTITQ0tEfrICIi+r7yRl+udd7ORbye0BERERGRZ/GhCCIiIiKNY0JHREREpHFM6IiIiIg0jgkdERERkcYxoSMiIiLSOCZ0RERERBrHhI6IiIhI45jQEREREWkcEzoiIiIijWNCR0RERKRxTOiIiIiINI4JHREREZHGMaEjIiIi0jgmdEREREQa9/8BGHA4boipOAkAAAAASUVORK5CYII=", "text/plain": [ "
" ] @@ -99,7 +99,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -137,7 +137,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -158,7 +158,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -190,16 +190,16 @@ "text": [ "The parameters of first two RY gates are\n", " [Parameter containing:\n", - "tensor([[[0.4804]],\n", + "tensor([[[ 1.3114]],\n", "\n", - " [[0.0517]]], requires_grad=True)]\n", + " [[-0.8210]]], requires_grad=True)]\n", "The Kraus representations of the first two RY gates are: \n", - " tensor([[[[ 0.9713+0.j, -0.2379+0.j],\n", - " [ 0.2379+0.j, 0.9713+0.j]]],\n", + " tensor([[[[ 0.7926+0.j, -0.6097+0.j],\n", + " [ 0.6097+0.j, 0.7926+0.j]]],\n", "\n", "\n", - " [[[ 0.9997+0.j, -0.0258+0.j],\n", - " [ 0.0258+0.j, 0.9997+0.j]]]], grad_fn=)\n" + " [[[ 0.9169+0.j, 0.3991+0.j],\n", + " [-0.3991+0.j, 0.9169+0.j]]]], grad_fn=)\n" ] } ], @@ -251,7 +251,7 @@ "text": [ "The parameters of this circuit are\n", " [Parameter containing:\n", - "tensor([[[5.0111, 5.7265, 0.4270]]], requires_grad=True)]\n" + "tensor([[[2.1875, 0.4630, 2.6166]]], requires_grad=True)]\n" ] } ], @@ -445,13 +445,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -480,7 +480,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/feature/qudit.ipynb b/tutorials/feature/qudit.ipynb index 48790fa..d65f474 100644 --- a/tutorials/feature/qudit.ipynb +++ b/tutorials/feature/qudit.ipynb @@ -60,7 +60,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -119,13 +119,13 @@ "output_type": "stream", "text": [ "The output state of the circuit is \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2, 2]\n", " System sequence: [2, 0, 1]\n", - "[ 0.59+0.j -0.01-0.07j -0.19+0.26j -0.03-0.15j -0.06+0.04j -0.33-0.56j\n", - " 0.13+0.04j -0.11-0.26j]\n", - "---------------------------------------------------\n", + "[-0.1 +0.j 0. -0.j -0.01+0.j 0.01-0.36j 0. -0.j -0.74+0.55j\n", + " 0.02-0.03j -0. -0.j ]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -162,29 +162,29 @@ "----------------------------------------------------------------------------------------------------\n", "\n", "Random 2-qutrit states: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [3, 3]\n", " System sequence: [0, 1]\n", - "[[ 0.11+0.j -0.04-0.04j 0. -0.04j -0.03+0.01j -0. +0.03j 0. +0.02j\n", - " -0. -0.01j -0. -0.02j -0.01-0.03j]\n", - " [-0.04+0.04j 0.1 +0.j -0.02-0.06j -0.01-0.j -0. +0.02j 0.02+0.01j\n", - " -0.01+0.02j -0.01-0.02j 0.01-0.01j]\n", - " [ 0. +0.04j -0.02+0.06j 0.23+0.j 0.04-0.01j -0.03+0.j -0.08+0.03j\n", - " -0. +0.01j 0.03-0.02j -0.01-0.03j]\n", - " [-0.03-0.01j -0.01+0.j 0.04+0.01j 0.1 +0.j 0.01-0.03j 0.02+0.j\n", - " 0.01-0.01j 0.04+0.01j -0.03+0.01j]\n", - " [-0. -0.03j -0. -0.02j -0.03-0.j 0.01+0.03j 0.11+0.j -0.02-0.02j\n", - " 0. +0.01j -0.01+0.03j -0.04+0.02j]\n", - " [ 0. -0.02j 0.02-0.01j -0.08-0.03j 0.02-0.j -0.02+0.02j 0.11+0.j\n", - " 0.02-0.01j -0.01-0.01j -0.01-0.01j]\n", - " [-0. +0.01j -0.01-0.02j -0. -0.01j 0.01+0.01j 0. -0.01j 0.02+0.01j\n", - " 0.09+0.j -0. +0.03j -0.03+0.01j]\n", - " [-0. +0.02j -0.01+0.02j 0.03+0.02j 0.04-0.01j -0.01-0.03j -0.01+0.01j\n", - " -0. -0.03j 0.09+0.j 0.01+0.j ]\n", - " [-0.01+0.03j 0.01+0.01j -0.01+0.03j -0.03-0.01j -0.04-0.02j -0.01+0.01j\n", - " -0.03-0.01j 0.01-0.j 0.07+0.j ]]\n", - "---------------------------------------------------\n", + "[[ 0.1 +0.j 0.04-0.05j 0.01+0.01j 0.03+0.02j 0.02-0.02j 0.01-0.01j\n", + " 0.01-0.02j 0.02-0.03j 0.02+0.07j]\n", + " [ 0.04+0.05j 0.14+0.j -0.03+0.01j -0.03+0.03j -0.01-0.j -0.01+0.01j\n", + " -0.06+0.05j -0.01+0.04j -0.01+0.05j]\n", + " [ 0.01-0.01j -0.03-0.01j 0.21+0.j 0.04-0.02j 0.05+0.01j -0. +0.05j\n", + " 0.03+0.04j 0.05-0.01j 0.03+0.06j]\n", + " [ 0.03-0.02j -0.03-0.03j 0.04+0.02j 0.08+0.j 0.03+0.01j 0.03-0.j\n", + " 0.05-0.01j 0.04-0.01j -0.04+0.03j]\n", + " [ 0.02+0.02j -0.01+0.j 0.05-0.01j 0.03-0.01j 0.04+0.j 0.02+0.j\n", + " 0.02+0.01j 0.03-0.03j -0.02+0.03j]\n", + " [ 0.01+0.01j -0.01-0.01j -0. -0.05j 0.03+0.j 0.02-0.j 0.04+0.j\n", + " 0.05-0.02j 0.03-0.02j -0.01-0.j ]\n", + " [ 0.01+0.02j -0.06-0.05j 0.03-0.04j 0.05+0.01j 0.02-0.01j 0.05+0.02j\n", + " 0.16+0.j 0.07-0.01j -0.04+0.01j]\n", + " [ 0.02+0.03j -0.01-0.04j 0.05+0.01j 0.04+0.01j 0.03+0.03j 0.03+0.02j\n", + " 0.07+0.01j 0.08+0.j -0.02+0.03j]\n", + " [ 0.02-0.07j -0.01-0.05j 0.03-0.06j -0.04-0.03j -0.02-0.03j -0.01+0.j\n", + " -0.04-0.01j -0.02-0.03j 0.15+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -260,24 +260,24 @@ "The dimension of each system of the state is [2, 3, 6]\n", "----------------------------------------------------------------------------------------------------\n", "Random 3-qudit states: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 3, 6]\n", " System sequence: [0, 1, 2]\n", - "[[ 0.03+0.j 0. -0.01j -0. -0.01j ... 0.02+0.j -0.01-0.02j\n", - " 0.01+0.j ]\n", - " [ 0. +0.01j 0.01+0.j 0. -0.j ... -0.01-0.j 0.01-0.01j\n", - " -0.01-0.j ]\n", - " [-0. +0.01j 0. +0.j 0.01+0.j ... -0.01+0.01j 0. -0.j\n", - " 0. +0.j ]\n", + "[[ 0.02+0.j -0. +0.j 0. +0.01j ... 0. +0.j -0. -0.j\n", + " 0. -0.j ]\n", + " [-0. -0.j 0.02+0.j -0. +0.j ... 0. -0.01j 0. -0.j\n", + " -0. +0.01j]\n", + " [ 0. -0.01j -0. -0.j 0.03+0.j ... 0. +0.01j 0. -0.j\n", + " 0. -0.j ]\n", " ...\n", - " [ 0.02-0.j -0.01+0.j -0.01-0.01j ... 0.04+0.j -0. +0.j\n", - " 0.01-0.01j]\n", - " [-0.01+0.02j 0.01+0.01j 0. +0.j ... -0. -0.j 0.03+0.j\n", - " -0. -0.01j]\n", - " [ 0.01-0.j -0.01+0.j 0. -0.j ... 0.01+0.01j -0. +0.01j\n", + " [ 0. -0.j 0. +0.01j 0. -0.01j ... 0.04+0.j 0. +0.j\n", + " -0. +0.j ]\n", + " [-0. +0.j 0. +0.j 0. +0.j ... 0. -0.j 0.04+0.j\n", + " -0. +0.j ]\n", + " [ 0. +0.j -0. -0.01j 0. +0.j ... -0. -0.j -0. -0.j\n", " 0.03+0.j ]]\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", "\n" ] } @@ -367,7 +367,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -410,26 +410,29 @@ "output_type": "stream", "text": [ "The first system is replaced with state \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [4]\n", " System sequence: [0]\n", - "[[ 0.36+0.j -0.05-0.01j -0.12-0.06j -0.02+0.21j]\n", - " [-0.05+0.01j 0.3 +0.j -0.1 +0.02j -0.16-0.06j]\n", - " [-0.12+0.06j -0.1 -0.02j 0.11+0.j 0.02-0.06j]\n", - " [-0.02-0.21j -0.16+0.06j 0.02+0.06j 0.23+0.j ]]\n", - "---------------------------------------------------\n", + "[[ 0.25+0.j -0.01-0.08j -0.02+0.03j 0.07-0.03j]\n", + " [-0.01+0.08j 0.15+0.j 0.13+0.04j 0.04-0.09j]\n", + " [-0.02-0.03j 0.13-0.04j 0.31+0.j -0.09-0.24j]\n", + " [ 0.07+0.03j 0.04+0.09j -0.09+0.24j 0.29+0.j ]]\n", + "-----------------------------------------------------\n", "\n", "while the output state of first system is: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [4]\n", " System sequence: [0]\n", - "[[ 0.36+0.j -0.05-0.01j -0.12-0.06j -0.02+0.21j]\n", - " [-0.05+0.01j 0.3 +0.j -0.1 +0.02j -0.16-0.06j]\n", - " [-0.12+0.06j -0.1 -0.02j 0.11+0.j 0.02-0.06j]\n", - " [-0.02-0.21j -0.16+0.06j 0.02+0.06j 0.23+0.j ]]\n", - "---------------------------------------------------\n", + " Batch size: [1]\n", + "\n", + " # 0:\n", + "[[ 0.25+0.j -0.01-0.08j -0.02+0.03j 0.07-0.03j]\n", + " [-0.01+0.08j 0.15+0.j 0.13+0.04j 0.04-0.09j]\n", + " [-0.02-0.03j 0.13-0.04j 0.31+0.j -0.09-0.24j]\n", + " [ 0.07+0.03j 0.04+0.09j -0.09+0.24j 0.29+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -466,33 +469,33 @@ "output_type": "stream", "text": [ "The output state of the second system is: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [3]\n", " System sequence: [0]\n", " Batch size: [5]\n", "\n", " # 0:\n", - "[[ 0.28+0.j -0.05+0.24j 0.02-0.11j]\n", - " [-0.05-0.24j 0.49+0.j -0.04-0.21j]\n", - " [ 0.02+0.11j -0.04+0.21j 0.23+0.j ]]\n", + "[[0.37+0.j 0.03+0.17j 0.06+0.11j]\n", + " [0.03-0.17j 0.51+0.j 0.22+0.04j]\n", + " [0.06-0.11j 0.22-0.04j 0.12+0.j ]]\n", " # 1:\n", - "[[ 0.28+0.j -0.05+0.24j 0.02-0.11j]\n", - " [-0.05-0.24j 0.49+0.j -0.04-0.21j]\n", - " [ 0.02+0.11j -0.04+0.21j 0.23+0.j ]]\n", + "[[0.37+0.j 0.03+0.17j 0.06+0.11j]\n", + " [0.03-0.17j 0.51+0.j 0.22+0.04j]\n", + " [0.06-0.11j 0.22-0.04j 0.12+0.j ]]\n", " # 2:\n", - "[[ 0.28+0.j -0.05+0.24j 0.02-0.11j]\n", - " [-0.05-0.24j 0.49+0.j -0.04-0.21j]\n", - " [ 0.02+0.11j -0.04+0.21j 0.23+0.j ]]\n", + "[[0.37+0.j 0.03+0.17j 0.06+0.11j]\n", + " [0.03-0.17j 0.51+0.j 0.22+0.04j]\n", + " [0.06-0.11j 0.22-0.04j 0.12+0.j ]]\n", " # 3:\n", - "[[ 0.28+0.j -0.05+0.24j 0.02-0.11j]\n", - " [-0.05-0.24j 0.49+0.j -0.04-0.21j]\n", - " [ 0.02+0.11j -0.04+0.21j 0.23+0.j ]]\n", + "[[0.37+0.j 0.03+0.17j 0.06+0.11j]\n", + " [0.03-0.17j 0.51+0.j 0.22+0.04j]\n", + " [0.06-0.11j 0.22-0.04j 0.12+0.j ]]\n", " # 4:\n", - "[[ 0.28+0.j -0.05+0.24j 0.02-0.11j]\n", - " [-0.05-0.24j 0.49+0.j -0.04-0.21j]\n", - " [ 0.02+0.11j -0.04+0.21j 0.23+0.j ]]\n", - "---------------------------------------------------\n", + "[[0.37+0.j 0.03+0.17j 0.06+0.11j]\n", + " [0.03-0.17j 0.51+0.j 0.22+0.04j]\n", + " [0.06-0.11j 0.22-0.04j 0.12+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -526,38 +529,37 @@ "name": "stdout", "output_type": "stream", "text": [ - "The first state for obtaining measurement result '1' for the system 0 is " - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "---------------------------------------------------\n", + "The first state for obtaining measurement result '1' for the system 0 is \n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 3, 6]\n", " System sequence: [0, 1, 2]\n", - "[ 0.14-0.18j -0.02+0.13j 0.05-0.21j -0. -0.03j 0.05-0.1j -0.05-0.j\n", - " 0.09-0.18j 0. +0.11j 0.01-0.19j -0. -0.02j 0.03-0.09j -0.04+0.01j\n", - " 0.22+0.24j -0.18-0.06j 0.28+0.13j 0.04+0.01j 0.13+0.09j 0.01-0.07j\n", - " -0.14+0.18j 0.02-0.13j -0.05+0.21j 0. +0.03j -0.05+0.1j 0.05+0.j\n", - " -0.09+0.18j -0. -0.11j -0.01+0.19j 0. +0.02j -0.03+0.09j 0.04-0.01j\n", - " -0.22-0.24j 0.18+0.06j -0.28-0.13j -0.04-0.01j -0.13-0.09j -0.01+0.07j]\n", - "---------------------------------------------------\n", + " Batch size: [5]\n", + "\n", + " # 0:\n", + "[-0.08-0.16j -0.18+0.26j -0.15+0.05j 0.16+0.06j 0.07-0.16j 0.27-0.06j\n", + " -0.12+0.06j 0.19+0.13j 0.03+0.11j 0.04-0.12j -0.12-0.05j -0.04-0.2j\n", + " -0.07+0.02j 0.09+0.09j 0.01+0.06j 0.04-0.06j -0.06-0.04j 0. -0.11j\n", + " 0.08+0.16j 0.18-0.26j 0.15-0.05j -0.16-0.06j -0.07+0.16j -0.27+0.06j\n", + " 0.12-0.06j -0.19-0.13j -0.03-0.11j -0.04+0.12j 0.12+0.05j 0.04+0.2j\n", + " 0.07-0.02j -0.09-0.09j -0.01-0.06j -0.04+0.06j 0.06+0.04j -0. +0.11j]\n", + "-----------------------------------------------------\n", "\n", "The first state for obtaining measurement result '2' for the system 1, and '4' for the system 2 is \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 3, 6]\n", " System sequence: [0, 1, 2]\n", + " Batch size: [5]\n", + "\n", + " # 0:\n", "[ 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j\n", " 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j\n", - " 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0.34+0.47j 0. +0.j\n", + " 0. +0.j 0. +0.j 0. +0.j 0. +0.j -0.04-0.66j 0. +0.j\n", " 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j\n", " 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0. +0.j\n", - " 0. +0.j 0. +0.j 0. +0.j 0. +0.j -0.74-0.33j 0. +0.j ]\n", - "---------------------------------------------------\n", + " 0. +0.j 0. +0.j 0. +0.j 0. +0.j 0.75-0.07j 0. +0.j ]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -593,31 +595,31 @@ "name": "stdout", "output_type": "stream", "text": [ - "systems [1, 2] collapse to the state |1>|3> with (average) probability 0.009825415569497007\n", + "systems [1, 2] collapse to the state |1>|3> with (average) probability 0.016744241430078275\n", "\n", " After collapsing the second qudit to its first eigenstate and the third qudit to its third eigenstate the state of the first system is: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [5]\n", "\n", " # 0:\n", - "[[0.95+0.j 0.08+0.19j]\n", - " [0.08-0.19j 0.05+0.j ]]\n", + "[[0.09+0.j 0.24+0.15j]\n", + " [0.24-0.15j 0.91+0.j ]]\n", " # 1:\n", - "[[0.95+0.j 0.08+0.19j]\n", - " [0.08-0.19j 0.05+0.j ]]\n", + "[[0.09+0.j 0.24+0.15j]\n", + " [0.24-0.15j 0.91+0.j ]]\n", " # 2:\n", - "[[0.95+0.j 0.08+0.19j]\n", - " [0.08-0.19j 0.05+0.j ]]\n", + "[[0.09+0.j 0.24+0.15j]\n", + " [0.24-0.15j 0.91+0.j ]]\n", " # 3:\n", - "[[0.95+0.j 0.08+0.19j]\n", - " [0.08-0.19j 0.05+0.j ]]\n", + "[[0.09+0.j 0.24+0.15j]\n", + " [0.24-0.15j 0.91+0.j ]]\n", " # 4:\n", - "[[0.95+0.j 0.08+0.19j]\n", - " [0.08-0.19j 0.05+0.j ]]\n", - "---------------------------------------------------\n", + "[[0.09+0.j 0.24+0.15j]\n", + " [0.24-0.15j 0.91+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -656,13 +658,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -691,7 +693,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/introduction/Hamiltonian.ipynb b/tutorials/introduction/Hamiltonian.ipynb index ef664ac..1d2d7ec 100644 --- a/tutorials/introduction/Hamiltonian.ipynb +++ b/tutorials/introduction/Hamiltonian.ipynb @@ -127,9 +127,9 @@ "0.5 Z1, Z2\n", "----------------------------------------------------------------------------------------------------\n", "The Pauli decomposition of the random Hamiltonian is:\n", - " 0.30402787550624577 Z1, Z2\n", - "-0.44363024944835594 X0, Y1, X2\n", - "0.6638237762231716 Y0, Z1, X2\n", + " 0.4181599354425789 X0, Z1, X2\n", + "-0.3910227956714316 Y0\n", + "0.17055199353235606 X0, Y1, Z2\n", "----------------------------------------------------------------------------------------------------\n" ] } @@ -217,9 +217,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "Expection value of the Hamiltonian: tensor(-0.0484)\n", + "Expection value of the Hamiltonian: tensor(0.0417)\n", "----------------------------------------------------------------------------------------------------\n", - "Expection value of the Hamiltonian: tensor(-0.0484)\n" + "Expection value of the Hamiltonian: tensor(0.0417)\n" ] } ], @@ -248,12 +248,12 @@ "output_type": "stream", "text": [ "For 1000 random 3-qubit states, a set of Expection value of a given Hamiltonian:\n", - " tensor([-0.0007, -0.0193, -0.0598, -0.0859, -0.1097, -0.1909, 0.0444, 0.0678,\n", - " -0.1136, 0.0709])\n", + " tensor([ 0.0420, 0.0472, -0.5196, 0.0336, -0.2425, -0.2431, 0.0382, -0.0846,\n", + " -0.1158, 0.2608])\n", "----------------------------------------------------------------------------------------------------\n", "For 1000 random 3-qubit states, a set of Expection value of a given Hamiltonian:\n", - " tensor([-0.0007, -0.0193, -0.0598, -0.0859, -0.1097, -0.1909, 0.0444, 0.0678,\n", - " -0.1136, 0.0709])\n" + " tensor([ 0.0420, 0.0472, -0.5196, 0.0336, -0.2425, -0.2431, 0.0382, -0.0846,\n", + " -0.1158, 0.2608])\n" ] } ], @@ -317,37 +317,37 @@ "output_type": "stream", "text": [ "The Pauli decomposition of the random Hamiltonian is:\n", - " 0.6087798181466624 Y1, X2\n", - "-0.8219269134530314 Z0, Z1, Z2\n", - "-0.7649579970411409 Y0, Y1, Y2\n", + " 0.5522232793578568 Z0, Z2\n", + "0.2221371571298889 Y0\n", + "0.21559535758899973 X0, Y1, Z2\n", "----------------------------------------------------------------------------------------------------\n", "Number of terms: 3\n", "----------------------------------------------------------------------------------------------------\n", "The Pauli string corresponding to the Hamiltonian:\n", - " [[0.6087798181466624, 'Y1,X2'], [-0.8219269134530314, 'Z0,Z1,Z2'], [-0.7649579970411409, 'Y0,Y1,Y2']]\n", + " [[0.5522232793578568, 'Z0,Z2'], [0.2221371571298889, 'Y0'], [0.21559535758899973, 'X0,Y1,Z2']]\n", "----------------------------------------------------------------------------------------------------\n", "The coefficients of the terms in the Hamiltonian:\n", - " [0.6087798181466624, -0.8219269134530314, -0.7649579970411409]\n", + " [0.5522232793578568, 0.2221371571298889, 0.21559535758899973]\n", "----------------------------------------------------------------------------------------------------\n", "The matrix form of the Hamiltonian:\n", - " tensor([[-0.8219+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-0.6088j,\n", - " 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-0.7650j],\n", - " [ 0.0000+0.0000j, 0.8219+0.0000j, 0.0000-0.6088j, 0.0000+0.0000j,\n", - " 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.7650j, 0.0000+0.0000j],\n", - " [ 0.0000+0.0000j, 0.0000+0.6088j, 0.8219+0.0000j, 0.0000+0.0000j,\n", - " 0.0000+0.0000j, 0.0000+0.7650j, 0.0000+0.0000j, 0.0000+0.0000j],\n", - " [ 0.0000+0.6088j, 0.0000+0.0000j, 0.0000+0.0000j, -0.8219+0.0000j,\n", - " 0.0000-0.7650j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j],\n", - " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.7650j,\n", - " 0.8219+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-0.6088j],\n", - " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.0000-0.7650j, 0.0000+0.0000j,\n", - " 0.0000+0.0000j, -0.8219+0.0000j, 0.0000-0.6088j, 0.0000+0.0000j],\n", - " [ 0.0000+0.0000j, 0.0000-0.7650j, 0.0000+0.0000j, 0.0000+0.0000j,\n", - " 0.0000+0.0000j, 0.0000+0.6088j, -0.8219+0.0000j, 0.0000+0.0000j],\n", - " [ 0.0000+0.7650j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j,\n", - " 0.0000+0.6088j, 0.0000+0.0000j, 0.0000+0.0000j, 0.8219+0.0000j]])\n", + " tensor([[ 0.5522+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j,\n", + " 0.0000-0.2221j, 0.0000+0.0000j, 0.0000-0.2156j, 0.0000+0.0000j],\n", + " [ 0.0000+0.0000j, -0.5522+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j,\n", + " 0.0000+0.0000j, 0.0000-0.2221j, 0.0000+0.0000j, 0.0000+0.2156j],\n", + " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.5522+0.0000j, 0.0000+0.0000j,\n", + " 0.0000+0.2156j, 0.0000+0.0000j, 0.0000-0.2221j, 0.0000+0.0000j],\n", + " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, -0.5522+0.0000j,\n", + " 0.0000+0.0000j, 0.0000-0.2156j, 0.0000+0.0000j, 0.0000-0.2221j],\n", + " [ 0.0000+0.2221j, 0.0000+0.0000j, 0.0000-0.2156j, 0.0000+0.0000j,\n", + " -0.5522+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j],\n", + " [ 0.0000+0.0000j, 0.0000+0.2221j, 0.0000+0.0000j, 0.0000+0.2156j,\n", + " 0.0000+0.0000j, 0.5522+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j],\n", + " [ 0.0000+0.2156j, 0.0000+0.0000j, 0.0000+0.2221j, 0.0000+0.0000j,\n", + " 0.0000+0.0000j, 0.0000+0.0000j, -0.5522+0.0000j, 0.0000+0.0000j],\n", + " [ 0.0000+0.0000j, 0.0000-0.2156j, 0.0000+0.0000j, 0.0000+0.2221j,\n", + " 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.5522+0.0000j]])\n", "----------------------------------------------------------------------------------------------------\n", - "The Pauli word of each term: ['IYX', 'ZZZ', 'YYY']\n", + "The Pauli word of each term: ['ZIZ', 'YII', 'XYZ']\n", "----------------------------------------------------------------------------------------------------\n", "Number of qubits in the Hamiltonian: 3\n", "----------------------------------------------------------------------------------------------------\n" @@ -422,13 +422,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -457,7 +457,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/introduction/circuit.ipynb b/tutorials/introduction/circuit.ipynb index 3a7f781..c2d03ff 100644 --- a/tutorials/introduction/circuit.ipynb +++ b/tutorials/introduction/circuit.ipynb @@ -25,7 +25,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -50,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -76,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -88,7 +88,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -137,7 +137,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -165,7 +165,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -177,7 +177,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAUsAAACyCAYAAADLXe37AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAWTUlEQVR4nO3db2wT5x0H8G9IfM5iY1o1BCvkD6YvqLIyJkayMVVrxqpqtKxatilSNagGpSVdJVSQBhSqZWyBbWTTSJcFEFEyIF0ibQlbCRnqUgIUlReITs1aqnZbA/HCspLROk5W20n824vWUf46z9l3zsX5fqR7c757fs89F3/t+P6liIiAiIiiWjDbHSAimgsYlkREChiWREQKGJZERAoYlkREChiWREQKGJZERAoYlkREChiWREQKGJZERAoYlkREChiWREQKGJZERAoYlkRECtISXTAQCCAUCplaQ9M0pKen617Pyn2bDzj+ySMZ92VCwzIQCMDj8aC3t9fUOm63G11dXboG0sp9mw84/skjWfdlQsMyFAqht7cXXq8XLpfLlBr9/f3Izc1FKBTSNYhW7tt8wPFPHsm6LxP+bzgAuFwu0wYxXlbu23zA8U8eybYveYCHiEgBw5KISAHDkohIAcOSiEgBw5KISAHDkohIAcOSiEgBw5KISAHDkohIAcOSiEgBw5J0aW1tRTgcVlrW6/Xir3/9q8k9IkoMhiUp6+/vx3PPPYeysrIZA9Pr9eKrX/0qGhoaEtQ7InNZNiw9Hg9++ctfTpq/Zs0alJeXz0KPPrn11NKlS3H8+PHReeFwGI8//jjWrFkDv98/K/1KFJfLhY6ODpw/fz5qYEaCct26daisrDSsfmNjI5xO56TJZrMhJSUFV69eNawWmSsYDCIvLw8HDx4cN7+npwcejwcVFRWz1LMoJIF8Pp8AEJ/PF3W527dvCwBpb28fN39oaEjsdru0trbGXSPW9aqrqyU/P1+CwaCIiDzzzDOyYsUKuX37tmE1puL1euXo0aNSX18vd+7c0b2+kbq7u+Xee++Vp556SkZGRpRfiybWsbl06ZK4XC7Zs2ePaTVUhcNhOX/+vPz617+WV155Rdf2JxPVcT527JhkZmbKwMCAiIj09fVJQUGB7Nixw7AaRrJkWLa1tQkA6evrGze/s7NTAMgHH3wQd41Y1wsGg5Kfny81NTXywgsvSG5urnR3dxtaY6IXX3xRUlNTJSMjQzIyMsRut8vZs2d1tWG0qUIx1qAUiW1szp07JxkZGVJRUWFaDVX9/f1SWFgodrt9dB+tWrVKPvzwQ8NrWZ3qOA8NDcny5culsrJS/H6/FBUVyebNmyUcDhtWw0iWDMsf/ehHkpOTM2n+yZMnZdmyZYbUiGe92tpacTgckpmZKe+8844pNSLee+89SU1NFQDjpoyMjNFP5NkyNhxv3LgRc1CK6B+b5uZmsdvtUlVVZVoNPXbu3Cl2u33cPtI0TZ5++mnDa1mdnnE+ceKELFmyRNatWyclJSUyPDxseA2jKN/8t7+/P/b/9XW2cfXqVfT29iIzM3Pc/I8//hgbNmwwtFasyw8ODmLnzp247777dK2nt9ZLL72EtLQ0jIyMjJsvInj55Zfx6KOP6q5vlEWLFuHll1/G17/+dTQ2NuJb3/oWDh06hIGBAd1t6RmTU6dOYevWrThy5Ai2bNliai09fQoGg+PmhUIhNDU1Gfq77VygZ3w3btyI/fv3IxAIoK2tDampqabVmo7yDYpVUxUTvtnEM830aZCVlSX79u0Tr9c7blq1apVUVlZGXTfyiWNW31paWsTpdMqzzz4rWVlZMjg4qDqEcfdtPkwzjX9NTY1omiZNTU3K487xt+a+jMjOzpaamppZ25eqlL9Z+nw+1UWnFXluRjQ3b97EBx98gIcffhg5OTmj8z/++GNcv34dRUVFSrX0Pv9DpW/t7e3YtGkTmpqasH79erS3t6O6uhq7du1SrqO3b//85z9RWFg46ZtlRkYG/vGPf8DhcOiqbaR//etf2LBhA9auXYvf/e53yM/PR3FxMQ4fPowFC/SdaKEy/ocOHUJ5eTmam5uV/8OYihnPhtm7dy9qa2vHfbu02Wz47ne/i6qqKkNrWZ3Kvozo6enBrVu3UFhYGFMtM5/zM4muOI+Tyu8Mv//978Vms8n//ve/cfMvXLggqampM/5OZ9ZvlleuXJGFCxdKQ0PD6LzGxkbJzMwUv99vSI3pjD3AA8ByB3g+/PBDASBvv/22aQd49u3bJw6HY9IZEkbWiIff75fCwkLRNE0+85nPCABZuXIlD/DM4PTp06Jp2ujZJWbUMIrlwnLXrl1SVFQ0af6BAwdk5cqVhtTQu15nZ6fcfffdUl1dPW7+yMiI3H///XLgwIG4a8zE6/XKr371KwEgN27c0L2+kSYe9R67XWacOnTt2jUBIGlpaeJwOCZNpaWlcdcwQjgclo6ODqmsrBQA8zIoRfSN8969e6WwsNDUGkaxXFjOVg0r982o9Y0wVRhO7FcsgTkXxt9qdawqmfblWJa9goesp7+/f/TKnKNHj077u2Rubu7olT4/+MEPEtxLInPMynPDaW5yuVw4fPgwHnnkkRkP4EQCs6+vL0G9IzIXw5J00XMUOjc3V/moKJHV8d9wIiIFDEsiIgUMSyIiBQxLIiIFDEsiIgUMSyIiBQxLIiIFDEsiIgUMSyIiBQxLIiIFDEsiIgWzcm24Gc9AMaptK/dtPuD4J49k25cJDUtN0+B2u02/uYLb7YamabrWsXLf5gOOf/JI1n2Z0LBMT09HV1cXQqGQqXU0TUN6erqudazct/mA45889O7LyDN79D5PJ9H7MuH/hqenp1v2j9XKfZsPOP7JI5Z96XK5EvfwsRjwAA8RkQKGJRGRAoYlEZEChiURkQKGJRGRAoYlEZEChiURkQKGJRGRAoYlEZGCWbmRhlUFAgFebjeLrDr+evsVucmDnps98O/C+hiWnwoEAvB4POjt7TW1jtvtRldXF98YE1h1/OPpl54bSfDvwvoYlp8KhULo7e3VfTG/HpEbBoRCIb4pJrDq+Fu1X5R4DMsJrH4xf7Kz6vhbtV+UODzAQ0SkgGFJRKSAYUlEpIBhSUSkgGFJRKSAYUlEpIBhSUSkgGFJRKSAJ6XPAT6fD6+88gpu3rwJAGhra0NJSQnsdvss94xo/uA3Swt76623UFZWhqVLl+InP/kJzp07BwDYvXs3cnJy8Pzzz6O7u3uWe0k0PzAsLaqurg5f/OIXMTw8jIsXL6KzsxO//e1vAQCXL19GU1MT3n33XXzuc5/Dq6++Om07fX19OHjwIMLhsFLdU6dO4Y033jBiE4iSCsPSgk6cOIEdO3bg7NmzqK2txRe+8IVxr6ekpOBrX/saWlpa8OKLL+Kxxx7Da6+9NmVbgUAAdXV1KCsrmzEw6+vr8f3vfx9+v9+wbSFKFgxLHQKBAJYuXYrjx4+PzguHw3j88cexZs0aQ0Lm5s2bKCsrQ0tLC4qLi2dc/oknnsAvfvELfOc730EgEJj0ek5ODi5cuIDz589HDcz6+nps374dZ86cwYMPPhjvZpiisbERTqdz0mSz2ZCSkoKrV6/OSr+CwSDy8vJw8ODBcfN7enrg8XhQUVExK/0igwmJiIjP5xMA4vP5oi5XXV0t+fn5EgwGRUTkmWeekRUrVsjt27cNqfH8889LSUnJlK95vV4BIF6vd9z8cDgsK1askJMnT07brtfrlXvvvVeeeuopGRkZGfdaXV2dOJ1O6ejomHEbpqI6dma0cenSJXG5XLJnzx5Taqiuc+zYMcnMzJSBgQEREenr65OCggLZsWOHKf3SIxwOS2trq3zve9+TsrIyef31102pEyuzt98oDMtPqe6wYDAo+fn5UlNTIy+88ILk5uZKd3e3ITUCgYAsXrxY/vKXv0z5+nRhKSJSVVUla9eujVp/qsCMNyhFZi8sz507JxkZGVJRUWFaDdV1hoaGZPny5VJZWSl+v1+Kiopk8+bNEg6HTemXqnA4LE888YTY7XYBIAsWLBCbzSY///nPDa8VK4blHKNnh9XW1orD4ZDMzEx55513DKtx+fJlycrKmvTNLyJaWN6+fVsAyJ07d6L2YWxg1tbWxh2UIrMTls3NzWK326Wqqsq0GnrXOXHihCxZskTWrVsnJSUlMjw8bFq/VL3++utis9kEwLgpLS1N/vOf/xheLxZzJSyVz7PU8zyRuUjv9g0ODmLnzp247777DKvV09ODxYsXY2BgYMrXI7+J+v3+SW3YbDakpaWhu7sbqamp09Z2uVw4c+YMvvKVr6C+vh4tLS1YvXp1XPs3lmfOTNeGilOnTmHr1q04cuQItmzZYmotPctu3LgR+/fvRyAQQFtbW9T9EG8tVa2trVPO1zQNf/7zn1FSUmJ4Tb2M+PuJh/JNnVVTFRM+mZJ1munTraWlRZxOpzz77LOSlZUlg4ODyp9MkU9QTrGPf01NjWiaJk1NTcrjbsT4q37ryc7OlpqamoT1i1P8kyrlb5Y+n0910Tkp8hyUaNrb27Fp0yY0NTVh/fr1aG9vR3V1NXbt2qWr1nTPc/n73/+OBx54AO+++y7uuuuuSa/7fD7k5eWhu7sbixYtGvdaZ2cnHn74Ydy4cSPqc1waGhqwe/du1NXVobS0FPn5+SguLsbhw4exYEFsJ0dExi6e59SojP+hQ4dQXl6O5uZmbNiwIaY6wPTjH2u/Inp6enDr1i0UFhaa3i9VfX19KCgoQDAYHJ23YMECLFmyBG+//bbub79mMOLvJyF0fQQmsZl+N7ly5YosXLhQGhoaRuc1NjZKZmam+P1+Q2qIiKxdu3ba3+Girb9t2zZ58skno9YfezAn0tb169enPUquKhG/We7bt08cDoe0t7ebViPedU6fPi2apo2eKWFmv/R49dVXZfHixaO/XS5fvlyuX79uSq1YzJXfLBmWn4q2wzo7O+Xuu++W6urqcfNHRkbk/vvvlwMHDsRdI6KhoUFWrFghQ0NDyuvfuXNHHA6HXLt2bdp2Jx71HttWtNOKjNqueNq4du2aAJ8clHA4HJOm0tJS0/qpZ529e/dKYWGhctvx9EuvoaEh6ejoEADy0UcfmVYnFgzLOSYRO0ylRiAQkM9+9rNSVlY26bSTqdYPBALy0EMPyTe+8Y1p25zq9KCJbcUTmLN5nqXZNazaLyvX0cuq/ZqIV/BYjN1uR1tbG9ra2rBly5aovxXfunUL69evh8/nw0svvTTlMm+++ebolTnRrggae6XP0aNH490MoqTDsLSgvLw8XLlyBe+//z6ys7Oxbds2XLlyBT09PQCAjo4OlJaWwuPxICsrC+fPn8fChQunbGvVqlV46623lC6dzMnJweXLl/Hkk08auTlESYFhaVHZ2dm4ePEiXnvtNYTDYTz66KMoKCgAAGzbtg3Lli3D9evX0dTUBKfTGbWt/Px85bput5v3ySSaAm/+a3GrV6/G8ePHcfz4cQwNDWFwcBCLFi1CSkrKbHeNaF5hWM4hNpttyvMvich8/DeciEgBw5KISAHDkohIAcOSiEgBw5KISAHDkohIAcOSiEgBw5KISAFPSp/AzFvbJ/ujOYxg1fG3ar8ocRiWn9I0DW63W/mu2LFyu93QNM3UGnORVcffqv2ixGNYfio9PR1dXV0IhUKm1tE0LepjH+Yrq46/VftFicewHCM9PZ1/sLPIquNv1X5RYvEADxGRAoYlEZEChiURkQKGJRGRAoYlEZEChiURkQKGJRGRAoYlEZEChiURkQKGJRGRAl7uSJYRCAR4DbYOescrcncjPXc5SqbxihfDkiwhEAjA4/Ggt7fX1DputxtdXV1zPgDiGS89d1BKlvEyAsOSLCEUCqG3txderxcul8uUGv39/cjNzUUoFJrzb36OV+IxLMlSXC6XaW/+ZMTxShwe4CEiUsCwJCJSwLAkIlLAsCQiUsCwJCJSwLAkIlLAsCQiUsCwJCJSwLAkIlLAsCQiUsCwTHLvvfcevv3tb2NgYGDGZUUEO3fuxOnTp6d83e/347HHHkNXV5dS7fr6euzfv19Xf4msimGZ5HJyctDf34/169dHDUwRwXPPPYfm5mZ8/vOfn3IZp9MJj8eD4uLiGQOzvr4e27dvx4MPPhhP94ksg2GZ5DIyMvCnP/0J6enp0wZmJCj/+Mc/4sKFC/B4PFO2lZKSgsOHD+Ob3/xm1MCMBOWZM2dQXFxs2LY0NjbC6XROmmw2G1JSUnD16lXDaiWDYDCIvLw8HDx4cNz8np4eeDweVFRUzFLP5iiheWFwcFAeeugheeCBB8Tv94vP5xMA8tFHH8n27dslLy9P3n//faW2wuHwuHUibfl8PqmrqxOn0ykdHR26+je2DT0uXbokLpdL9uzZY1oNK1LdlmPHjklmZqYMDAyIiEhfX58UFBTIjh07DKsRj9bWVvnyl78sAGTTpk3S1dVlWq14MSznkbGB2dPTIwCkrKxMV1BGjA3MN998UwDIb37zm5iCUiS2N+a5c+ckIyNDKioqTKthVarbMjQ0JMuXL5fKykrx+/1SVFQkmzdvlnA4bFiNWNXW1oqmaQJAAEhaWprcdddd4vV6TakXL4blPBMJzC996UsCQHJzc3UHZUQkMHNzcwVAzEEpov+N2dzcLHa7XaqqqkyrYWV6tuXEiROyZMkSWbdunZSUlMjw8LDhNfQaGhqSe+65ZzQoI5OmaUrfemeD8s1/9Ty3g6zt5MmTWLNmDYBPfl+85557Yt6/P/7xj/HGG2/A6/Xipz/9KVavXh1TW3rWOXXqFLZu3YojR45gy5YtptayKj3bsHHjRuzfvx+BQABtbW1ITU01rZaqf//73/jvf/87aX4oFMLFixcTuo+Ub56smqqY8AnAiZMZ00zfYmpqakTTNGlqatL9zSDyTSmZJtVvfdnZ2VJTUzPvx2uqSZXyN0ufz6e6KFmUiGDPnj04e/Yszpw5g4yMDDz99NMIBoP4wx/+AKfTqau9hoYG7N69G42NjVi1ahUOHDiAtrY2tLa2YtmyZbraijzvJZpDhw6hvLwczc3N2LBhg672xzLzuTWJojJeET09Pbh16xYKCwtjqmXWeP3whz/E0aNHEQwGR+fZbDZ0dHRg5cqVhteLm66PGpqzJh7Bjph4lFzVVEe9p6uhYqbfx/bt2ycOh0Pa29t1taunxlyiZ1tOnz4tmqZJMBg0rUYshoeHpby8XBYuXCgApKCgIK79azaG5TwwU4jpDcxopwfFGpjR3pjXrl0T4JOjpQ6HY9JUWload425Rs+27N27VwoLC02tEY9wOCyhUMjUGkZgWCY51fBSDUyV8yhjCcxEvDHna1haucZcwit4ktzf/vY3tLW1Rb0yBxh/pU9jY+OUy/T396OiomLGK3PGXunzs5/9LN5NILKEFBGR2e4EmSsUCkHTNOVlI5cPxtuWiGB4eBg2m23GZfv7+7Fo0SL4fD7TDr4kokaicLwST/loOM1dquGmsqyetlJSUpSCkmgu4L/hREQKGJZERAoYlkREChiWREQKGJZERAoYlkREChiWREQKGJZERAoYlkREChiWREQKeLkjWYqZjxNIhsdJTMTxShyGJVmCpmlwu93Kd/+Oldvt1nV9u1VxvBKPdx0iywgEAgiFQqbW0DQN6enpptZIFI5XYjEsiYgU8AAPEZEChiURkQKGJRGRAoYlEZEChiURkQKGJRGRAoYlEZEChiURkQKGJRGRAoYlEZEChiURkQKGJRGRAoYlEZEChiURkYL/A94s1J43bda7AAAAAElFTkSuQmCC", + "image/png": "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", "text/plain": [ "
" ] @@ -218,7 +218,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -230,7 +230,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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wyE3xi/sExEREZFL+fr64o033sCf/vQnfleHmsXihYiIiIhcbtKkSejRowcWLVqkeJkLFy4gODgYmzZtclxg5FZYvBARERGRQ3h5eaGmpqbB/JqaGnh5eVnN0+l0ePvtt7Fy5UqcPHlS0frnz5+PYcOG2SVW0gYWL0RERETkENHR0Thx4oTVPLPZjF9++QU9evRo0P73v/89EhMTkZKSYnPdR48ehclkQkxMjN3iJffH4oWIiIiIHGLatGlYv3498vLycO3aNZSXlyM1NRU6nc7qtsj1vfHGG9i2bRuOHDnS7LpTU1Mxf/58R4RNbswlP1JJRERERG3f5MmTUVlZiRdeeAGnTp2Cj48PBg0ahF27diEoKKjRZbp27YrZs2c3+92X3Nxc9OzZE127dnVQ5OSudCIirg6ClCkrK0NgYCBKS0sdfktZNdw1LldhPtRhvoiI3IdWzsmLFi3Czp074ePjg59++gm+vr5YtWoV7rvvvlattyXbr5WcOYqzt58jL0RERESkKampqUhNTQUApKeno1u3bq0uXEgbWLwQERERkWalp6e7OgRyIhYv9VRWVqK6utqhfej1ev5achPcNf9q46r7cS01P7LF48I5nHGMaV1Lj0Xm1ja+zomIWo/Fy79VVlYiOjoaRUVFDu0nPDwcJ0+e5BvYDdw1/62JKzIy0mFxkXrOOsa0riXHInOrDF/nREStx+Ll36qrq1FUVITCwkKHfdmorKwMkZGRqK6u5pvXDdw1/+4aF6nnjH2pdS09Fplb2/g6JyKyDxYvNzAajXzzdSF3zb+7xkXqcV86DnNLRESOxh+pJCIiIiIiTWDxQkREREREmsDihYiIiIiINIHFCxERERERaQKLFyIiIiIi0gQWL0REREREpAksXoiIiIiISBNYvBARERERkSbwRyo1oLS0FDt27MDp06cBANu3b0diYiK8vb1dHBkRERERkfNw5MWNHTlyBMnJyejcuTMWLFiA3NxcAEBKSgq6dOmCV155Bb/++quLoyQiIiIicg4WL25qw4YNuPvuu3Ht2jXs2bMHhw8fxqZNmwAAX331FbKysvDDDz+gX79++Oyzz5pcz4ULF7B48WKYzWZF/b733ns4cOCAPTaBqF3Ly8tDTEyM4teeIyQmJlrOG20F80pE1L6xeHFD//3f/40XXngBOTk5WL9+Pe666y6r53U6HUaOHIns7GysXLkSDz30EL788stG11VZWYkNGzYgOTnZ5pv9xo0bMWvWLJSXl9ttW4i0LDo6Gj4+PjAYDAgICMDQoUNx6NAhRcs+//zzeP3113HTTddPs2azGfPmzUOnTp1gMBgQFxdnuRS0Menp6fDw8IDBYLBMkydPtmpz/vx5PProowgLC0NQUBCGDBmCL774wvL8woULMXfuXFRWVqrfeAeyZ16zsrIwbNgwGI1G6HQ6m8sr2Q+22rhrXolI+7p169boH0eGDx+O9PR0y/91Op3lipzG2jT2uK1g8aJCZWUlOnfujHXr1lnmmc1mTJ48GQMGDLDLh/7Tp08jOTkZ2dnZGD58uM32//mf/4nly5fj4YcfbvSNtEuXLvj888+xe/fuZguYjRs34rnnnsPWrVtx3333tXYzHCIzM9Pqg1zd5OXlBZ1Oh/z8fJfEVVVVha5du2Lx4sVW88+cOYPo6GgsXLjQJXFR61y4cAGnTp1CXl4eTCYTzp07h4CAAEyfPt3msjt37sSlS5cwZswYy7ylS5ciMzMTX3zxBYqKitC1a1eMGzeu2T8qDBs2DCaTyTJlZmZaPT9r1iycPXsWR48excWLFzFhwgSMHTsWly9fBgD07t0b3bt3xwcffNCyJDiAvfMaHByMWbNmYcWKFYr6V7IfbLVxx7wSUfsSEhKCl156CbW1ta4OxelYvKjg4+ODefPmYdGiRaiurgYA/OEPf8DBgweRm5uLgICAVvfxl7/8BfHx8Rg5cqTiZZKTkxEcHIy//e1vjT5vq4CpX7goKZhcZfLkyVYf5EwmEz755BP4+flh7ty5GDhwoEvi8vb2xquvvoq3334bFRUVAICLFy8iNjYWiYmJePXVV10SVx0RQU5ODqZNm4ann34ae/fudWk8WpGfnw+9Xo+YmBgAgMFgwD333IPz58/bXDY7OxujRo2yjA4AwNq1azFnzhzceuutMBgMWLp0KX744Qd89dVXLY7xp59+wiOPPIKQkBB4eHhg5syZMJlM+Pnnny1tYmNjsWXLlhb3YW/2zuvo0aMxefJkdO/eXVH/SvaDkjbullcial+SkpJQXl5u9Qf19oLFi0ozZswAAGRkZOC1117Dtm3bsHPnToSEhLR63VVVVVi/fj1mzZqlajmdTodZs2ZhzZo1TbZpqoDRSuHSmE8//RRxcXGYM2cOlixZ4tJYkpKSYDQasWbNGphMJowZMwZ333033nzzTZfGJSKYOnUqJkyYgE2bNuG//uu/cN9992Hp0qUujUsLvvvuO9x5553w9vaG2WzG119/jdWrV2PKlCk2lz1w4AD69OljeVxaWorTp09jwIABlnlBQUG45ZZbmr1cat++fQgNDUVUVBQeffRRnDx50ur5lJQUZGdno6ioCDU1NXj33XfRs2dPq7779u3rslHJxtgzr2op2Q9K95W75ZWI2hdfX1+88cYb+NOf/oSysjJXh+NULF5U0uv1eO211/Dyyy9j7dq12LFjByIjI+2y7n379kGn02HEiBGql3300Uexd+9eXLp0qck2NxYwGRkZmi1csrOzkZCQgCVLliA1NdXV4cDT0xNpaWlYvnw5EhISLJcXKrkG35G+/fZbZGZmoqqqCsD1yxxramqQmpqK4uJil8bm7vLz83Ho0CEEBQXB29sbI0aMwCuvvKKoUL506RICAwMtj+veWIKCgqzaBQUFNfmm8/DDD6OgoADFxcXYu3cvPD09MWrUKJhMJkubIUOGwMvLCzfffDN8fX3x1ltvYdOmTVa3UTcajSgpKVGz6Q5lz7yqpWQ/KN1X7pZXImp/Jk2ahB49emDRokU224oInn32Wfz+97/HoEGD8M477zghQsdQ/Dsvbb2qU7t9FRUVmD17Nnr16mW3vs6cOYPQ0FCrDyf11X2npry8vME6vLy84OnpiV9//RUeHh5N9m00GrF161bce++92LhxI7KzsxETE9Oq/Xvjm35r1qHEe++9hyeffBJr1qxBUlKSQ/tS03bKlCmYP38+KisrsX379mb3Q2v7Umrbtm2Nztfr9fjkk0+QmJho9z7Vssfxo6YfpfLz85GRkYEpU6agpKQECQkJOHjwoKKCtEOHDigtLbU8NhqNAGA1DwAuX75see5G9UcYIiIikJGRgcDAQHzzzTeIjY2F2WzGyJEjcf/996OkpAQBAQHIyclBfHw8vvzyS/Tt29ey3R06dFC17Wpzpaa9PfOqlpL9oHRftSSvdcsRuTMeo9c56rOCLV5eXqipqWkwv6amBl5eXlbzdDod3n77bdx///1ITk5udr3//Oc/8f333+Pbb7/FtWvXcNttt2HatGlNvge1hD3yoCgeUQhAu5hKS0ubzUN2drYYDAZ55plnJCwsTCoqKpSmUEpLS12+fe4+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", "text/plain": [ "
" ] @@ -275,7 +275,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -287,7 +287,7 @@ }, { "data": { - "image/png": "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7TC3RERE1sELhxAREREREWkIizQiIiIiIiINYZFGRERERESkISzSiIiIiIiINIRFGhERERERkYawSCMiIiIiItIQFmlEREREREQawiKNiIiIiIhIQ/hj1o1AQUEBdu3ahTNnzgAAtm/fjpiYGLi6ujo4MiIiIiIisjbOpGnY8ePHkZCQgHbt2uHVV1/Fzp07AQCJiYlo3749Xn75ZZw9e9bBURIRERERkTWxSNOodevWoX///qioqMC+fftw7NgxrF+/HgDw5ZdfYvPmzTh58iR69OiBzz//vNZ+Ll++jNdeew1Go1HRuO+//z4OHz5sjV0gataysrIQHh6u+LFnCzExMabnjaaCeSUiouaARZoGvffee3jhhReQmZmJNWvW4J577qm2XqfTYdiwYcjIyMDSpUvx4IMPYv/+/Wb7MhgMWLduHRISEiy+qUlLS8O0adNQVFRktX0hasxCQ0Ph5uYGLy8veHt7Y9CgQTh69KiibadPn4558+ahRYubT7NGoxGzZs1CmzZt4OXlhaioKNNHmM3ZvHkzBg8eDB8fH+h0OrNt5syZAycnJ3h5eZluEydONK2fP38+kpKSYDAYlO+0HVgzr0rydCslx8FSG63mlYgav44dO5r9I1BERATmzJlj+r9OpzN9wspcG3P3qXFhkaaCwWBAu3btsHr1atMyo9GIiRMnok+fPlYpbs6cOYOEhARkZGQgIiLCYvv//d//xeuvv46HHnrI7BuG9u3bY+/evdizZ0+dhVpaWhqee+45bN26FUOGDGnobthEenp6tTejVTcXFxfodDpkZ2c7JK7S0lJ06NABr732WrXl586dQ2hoKObPn++QuKhhLl++jNzcXGRlZaG4uBi//fYbvL29MXnyZIvbfvbZZ7h69SpGjRplWpaamor09HR88cUXuHDhAjp06ICxY8fW+phs1aoVpk2bhiVLltQ51uDBg1FcXGy6paenm9Z169YNnTp1wqZNm5TttB1YO69K81RFyXGw1EaLeSWi5sXf3x8vvfQSKisrHR0K2QiLNBXc3Nwwa9YsLFiwAGVlZQCAZ555BkeOHMHOnTvh7e3d4DHeeecdjBw5EsOGDVO8TUJCAlq1aoV//etfZtdbKtRuLdCUFIaOMnHixGpvRouLi7Fjxw54eHggKSkJffv2dUhcrq6umD17Nt566y2UlJQAAK5cuYLIyEjExMRg9uzZDomrioggMzMTcXFxeOqpp3DgwAGHxtNYZGdnQ6/XIzw8HADg5eWF++67DxcvXrS4bUZGBoYPH26a7QGAVatWYebMmbjzzjvh5eWF1NRUnDx5El9++aXZPkaMGIGJEyeiU6dODdqPyMhIbNmypUF9WJO186o2T0qOg5I2WssrETUv8fHxKCoqqjZxQE0LizSVnnjiCQDA2rVr8corr2Dbtm347LPP4O/v3+C+S0tLsWbNGkybNk3VdjqdDtOmTcPKlStrbVNbodZYCjRzPv30U0RFRWHmzJlYuHChQ2OJj4+Hj48PVq5cieLiYowaNQr9+/fHG2+84dC4RASTJk3C+PHjsX79erz77rsYMmQIUlNTHRpXY/Dtt9+iV69ecHV1hdFoxFdffYUVK1YgNjbW4raHDx9G9+7dTfcLCgpw5swZ9OnTx7SsZcuWuOOOOxR/zK82Bw8eREBAAEJCQvDII4/g9OnT1daHhYU5bJbZHGvmVS0lx0HpsdJaXomoeXF3d8eiRYvwt7/9DYWFhY4Oh2yARZpKer0er7zyCv76179i1apV2LVrF4KDg63S98GDB6HT6TB06FDV2z7yyCM4cOAArl69Wmub2wu1tWvXNtoCLSMjA9HR0Vi4cCGSk5MdHQ6cnZ2RkpKC119/HdHR0aaPxSr5jowtffPNN0hPT0dpaSmAmx/PLS8vR3JyMi5duuTQ2LQuOzsbR48eRcuWLeHq6oqhQ4fi5ZdfVvQHgatXr8LX19d0v+oFtGXLltXatWzZskEvrg899BBycnJw6dIlHDhwAM7Ozhg+fDiKi4tNbXx8fJCfn1/vMazNmnlVS8lxUHqstJZXImp+Hn74YXTu3BkLFiyw2FZE8Oyzz+Lee+9Fv3798Pbbb9shQmoIxb+T1tSrdLX7V1JSghkzZqBr165WG+vcuXMICAio9gbrVlXfeSsqKqrRh4uLC5ydnXH27Fk4OTnVOraPjw+2bt2K+++/H2lpacjIyEB4eHiDju/tb24a0ocS77//PqZMmYKVK1ciPj7epmOpaRsbG4u5c+fCYDBg+/btdR6Hho6l1LZt28wu1+v12LFjB2JiYqw+plrWOH/UjKNUdnY21q5di9jYWOTn5yM6OhpHjhxRVHj7+fmhoKDAdN/HxwcAqi0DgGvXrpnW1cets0pt27bF2rVr4evri6+//hqRkZEAbu63n5+fqn7V5kpNe2vmVS0lx0HpsapPXqu2I9IynqM32eq9giUuLi4oLy+vsby8vBwuLi7Vlul0Orz11lt44IEHkJCQUGe///3vf/Hdd9/hm2++QUVFBe666y7ExcU16DXodo7KmT1ZI26lOVdcpDXkr5dNyZYtW/D888/j6aefxjvvvIOkpCR4eHio6sPSzJulXN999921ruvVq5eqWB588EFV7etirRnFuqxcuRLPP/88NmzYgL/85S/16sNWcbZo0QIGgwGxsbH1+qFxe+SvyvXr1zFp0iRMmjTJbmNaYs/9t+TMmTO4dOmS6XtTfn5+mD17NqKjo/HGG2+gVatWEBHcd999SEtLg5+fHx566CG888476Nq1K+655x7k5OSY+vP19UVISAgOHjxo+hhdQUEBfv75Z9WP2brodDrodDqIiGnZ8ePHq310TwlbHQtr51UtJcdB6bGqT14BbZ3nRFQ7Rz1WQ0ND8eOPP1ZbZjQa8csvv6Bz58412t97772IiYlBYmJinf22b98eer0eZWVluHHjBlxdXaHX660ae3N4frPGPt76Gl0XxUVaQ/562RgUFhZaTPzu3bvx2GOPYfPmzRg5ciR2796NZcuWYebMmarGysvLM1tF//jjjxg0aBBOnjxZ46M2wM1j0KFDB5w9e7ZGIXfs2DFERkYiNzcXbm5utY69ceNGJCYmYt26dZgwYQJCQkIQERGBJUuWVPsyvhpVuattv9T0UZfU1FSkpKTgww8/xJgxY+o1DlB7/usbV5Vz587h/Pnz9b6ASUPyV5vLly/j7rvvNn3cEbhZTLZp0wY5OTmqZ/tswRrnj5pxlMjOzoanp2e1mfJhw4bB3d0dW7ZsQXx8PHQ6HVJTU/Hiiy/i+vXrWLJkian9uHHjEBcXB6PRaHpcJSQkYPHixRg6dCjatWuHxMREdOnSBYMGDTIbQ2VlJcrLy00XKaq6eqterzf1+Y9//ANDhw5FQEAALl26hMTERAQEBGDgwIGmfnbt2qV6xlntsVCaW1vkVUmebqXkOChpU5+8ArZ5nBNZk5rnyqbMVu8VLImLi8PTTz+NkSNHYvDgwbhx4wZee+016HQ6REVFmd1m0aJF6Nq1Kzw8PGr9+krr1q3xxz/+EXfccQdKS0uRkpJS5/vF+nBUzuzJrs/hQiIiUlBQIACkoKDA7PoDBw6It7e3bNy40bQsPT1d/P39paioyCpjiIgMGDBA3n77bdXbT506VSZPnlzn+OvWrRMvLy/Jysoy9XXixAnp3LmzPPHEE1JZWaloP9TEZa0+kpOTxdPTU3bv3m2zMRq6zZYtW0Sv10tpaanN41Lj888/l4CAAHFxcREA0qlTJzlx4oRNxqoPW+9/fcaZOXOmDBw4sMbyRx99VEaMGGG6n5+fL4GBgbJ8+fIabXv06CFbt2413a+srJSkpCQJCAgQDw8PiYyMlNOnT5vWT506VaKiokz309LSBECNW1ZWlqnN2LFjxd/fX9zd3aVt27by8MMPy48//mhan5OTI4GBgXL9+nWL+yxS/2OhdDtb5NVSnm7Pq6XjoKSN2ryK2O88J2qo5n6u2vq9ghLr1q2Tnj17iq+vr7Rp00bGjh0rOTk5pvVDhgyRlJSUatskJycLgGrLb223c+dOGT16tJSXl0tJSYncc889cubMGavEq4Wc2Zoj4mWR9n/qSv6xY8ekVatWsmzZsmrLKysrpXv37rJgwYIGj1Fl48aNcuedd0p5ebni7fPz88XT01MOHTpUa7+3Fmi395WXl9egQs3WRdqhQ4cEgDg7O4unp2eN24QJE2wWp5ptZs2aJX379lXcd0PiUqu8vFyysrIEgFy7ds1m49SHFos0JYqLi2X48OHywQcfSL9+/Wo8dvbs2SO9e/eu9x8/rCEmJkbWrVunuL2tizQlmmJeRRrfGxJqvpr7udpUC46dO3dKbGysiIgYjUa577775Pjx41bpu6nm7FYs0hzIHslXMobBYJBu3bpJQkKCGI1Gi9sbDAYZPny4jB07ttY+by/QzPXVkELNHjNp1qDVJ5HGWqRYS2Pcf4PBIKNGjTLN7D777LOSlpbW4H4dzdFFWlPNq4h2H39Et2vu56pW3ys0VGVlpUyePFkGDhwoffv2lcTERKv13VRzditHxKv4O2lkH66urti+fTsGDx6M+Ph4LFmypNYLiZw/fx6xsbEoLi5GRkaG2Tb//e9/FV1mv+ry/BEREVi1apXq32ojak5cXV2RmZlpur906VIHRtN0MK9ERLbRokULrFmzxtFhkAr8nTQN6tChAw4cOIBffvkFbdu2xdSpU3HgwAGcO3cOAJCVlYUJEyYgNDQUgYGB2LNnD7y9vc321bNnTxw/flzR76C1b98eX375JSZPnmzN3SEiIiIiIhVYpGlU27ZtsW/fPuzfvx9GoxGjR482XXp/6tSp6NixI06cOIHNmzfDy8urzr5CQkIUjxsUFFSvy8cTEREREZF18OOOGhceHo7Vq1dj9erVKC8vR0lJCXx9fRX98CsRERERETU+LNIaERcXF7O/n0ZERERERE0HP+5IRERERESkISzSiIiIiIiINIRFGhERERERkYawSCMiIiIiItIQFmlEREREREQawiKNiIiIiIhIQ1ikERERERERaQiLNCIiIiIiIg3hj1nfprCwsFH23VRoNf9ajYvUY75r19DcMLe1Y26osWmu52xz3W9HaSz5dkScLNL+j16vR1BQEIKDg206TlBQEPR6vU3HaIy0mn+txkXq2etYNnb1OReZW2X4OKfGgI9nPlbtoTGeZ/Y+L1ik/R83NzecPn0aZWVlNh1Hr9fDzc3NpmM0RlrNv1bjIvXsdSwbu/qci8ytMnycU2PAxzMfq/bQGM8ze58XLNJu4ebmxgelA2k1/1qNi9TjsbQd5pao6eDjmeyB51ndeOEQIiIiIiIiDWGRRkREREREpCEs0oiIiIiIiDSERRoREREREZGGsEgjIiIiIiLSEBZpREREREREGsIijYiIiIiISENYpBEREREREWkIizQiIiIiIiINYZFGRERERESkIc6ODoCoisFgQFlZmU3H0Ov1cHNzs+kY9qI2X4WFhdX+VaIp5QuwzznW2DW1Y05ERNQYsUgjTTAYDAgNDcWFCxdsOk5QUBBOnz7d6N+ENiRfwcHBits2lXwB9jvHGrumdMyJiIgaKxZppAllZWW4cOEC8vLy4OPjY5MxCgsLERwcjLKyskb/BpT5Us8eOWvsmtoxJyIiaqxYpJGm+Pj48A20CsyXeswZERERaR0vHEJERERERKQhLNKIiIiIiIg0hEUaERERERGRhrBIIyIiIiIi0hAWaURERERERBrCIo2IiIiIiEhDWKQRERERERFpCIs0IiIiIiIiDWGRRkREREREpCEs0oiIiIiIiDSERVoTd+rUKYwfPx7FxcUW24oIZsyYgS1btphdX1RUhAcffBCnT59WNHZaWhrmzp2rKl6ipiIrKwvh4eEwGo0OiyEmJgbr16932PhERERUPyzSmrj27dujsLAQI0eOrLNQExE8//zz+PDDD9GrVy+zbby8vBAaGoqIiAiLhVpaWhqee+45DBkypCHhEzlUaGgo3Nzc4OXlBW9vbwwaNAhHjx5VtO306dMxb948tGhx82l2/vz56Ny5M3x9feHv748RI0bU2dfFixfxyCOPIDAwEC1btsTAgQPxxRdfmNbn5+dj8uTJaNu2Lby9vREdHY1ff/21Wh/z589HUlISDAaD6n0nIiIix2GR1sR5eHjg448/hpubW62FWlWB9tFHH2Hv3r0IDQ0125dOp8OSJUvw5z//uc5CrapA27p1KyIiIqy2L+np6fDy8qpxc3FxgU6nQ3Z2ttXGagpKS0vRoUMHvPbaa9WWnzt3DqGhoZg/f76DImscLl++jNzcXGRlZaG4uBi//fYbvL29MXnyZIvbfvbZZ7h69SpGjRplWjZhwgQcPHgQBQUFOH/+PCIjIzFy5MhaZ9qmTZuG8+fP48SJE7hy5QrGjx+P0aNH49q1awCAxx9/HJcuXcKJEyfw22+/wcPDA2PHjq3WX7du3dCpUyds2rSpYckgIiIiu2KR1gzUVagpLdCqWCrUbFWgAcDEiRNRXFxc7bZjxw54eHggKSkJffv2tep4jZ2rqytmz56Nt956CyUlJQCAK1euIDIyEjExMZg9e7aDIwQyMzMxcuRIAMAzzzyD3NxcxwZ0i+zsbOj1eoSHhwO4OZN833334eLFixa3zcjIwPDhw02zaADQpUsXtGrVCsDNx52TkxMuXLiAgoICs3389NNP+J//+R/4+/vDyckJU6dORXFxMX7++WeUlJQgMzMTKSkpaNmyJby8vPDqq6/i6NGj+Oqrr6r1ExkZWetHmImIiEibWKQ1E7UVaklJSYoLtCq3F2pVb6w3btxoswLNnE8//RRRUVGYOXMmFi5caPPxGqP4+Hj4+Phg5cqVKC4uxqhRo9C/f3+88cYbjg4Na9euxbhx4/D1118DuDlT2rt37xof2XOUb7/9Fr169YKrqyuMRiO++uorrFixArGxsRa3PXz4MLp3715jeWZmJlq2bAk3NzfMmDEDM2bMMBVut0tMTERGRgYuXLiA8vJyLF++HF26dEH37t0hIgBg+vfW/x85cqRaP2FhYZxlJiIiamScHR0A2U9VoRYdHY3x48cDuPmmcd++fYoLtCpVhRoAjBkzBsDNN5X2KtAyMjLwyCOPIDU1Fc8995zNx2usnJ2dkZKSgpkzZ2LHjh1o164dVq9eDZ1O59C4KioqkJiYiLKysmrLrl+/jjfffBNvvvmmA6O7KTs7G0ePHkXLli1RUlKCFi1a4PXXX8czzzxjcdurV6/C19e3xvKqjyvm5+fjvffeQ4cOHWrtY+DAgdiwYQP+8Ic/wMnJCa1bt8ZHH30EV1dXuLq6YujQoUhJScH7778PZ2dnJCcnQ6fToaioqFo/Pj4+yM/PV58AIiIichjFRVphYaEt4yA72rBhA/r06QPg5scTW7duXe/jO2/ePBw+fBh5eXlYuHAhwsPD69WXmm3ef/99TJkyBStXrkR8fLxNx9IqNfsQGxuLuXPnwmAwYPv27XBycrLZWEr99ttvuHLlSo3lZWVl2Ldvn03GVNtndnY21q5di9jYWOTn5yM6OhpHjhxRVOD6+fnV+jHGqvXTp09Hq1at0LVrV3Tr1q3aeqPRiGHDhuGBBx5Afn4+vL29TR8N3b9/P8LCwrBx40a89NJL6NGjB3Q6Hf76179i586d8Pf3r7Hffn5+qva9KTxGiIjshc+ZNzEPyvj4+ChrKAoB4I03m98KCgrqPA9XrFgher1eNm/erPTUNSkoKHD4/tk7X1Xatm0rK1asaPb5Upqz3NxcASA5OTmmZTt37hRXV1fJz88XERGj0SgDBgyQH374QS5duiT333+/fP/99yIiMm3aNImLi6tzjPLycnF3d5ctW7bUWHf58mUBIMeOHau2vHfv3vL666+b7e/YsWMCQH744Ydqy+fMmSOjR4+2uM8iTfeY88Ybb7zZ46b0Nbmp4WuHuptSimfS6vqrMDUOIoKkpCRkZmZi69at8PDwwJNPPonS0lL8+9//hpeXl6r+Nm7ciMTERKSnp6Nnz55YsGABtm/fjm3btqFjx46q+iosLERwcHCdbVJTU5GSkoIPP/zQ9BHL+sjLy1P+VwyNUpKvKufOncP58+frfWEVW+Xrb3/7G1atWoXS0lLTMhcXF2RlZSEsLMzq46nJWXZ2Njw9PdG1a1fTsmHDhsHd3R1btmxBfHw8dDodUlNT8eKLL+L69etYsmSJqf24ceMQFxcHo9FounjI0qVLMWHCBAQFBeH3339HcnIyXF1dMWDAgBrjt27dGnfddReWLVuGxYsXw8vLC9u2bUNOTg7uueceAMDJkyfRunVrtG7dGidOnEBcXBwmT56MO++8s1pfu3btUj3j3BQeI0RE9qLm9aUp42uHldmuriYtMRqN8txzz0mHDh3kl19+MS0vKSmR4cOHy6BBg6SoqEhxf+vWrRMvLy/JysqyOIYSVX+Fqe2vUMnJyeLp6Sm7d+9W1a+aMRoTNfuyZcsW0ev1UlpaarMx6qOiokJSUlLE29tbAMjdd9/doONriZr9mTlzpgwcOLDG8kcffVRGjBhhup+fny+BgYGyfPnyGm179OghW7duNd2Pjo6WNm3aiIeHhwQFBcmDDz4ohw4dMq2fOnWqREVFme6fOnVKoqOjJSAgQLy9vaV79+6yevVq0/q1a9dK27Ztxd3dXUJCQmTu3LlSUVFRLYacnBwJDAyU69evW9xnkab1GCEispfm/tzZ3PffVlikNQOWiie1hZq5Ak3pWLWp6wF+6NAhASDOzs7i6elZ4zZhwoQGj9HYqNmXWbNmSd++fW06RkMYjUYpKyuz6Rgi1t+f4uJiGT58uHzwwQfSr18/qaysrLZ+z5490rt37xrL7SkmJkbWrVunuH1TeowQEdlLc3/ubO77bys6kVuu4UxNjij8HbTr168jOjoaBoMBO3bsqPWjj0p+B03pmLcqLCyEr68vCgoKbDZVbo8x7IX5Us+a+1NaWopx48ZhxowZGDZsGJ577jmEh4dj0qRJ1gnWQZraMScisofm/tzZ3PffVvg7aU3cd999h+3bt1sslm79HbX09HSzbQoLCzF//nyLl9m/9XfUFi1a1NBdINIcV1dXZGZmYtiwYQBuft+ssRdoREREpB38nbQmrkePHsjJyYFer7fY1sPDA5mZmXBxcTG73sfHB99//72ivqoKtYqKCtUxExERERE1ZyzSmgElRZXStmr60ul0tRZ8RERERERkHj/uSEREREREpCEs0oiIiIiIiDSERRoREREREZGGsEgjIiIiIiLSEBZpREREREREGsIijYiIiIiISENYpBEREREREWkIizQiIiIiIiINYZFGRERERESkISzSiIiIiIiINMTZ0QEQ3aqwsLBR9u0ozJd6TXW/rIG5ISKqv+b6HNpc99vWWKSRJuj1egQFBSE4ONim4wQFBUGv19t0DHtgvtSzV84au6Z0zImI7IGvL3ztsAWdiIijgyACAIPBgLKyMpuOodfr4ebmZtMx7IX5Us8eOWvsmtoxJyKyh+b++sLXDutjkUZERERERKQhvHAIERERERGRhrBIIyIiIiIi0hAWaURERERERBrCIo2IiIiIiEhDWKQRERERERFpCIs0IiIiIiIiDWGRRkREREREpCEs0oiIiIiIiDSERRoREREREZGGsEgjIiIiIiLSEBZpREREREREGsIijYiIiIiISENYpBEREREREWkIizQiIiIiIiIN+X81GsQGJpto5AAAAABJRU5ErkJggg==", + "image/png": "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UcnvoCnts6K8vDy4u7sjNzfXYkPl1ujDWpgv05lzf4qLizF69GjMnDkTQ4YMwauvvorAwEBMnDjRPMHaSFM75kRE1tDcXzub+/5bCm/B38T9+OOP2LlzZ53FUsXb88fHx1fbJi8vDwsXLqzzNvsVb8+/dOnShu4Ckeo4OjoiKSkJQ4YMAXDn780ae4FGRERE6qH4xiHUOHXv3h1paWnQarV1tnVxcUFSUhIcHByqXa7X63H69GlF2yov1G7fvm1yzEREREREzRmLtGZASVGltK0p29JoNDUWfEREREREVD1e7khERERERKQiLNKIiIiIiIhUhEUaERERERGRirBIIyIiIiIiUhEWaURERERERCrCIo2IiIiIiEhFWKQRERERERGpCIs0IiIiIiIiFWGRRkREREREpCIs0oiIiIiIiFTE3tYBEFWUl5fXKLdtK8yX6ZrqfpkDc0NEVH/N9TW0ue63pbFII1XQarXw8fGBn5+fRfvx8fGBVqu1aB/WwHyZzlo5a+ya0jEnIrIGvr/wvcMSNCIitg6CCACKiopQUlJi0T60Wi2cnJws2oe1MF+ms0bOGrumdsyJiKyhub+/8L3D/FikERERERERqQhvHEJERERERKQiLNKIiIiIiIhUhEUaERERERGRirBIIyIiIiIiUhEWaURERERERCrCIo2IiIiIiEhFWKQRERERERGpCIs0IiIiIiIiFWGRRkREREREpCIs0oiIiIiIiFSERRoREREREZGKsEgjIiIiIiJSERZpREREREREKsIijYiIiIiISEX+D2vRoEIR7QXMAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -315,7 +315,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -327,7 +327,7 @@ }, { "data": { - "image/png": "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Y+MqLCzU+9dccZHxLLGNNXb13RaZW8P4OiciahiVSiXpSuBSpaWlYevWrXj88ceRnp6OFi1aGHWbJGp8WPz+V0lJCQIDA5Gbm2vWcXx8fHDhwgV+ALqPrea/IXH5+fmZLS4ynqW2scauPtsicysNX+dERLZl5MiRKCkpsXYYZEEsfv+rrKwMubm5yMnJgVqtNssYhYWF8PPzQ1lZGT/83MdW82+rcZHxLLEuG7v6bovMrWF8nRMREVkfi9/7qNVqfnizIlvNv63GRcbjujQf5paIiIhsGS94RURERERERLLH4peIiIiIiIhkj8UvERERERERyR6LXyIiIiIiIpI9Fr9EREREREQkeyx+iYiIiIiISPZY/BIREREREZHssfglIiIiIiIiPdnZ2Zg0aZK1wzApe2sHQIYVFBRg9+7duHjxIgBg586diIyMhEqlsnJkREREREREjQOP/Nqw06dPY9q0aWjdujXeeecdpKenAwBiY2PRpk0bvPXWW7h06ZKVoyQiIiIiIjmZPn06xo0bh/T0dISGhuLIkSPWDskkWPzaqA0bNqB37964e/cuDhw4gFOnTmHTpk0AgEOHDiElJQXnzp1D165d8e2339baz40bN/Duu+9Cq9VKGnfz5s04fvy4KRaBqEnLyMhAcHCw5NeeOURGRureN+SCeSUiIjK/VatWISUlBeHh4di/fz969epl7ZBMgsWvDfrXv/6F119/HWlpaVi3bh0ee+wxvecVCgUGDx6M1NRULF++HE899RQOHjxYY18lJSXYsGEDpk2bZvDD4saNGzF9+nQUFRWZbFmIGrPAwEA4OjrC1dUVbm5uCAkJwcmTJyXNO3PmTMyfPx/Nmt17m9VqtZgzZw5atWoFV1dXhIeH637KUJOUlBT0798farUaCoWixjaJiYmws7ODq6ur7jF+/Hjd8wsWLEBcXBxKSkqkL7QFmDKvUvJUlZT1YKiNreaViBq/tm3b1vjlWmhoKBITE3X/VygUujMCa2pT098kPykpKQgNDUXz5s3RsmVLhISE4JtvvtFrExgYCCcnJ73PChMnTsTXX3+tN02hUOi16969u5WWyrxY/BqhpKQErVu3xtq1a3XTtFotxo8fjx49epikaLx48SKmTZuG1NRUhIaGGmz/v//7v1i6dCmeeeaZGj+ItWnTBvv378e+ffvqLIA3btyI1157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", + "image/png": "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UmNYaVRUFKKiopCSkoKoqCjs2rULW7duxbBhw2otU9vfRI21fPly5ObmIiUlBevXr3d2c8gBHJr8enp64sSJE6ioqLBrPVqtFp6enlat48ptaw4Yf/Ww9lgWFxcjLCwMeXl50Ov1iuux9lg6qo81da78/tnUsc+SMzSV815gYCBeeOEFPPDAA3Bzc3N2c8hF7N+/H3PnzsU333yDsrIyRERE4IknnsALL7wAd/fraUxUVBS+++47sy95BgwYgK1bt8LX19c0r6KiAteuXYOXl5dp3tGjRx23M+QSHD7s2dPT02XfhF25bc0B468eDTmWer3equS3IdjH7IextQ/GlZqL+Ph4pKWlYdWqVZgyZYqzm0MuYMeOHRgxYgSmT5+O9957D61atcL333+PJ598Env27ME///lPaDQaAMDs2bNrHRFgMBhM/09JScHOnTuxc+dOszK5ubl23AtyNbzhFRERERE5lZeXFxYtWoRXXnmFv1UmAMAzzzyDMWPGYNGiRabh+/fddx8+++wzbNmyBZ988omzm0hNEJNfIiIiInK6cePGoWPHjliwYIHidc6fP4+AgAD+XlNlfv75Z/z888+1PoLotttuQ+/evbFp0yab1OXp6YnOnTvbZFvk+pj8EhEREZFdeHh4oLKyssb8yspKeHh4mM3TaDR466238M477+DEiROKtj937lwMGDDAJm0l13Hu3DkAQNu2bWtd3q5dO5w9e9b096JFi+Dv72+a0tPTFdcVEhKCxMTExjWYmgwmv0RERERkF5GRkfjll1/M5hmNRvz73/9Gx44da5S/5557MGrUKCQkJFjc9tGjR2EwGNCzZ0+btZdcQ1BQEADg1KlTtS7/448/EBwcbPo7MTERly5dMk2jR49WVE9OTg769++PAQMGoH///sjOzm5848mlMfklIiIiIruIi4vD6tWrkZWVhatXr6KkpARJSUnQaDRmjzWqbtGiRdi8eTOOHDlS77aTkpIwd+5cezSbnKxTp064+eab8f7779dY9tNPP2Hv3r2Ijo5udD1BQUHYvHkzdu/ejffeew/Tp09v9DbJtTn8bs9ERERE1DyMHz8eZWVleP7555GbmwtPT0/07t0b27dvh7+/f63rhIeHY8aMGfX+9jczMxOdOnVCeHi4nVpOzrZ8+XKMHDkS7dq1w/Tp09GqVSv88MMPePLJJ9G7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", "text/plain": [ "
" ] @@ -356,7 +356,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -368,7 +368,7 @@ }, { "data": { - "image/png": "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0+Hee+9F3759ERUVxd9EdxGenp748MMPERoaij/++MNi/VZUVBhrER8fH+h0Oot/xIOsR/Fn8sk2dDodtm7digEDBiAhIQFLliyp9yejzp49i4kTJ0Kv1yMrK6vONt9++62in8mrKfSjo6OxcuVKJCYmWmJ1iFySTqfDli1bjH8vXbrUjtG4DuaViMg6WrRogdWrV9s7DLKSW265BampqRbt8/jx45g+fTpatGiB8vJyzJ8/HzqdzqJjkPWwyHdAYWFh2Lt3LyZMmIB27dph4sSJmDx5svHL+HJycvDee+/h448/RlxcHD755BP4+vrW2dcdd9yB77//Hh07djQ7bocOHfDll1+iVatWllwdIiIiIiJyIhEREfjiiy/sHQY1Em/Xd1Dt2rXD7t27sWfPHhgMBowaNQq33347AGDq1Kno1KkTjh07hszMzHoL/BpKCvwaISEhPEtHRERERETkpHgl38FFRkZi1apVWLVqFSorK1FaWoqAgAB+rpqIiIiIiIhqYZHvRDw8PIy37BMRERERERHdiLfrExEREREREbkIFvlERERERERELoJFPhEREREREZGLYJFPRERERERE5CJY5BMRERERERG5CBb5RERERERERC6CRT4RERERERGRi2CRT0REREREROQi3O0dgKMpLi52yr5dhaPm31HjIvWY7/o1NTfMbf2YG3I2zXWfba7rbS/Okm9niZOoBov8/6PVahESEoLQ0FCrjhMSEgKtVmvVMZyRo+bfUeMi9Wy1LZ1dY/ZF5lYZPs/JGfD5zOeqLTjjfsb9gpwJi/z/4+npiZMnT6KiosKq42i1Wnh6elp1DGfkqPl31LhIPVttS2fXmH2RuVWGz3NyBnw+87lqC864n3G/IGfCIv86np6efPLakaPm31HjIvW4La2HuSVyHXw+ky1wPyNH8sEHH2DFihX49ttv0aJFC9x222144YUXMHz4cHuH1ij84j0iIiIiIiJqdgwGAyZPnoyUlBQkJSXh/Pnz+O233zBp0iSMHDkSGzdutHeIjcIr+URERERERNTsLFy4EJ9++ikOHjyIm266yTh/6tSp2L59O1599VXExcXZMcLG4ZV8IiIiIiIialYKCgqwePFipKSkmBT4NW699Vbk5+fbIbKmY5FPREREREREzcr27dtx5coVTJgwoc7H8/Ly6iz+nQGLfCIiIiIiImpWzp49C29vb7Rp06bWYyUlJdi6dStiY2PtEFnTscgnIiIiIiKiZiUsLAxXrlzB2bNnaz32wgsvICAgANOnT7dDZE3HIp+IiIiIiIialdGjR+OWW25BQkICTp8+DQD49ddf8eSTT+KDDz7Apk2b4O/vb+coG4dFPhERERERETUrnp6e2LNnD0JDQzFgwAD4+vpi6NCh8Pb2xrfffouePXvaO8RG40/oERERERERUbPTtm1brFq1yt5hWByv5BMRERERERG5CF7JJ4dRVlaGiooKq46h1Wrh6elp1TFsRW2+iouLTf5VwpXyBdhmH3N2rrbNiYiIiJobFvnkEMrKyhAeHo5z585ZdZyQkBCcPHnS6YuYpuQrNDRUcVtXyRdgu33M2bnSNiciIiJqjljkk0OoqKjAuXPnkJ+fb7VvsSwuLkZoaCgqKiqcvoBhvtSzRc6cnattcyIiIqLmiEU+ORR/f38WYCowX+oxZ0RERETkyvjFe0REREREREQugkU+ERERERERkYtgkU9ERERERETkIljkExEREREREbkIFvlERERERERELoJFPhEREREREZGLYJFPRERERERE5CJY5BMRERERERG5CBb5RERERERERC6CRT4RERERERGRi2CR7+JOnDiBcePGQa/Xm20rIpg5cyY2btxY5+MlJSV44IEHcPLkSUVjr1u3DvPmzVMVL5GryMnJQWRkJAwGg91iiIuLw9tvv2238YmIiIjI9ljku7gOHTqguLgYI0aMaLDQFxH8+c9/xkcffYQ777yzzja+vr4IDw9HdHS02UJ/3bp1ePbZZ3Hfffc1JXwiuwoPD4enpyd8fX3h5+eHqKgoHD58WNGyM2bMwPz589GixbWX2QULFqBLly4ICAhAYGAghg8f3mBf58+fxyOPPILg4GC0bNkS/fv3xxdffGF8vKCgAFOmTEG7du3g5+eH2NhY/PbbbyZ9LFiwAMnJySgrK1O97kRERETknFjkuzhvb298/PHH8PT0rLfQrynw//Of/2DXrl0IDw+vsy+NRoMlS5bgwQcfbLDQrynwN23ahOjoaIutS0ZGBnx9fWtNHh4e0Gg0yM3NtdhYrqC8vBxhYWF46aWXTOafOXMG4eHhWLBggZ0icw4XL15EXl4ecnJyoNfr8fvvv8PPzw9Tpkwxu+xnn32Gy5cvY+TIkcZ548ePx/79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Ws8RIiJbae6vnc19/RvC3JjXmBw5W17tEa9G5LqvZyaXJGZ+Ju/KlSuIjY1FWVkZtm3bZvaKfkM/k2durPoUFxcjICAARUVFtc5wHTx4EHfddRfc3d2h0+lqLTtq1Ch88MEHTRrD2ahZl5SUFHz22WfYt2+f1cZoChFBVVUVPDw8rDYGYPn1KS0txYMPPoj4+Hi88cYb2Lt3r8lP5uXk5GDWrFnYv3+/yXxbGjt2LMaMGYP4+HhF7V3pOUJEZCvN/bWzua9/Q5gb8xqTI2fLqz3i5U/ouTglRXd9P69Xl4YKfKD2z+udPHmyyesQGRkJEUFlZSX0en2tSUmB35wtXLhQdYFvSxqNxuoFvqWVl5dj/PjxSE5OxiOPPIK+ffti/fr1Jm0GDRqEgwcP2q3AB679CoXSAp+IiIiIXAOLfBf33XffYevWrWavql9f6GdkZNTZpri4GAsWLDD7M3nXF/qLFy9u6ioQORydToctW7ZgyJAhAK593n7y5Mn2DYqIiIiICCp+Qo+cU8+ePXH06FFotVqzbb29vbFly5Z6r6r6+/vjhx9+UNRXTaFfVVWlOmYiIiIiIiJqHBb5zYCSolxpWzV9OeNt2ERERERERM6Mt+sTERERERERuQgW+UREREREREQugkU+ERERERERkYtgkU9ERERERETkIljkExEREREREbkIFvlERERERERELoJFPhEREREREZGLYJFPRERERERE5CJY5BMRERERERG5CBb5RERERERERC7C3d4BEF2vuLjYKfu2F+ZLPVddL0tgboiIGq+5voY21/VWgzmqX1Ny4yx5tUecLPLJIWi1WoSEhCA0NNSq44SEhECr1Vp1DFtgvtSzVc6cnSttcyIiW+D7C9876sN9Qxm1+48z5tXWzxGNiIjNRiNqQFlZGSoqKqw6hlarhaenp1XHsBXmSz1b5MzZudo2JyKyheb+/sL3jvo1931DicbsP86WV1s/R1jkExEREREREbkIfvEeERERERERkYtgkU9ERERERETkIljkExEREREREbkIFvlERERERERELoJFPhEREREREZGLYJFPRERERERE5CJY5BMRERERERG5CBb5RERERERERC6CRT4RERERERGRi2CRT0REREREROQiWOQTERERERERuQgW+UREREREREQugkU+ERERERERkYtgkU9ERERERETkIv4fzO+FyQYxwUgAAAAASUVORK5CYII=", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA/kAAACyCAYAAAAZMg8+AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAPTdJREFUeJzt3XlcVPX6B/DPCMywDiiLiAKiZZZLSalX08Il3CO0/KnpL8FK01vetITELmiaXm2xrqk311sWeG/hLUXJTDQrS9wyUVvFSEVUZBmUReb5/eFlfo4sMwOz83m/XuelnPM95/uc55yZOc+cM+coRERARERERERERA6vha0DICIiIiIiIiLzYJFPRERERERE5CRY5BMRERERERE5CRb5RERERERERE6CRT4RERERERGRk2CRT0REREREROQkWOQTEREREREROQkW+UREREREREROgkU+ERERERERkZNgkU9ERERERETkJFjkExERERERETkJFvlEREREREREToJFPhEREREREZGTYJFPRERERERE5CRcrd1heXk5KisrLdqHUqmEu7u7yfPZc2zNAfPvPOx1W1ojLkdnz++fjo77LNkC9zvTMWemaw454+ej5fD43ALEiq5duybBwcECwKJDcHCwXLt2zWliaw6Yf+dhr9vSWnE5+mDP75+OPnCf5WCLgfsdc8ac2WYdHXU9HSW31DCrnsmvrKxEfn4+8vLyoFarLdJHSUkJQkNDUVlZadI3QvYcW3PA/DsPe92W1ojL0dnz+6ej4z5LtsD9znTMmemaQ874+Wg5PD63DKtfrg8AarXabnd0e46tOWD+nYe9bkt7jcsZMLeWwbySLXC/Mx1zZrrmkrPmsp5kP3jjPSIiIiIiIiInwSKfiIiIiIiIyEmwyCciIiIiIiJyEizyiYiIiIiIiJwEi3wiIiIiIiIiJ8Ein4iIiIiIiMhJsMgnIiIiIiIichIs8omIiIiIiIicBIt8IiIiIiIiIifBIp+IiIiIiIjISbDIJ5Ns27YNWq3WqLZ5eXk4cuSIhSMisk9ZWVmIjIw0+vViCbGxsdi4caPN+rcE5pWIiIioYSzyyWglJSX4y1/+gmnTphk8wM7Ly8OAAQOwadMmK0VHZH4RERFwd3eHt7c3fHx80K9fPxw9etSoeWfOnIkFCxagRYsbb7MJCQno0qUL1Go1QkJCMGXKFFy+fNmoZcXGxkKhUGDPnj164y9cuIAJEyYgKCgIfn5+6Nu3L7788kvd9IULFyIxMRHl5eVG9WMt5syrVqvF3Llz0bp1a3h7e2Po0KE4c+ZMvfMb095QG3vNKxERERFgx0V+REQEXn/99Vrj77vvPiQnJ9sgIqC8vBxt27bFmjVrdOO0Wi3Gjx+P++67D6WlpTaJy1rUajWysrKwe/fuBgv9mgJ/4MCBWLZsmdn6T01Nhbe3d63Bzc0NCoUC2dnZZuuLLKuiogJhYWF49dVX9cafPXsWERERWLhwoY0i+3+XLl1Cbm4usrKyoNFocP78efj4+GDKlCkG5/38889x5coVDB8+XDfOxcUFmzZtwuXLl3H06FHk5eVh8uTJBpf13nvv4erVq3VOmz59Os6dO4cTJ07g8uXLGDNmDEaMGIGioiIAQJcuXdChQwd8+OGHRq2zNZg7r0uXLkVqaiq+/PJL5OfnIywsDKNGjar3/cmY9oba2GNeG8seroyghvHKESIiMplYUXFxsQCQ4uLiBttdvHhRAMiuXbv0xldVVYlKpZJt27Y1uY/GzrdixQoJDw+XiooKERF55pln5I477pCLFy+arY+65OXlyerVq2XDhg1SWFho8vzm9Pvvv0vHjh3lqaeekurqaqOnNaSxufnyyy9FrVZLYmKixfowllarld27d8vf//532blzp0nr70yMzfM//vEPCQgIEI1GIyIily5dkrvuukuef/55s/XRlHm2b98uSqVSysvLdeNeeeUVadu2rcF5p02bJpMnT26wzdatW8XHx6fBNnl5eRIaGipnzpwRAJKVlaU3vXv37rJixQrd36WlpQJADh48qBuXnJwsI0eONBiziOXfP0XMn9fw8HBZuXKl7u8rV66IUqmUvXv31rkMY9ob08aUvIpYZ5+9WVFRkSgUCtm9e7fe+OvXr4uXl5ekpqaKiEi3bt1k69atuunJycnSokUL8fLy0g3jxo1rsC9D81y+fFni4+OlTZs24u3tLQ8//LDk5eUZtR6vvPKKdOjQQdRqtfj7+0t0dLQcOXKk3vb5+fkyfvx4CQwMFF9fX+nTp0+tfWHOnDly1113iY+Pj7Rp00bi4+Pl0qVLdhvP8ePHpXXr1nLt2jWjYryZtfc7Z8Ccma455Mwan4/Nlb3kqKioSP75z3/KqlWrJDc316axmINdnsmvOSN7zz336I0/efIkKioq0KtXLxtEdcNTTz0FAFi3bh1efvllbNu2DZ9//jkCAgIs1uff//53tG/fHrNmzcKMGTPQpk0bbN++3WL9GRIaGlrnGf2bz+CvXr1adzmtpXz22WcYOnQo5syZg8WLF1u0L0NKS0vRu3dvDBs2DAkJCRg1ahQiIyN1Z1Sptvj4eKjVaqxatQoajQbDhw9H796967yCxxYOHDiAe+65ByqVClqtFl9//TVWrlyJiRMnGpz38OHD6Nq1a4NtvvjiC9x99931ThcRxMfHY968eQgLC6uzTUJCAtLT05Gfn4+qqiq888476NSpk17f3bp1s6urXMyZ1+LiYpw5cwb33Xefbpyfnx9uu+22Oi//N6a9scu0t7ze6uDBg1AoFHrrAQA5OTkoKytDr1696rwyAgD69+8PjUajG1JTUw3219A8TzzxBAoKCnDixAmcP38enp6eDV5tcbOxY8fi4MGDKC4uxrlz5xAdHY1hw4bVO6+hq1uAxl9VY6t4nOnKESIie7R79260adMGzzzzDGbPno2OHTvib3/7m63DahK7LPIPHDiAdu3awd/fX2/80aNH0b59ewQGBtooMkCpVOLll1/Giy++iNWrV2Pnzp0IDQ21WH8///wznn/+eVRXV+Pq1au4evUqKioq8Nhjj6GsrMxi/Rpya6F/5swZqxb46enpiImJweLFi5GUlGTRvoyRkpKCY8eOoaKiQreNTp48iYSEBFuHZrdcXV2RnJyM1157DTExMbqfwigUCluHBuDGl41Hjx6Fn58fVCoVBg4ciJdeesmoL5SuXLkCX1/feqf/61//wtq1a/HWW2/V22bVqlUQETz99NP1tunbty/c3NzQpk0beHh44I033sDGjRuhUql0bdRqNQoLCw3GbC3mzGtJSQmAG0X4zfz8/HTTbmZMe2OXaW95vVV2djY6d+4MHx8fvfHfffcdAgIC0KFDB6Snp2Pw4MEWfb8uKytDRkYGkpOT4efnB29vb7zyyis4evQovv76a4Pzd+rUCS1btgRw44svFxcX5Ofno7i4uM72v/zyCx577DEEBATAxcUFU6dOhUajwa+//qpr8+qrr6JHjx5wc3NDUFAQnnvuOezdu9eo9bFVPNHR0diyZYtRMRIRkfEqKiowevRoXLt2TVdrVVdXY968eTh27Jitw2s0V2Mb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MWLECNx1110AgKlTp6J9+/Y4ceIE0tLS6i3waxhT4NcIDg7mt3REREREREQOimfy7VxkZCTWrFmDNWvWoKqqCmVlZfD19eXvqomIiIiIiKgWFvkOxM3NTXfJPhEREREREdGteLk+ERERERERkZNgkU9ERERERETkJFjkExERERERETkJFvlEREREREREToJFPhEREREREZGTYJFPRERERERE5CRY5BMRERERERE5CRb5RERERERERE7C1dYB2JuSkhKHXLazsNf822tcZDrmu35NzQ1zWz/mhhxNc91nm+t624qj5NtR4iSqwSL/v5RKJYKDgxEaGmrRfoKDg6FUKi3ahyOy1/zba1xkOmttS0fXmH2RuTUOX+fkCPh65mvVGhxxP+N+QY6ERf5/ubu74/Tp06isrLRoP0qlEu7u7hbtwxHZa/7tNS4ynbW2paNrzL7I3BqHr3NyBHw987VqDY64n3G/IEfCIv8m7u7ufPHakL3m317jItNxW1oOc0vkPPh6Jmvgfkb2ZPPmzVi1ahW+//57tGjRAnfeeSdefvllDBkyxNahNQpvvEdERERERETNjlarxeTJk5GUlISEhARcuHABf/zxByZNmoThw4djy5Yttg6xUXgmn4iIiIiIiJqdRYsW4bPPPsPhw4fRpk0b3fipU6di586deP311xEbG2vDCBuHZ/KJiIiIiIioWSksLMSSJUuQlJSkV+DXuOOOO5CXl2eDyJqORT4RERERERE1Kzt37sTVq1cxfvz4Oqfn5ubWWfw7Ahb5RERERERE1KycO3cOnp6e8Pf3rzWttLQU27dvR0xMjA0iazoW+URERERERNSshIWF4erVqzh37lytaS+//DJ8fX0xY8YMG0TWdCzyiYiIiIiIqFkZOXIkbr/9dsTHx+P3338HAPz22294+umnsXnzZmzduhVqtdrGUTYOi3wiIiIiIiJqVtzd3bFv3z6Ehoaif//+8Pb2xuDBg+Hp6Ynvv/8e3bt3t3WIjcZH6BEREREREVGz07p1a6xZs8bWYZgdz+QTEREREREROQmeySe7UV5ejsrKSov2oVQq4e7ubtE+rMXUfJWUlOj9awxnyhdgnX3M0TnbNiciIiJqbljkk10oLy9HREQE8vPzLdpPcHAwTp8+7fBFTFPyFRoaanRbZ8kXYL19zNE50zYnIiIiao5Y5JNdqKys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1tPTExkZGfWeVVWr1Th58qRRy6op9K9fv25yzERERERERNQ4LPKbAWOKcmPbmrIsR7wMm4iIiIiIyJHxcn0iIiIiIiIiJ8Ein4iIiIiIiMhJsMgnIiIiIiIichIs8omIiIiIiIicBIt8IiIiIiIiIifBIp+IiIiIiIjISbDIJyIiIiIiInISLPKJiIiIiIiInASLfCIiIiIiIiInwSKfiIiIiIiIyEm42joAopuVlJQ45LJthfkynbOulzkwN0REjddc30Ob63qbgjmqX1Ny4yh5tUWcLPLJLiiVSgQHByM0NNSi/QQHB0OpVFq0D2tgvkxnrZw5Omfa5kRE1sDPF3521If7hnFM3X8cMa/Wfo0oRESs1htRA8rLy1FZWWnRPpRKJdzd3S3ah7UwX6azRs4cnbNtcyIia2juny/87Khfc983jNGY/cfR8mrt1wiLfCIiIiIiIiInwRvvERERERERETkJFvlEREREREREToJFPhEREREREZGTYJFPRERERERE5CRY5BMRERERERE5CRb5RERERERERE6CRT4RERERERGRk2CRT0REREREROQkWOQTEREREREROQkW+UREREREREROgkU+ERERERERkZNgkU9ERERERETkJFjkExERERERETkJFvlERERERERETuL/AFdEMPWEtED3AAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -395,7 +395,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -414,7 +414,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -438,7 +438,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -470,7 +470,7 @@ ")" ] }, - "execution_count": 31, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -507,7 +507,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -519,7 +519,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAACCwAAACyCAYAAACDK8x3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABuYUlEQVR4nO3deXgUVfb4/5MQsi+EfQ9EBxVEZRlmZBEVZFE0ooOjoD8RBkF03D4CLswTHFQcxQUHgUFwRURkQFAcQBZRUTEIiMKAgiwBISyBJEAgIX1+f/hNTzrp7qrqrbqT9+t5+lG6a7l177nnVldX6kapqgoAAAAAAAAAAAAAAEAIRdtdAAAAAAAAAAAAAAAAUPNwwwIAAAAAAAAAAAAAAAg5blgAAAAAAAAAAAAAAAAhxw0LAAAAAAAAAAAAAAAg5LhhAQAAAAAAAAAAAAAAhBw3LAAAAAAAAAAAAAAAgJDjhgUAAAAAAAAAAAAAABBy3LAAAAAAAAAAAAAAAABCjhsWAAAAAAAAAAAAAABAyHHDAgAAAAAAAAAAAAAACDluWAAAAAAAAAAAAAAAACHHDQsAAAAAAAAAAAAAACDkuGEBAAAAAAAAAAAAAACEHDcsAAAAAAAAAAAAAACAkIsJ9Q7PnDkjJSUlod5tRImNjZX4+Hi7ixEwtLkx2rzmsbvNaSNjdrcREInILcbszi20kTG72wiIROQWY+QWz4gf+Mvu/kUMw192xzAA1DSM3fAXY3fghfSGhTNnzkjr1q3l0KFDodxtxGncuLHs3r27WgQ7bW4ObV7z2NnmtJE51alfAqFAbjGH/B/+yP+ANeQWc8gt7hE/CATOrxDpGCMAIHQYuxEIjN2BF9IbFkpKSuTQoUOSm5srqampodx1xCgsLJQWLVpISUlJtQh02twYbV7z2N3mtJExu9sIiETkFmN25xbayJjdbQREInKLMXKLZ8QP/GV3/yKG4S+7YxgAahrGbviLsTs4Qj4lhIhIamoqiaCGoc1rHto8/NFGAIKB3BL+aCMAwUBugT+IH0Q6YhgAgMjC2A2El2i7CwAAAAAAAAAAAAAAAGoeblgAAAAAAAAAAAAAAAAhxw0LAAAAAAAAAAAAAAAg5LhhAQAAAAAAAAAAAAAAhBw3LAAAAAAAAAAAAAAAgJDjhgUAAAAAAAAAAAAAABBy3LAAAAAAAAAAAAAAAABCjhsWAAAAAAAAAAAAAABAyMXYXQAAAAAAAABEjtOnT8uuXbukqKhIoqKipH379pKcnGx3sQAAAAAAFoXD97tq/YSFNWvWSMeOHcXhcNiy/4EDB8qbb75py76BmsDuPi5CPzeDdgIQaOSVyEA7AQg08or9duzYIQ8++KA0bdpUunXrJn/605+ka9eu0qRJE/nrX/8q27Zts7uIAAAAAAATwun7XdjfsNC6dWuJj4+X5ORkSUlJke7du8vmzZtNrfvAAw/I3//+d4mO/u0wx40bJ+3atZPU1FRp2rSpDB8+XI4dO+ZxfaPljT5/6qmn5NFHH5UzZ874dvCwzO4LWDX94pUvAtnH582bJz169JDU1FSJioqyVI6BAwdKVFSUfPbZZy7vT5gwQWrVqiXJycnO12233eb8vKb080C2k8PhkMcff1waNWokycnJ0q9fP9m7d6+pbXlqJ6Nlako7AZEkkHnlqaeekvPOO0/S0tKkfv360rdvX9PbIv97Z+e5uJnxwmiZmtJOQCSxM6+YGS/y8vJk8ODB0rBhQ6lTp4507dpVPv/8c5dt1MS84nA45NFHH5VLL71Ujh49Kp988okUFBTI9u3bRURk8eLFUlhYKB07dpQHH3xQysrKbC4xAAAAAMCdcPx+F9Y3LBw9elT27Nkja9askZMnT8rBgwclJSVFhg8fbrjup59+KsePH5drr73W+V6tWrVkzpw5cuzYMdm8ebPk5ubK0KFDPW7DaHmjz9u1ayeZmZkyd+5cXw6/RvP1IlblC1gVmfmhs127di4/TCQmJkpUVJQsWrTI1Oc19eKVrwLdx9PT02X06NHy8ssvWyrH22+/LadPn/b4eY8ePeTkyZPO13vvvef8rCb080C303PPPSfvvfeefP7553Lo0CFp2bKlXH/99YY3Ghm1k7dlakI7AZEk0HnllltukQ0bNkhBQYH8+uuv0qdPH+nfv7/feYX8b++5uJnxwmiZmtBOQCSxO6+YGS9Gjx4tv/76q2zbtk2OHTsmN998s1x33XVy4sQJEamZeUVV5b777pP58+fL999/L3PmzJGuXbu63CTeuXNneeutt2Tbtm2ybNky+ctf/iKqamOpAQAAAACVhev3u7C+YSEnJ0diY2OlY8eOIiKSnJws3bp1k7y8PMN1Fy5cKL1793b54fqZZ56RDh06SO3ataVhw4Zy//33y9q1az1uw2h5M9vr06eP88dsmOPrRSx3F7DKmfmhU0Rk69atLj9MPPvss1KvXj3p37+/qc9r4sUrfwS6j/ft21duu+02yczMNF2G/fv3y/jx4+W1116zfgD/T3Xv54FupxkzZsjYsWPlggsukOTkZHnuuedkx44d8uWXX3rcjpl2MlqmurcTEEkCnVfatGkj6enpIvLbSXetWrXk0KFDUlBQ4HE75H9jdp+LmxkvzCxT3dsJiCR25xUz48XOnTtl0KBBUr9+falVq5aMHDlSTp48Kbt27XIuU9Pyyuuvvy4ffvihfPbZZ3LBBRd4XTYzM1NWr14tq1evlqlTp4aohJ7Z/RRGmMPTKr0jjiMDcQwAEGHcjhQ1edwO1+93YX3DwrfffiuXXXaZxMXFicPhkHXr1sm0adPk9ttvN1x348aNcvHFF3tdZtWqVXLppZeaLo/R8u4+b9++veTk5Jjehz9UVdasWSNTp06VTz/9NGIToq8XsdxdwBLx7weJ6dOny/DhwyU+Pt7056G8eFVSUiILFy6UqVOnyqZNm0Kyz0AKdh83oqoybNgwGT9+vLRs2dLjchs2bJAGDRpIRkaGDB48WHbv3u3yeSj7eUFBgbz99tsyY8YM09Mo+CuQ7VRQUCB79+6Vzp07O9+rU6eOnH/++R6fomKmncwsE8p2AuBdMPL/0qVLpU6dOhIfHy8PP/ywPPzww84fpSoj/5tj57m4mfHC7JhC/gfCRzh8xzcaL8aNGycLFy6UQ4cOSWlpqbz66qvSpk0bl31X9/xfkarK5MmT5R//+IfXMbOipk2bygsvvCAvvvhi0B4dWlBQINHR0bJmzRqX98vKyiQ5OVnmzZsnIlWfwmg05VNlZqYdMZpGxBur5RExngrR6MmQ/mzb12NYu3at9OjRQ5KTk6Vu3bqSlZXl8rldT6u0u3/5GscVmXmaqEhg2skbq1O0GfUbf6b8NHu8lRkdP1PGAUDN5uu47es0pt7GJX/OP0Wsj7P5+fkyfPhwadq0qaSkpEhWVpbs37/f8jKe+DKFtNExhOtUf3aff4br97vywoVMQUGBiogWFBSYWv66667T2NhYTUtL05iYGI2NjdVXXnlFHQ6H4bq/+93v9LXXXvP4+fvvv6/Jycn63XffmSqL0fKePl+xYoXWrl3b1D5UrddRucLCQv3973+vcXFxmpiYqHFxcXrppZfq8ePHLW0n0Hw5ngkTJmiXLl1UVbWsrEy//PJLbdKkiY4bN87rel26dNHJkye7vOdwOPSaa67Rf/3rX6qqKiK6Zs0aU+VYtWqVRkdH6y+//GLp8wULFmijRo1M7UPV9zbfuXOnNmnSRBMSEjQhIUFjYmL0z3/+s547d87SdgLNyvEEq4+vWbNGzaS3V199VXv37u38t7v4+OGHH3TPnj3qcDj0wIEDescdd2hmZqYWFRU5lwlVP1+1apUmJCRoYmKiJiYmaq1atfTZZ5+1tA1f9h/Idtq3b5+KiP70008uy3Xt2lUnTpzodhtm2snMMlbaydc2AmqycMj/qqrHjh3TF198URcsWOBxGfJ/+J+LmxkvzI4p5H8guMIl/1v9ju9pvNi9e7f27dtXRURr1aqlDRs21K+++splmUjL//5YvXq11q9fX4uLi91+7unYSkpKtGnTpvrxxx973b6vdbNy5UqNjo7WwsJCl/e///57FRHdtWuXrlixQps3b65lZWXOz7Ozs7Vnz56m9/PYY4/pxo0btaSkRPPy8vSaa67RAQMGuCxz0003ac+ePfXIkSN67tw5nTx5siYnJ5u6HmO1PKqqy5Yt07lz5+rs2bNNfe+dMmWK1qtXz2Mb+rNtVeNjWLt2raampuqcOXP09OnTevbsWV2/fn2V5S6//HKdPXu2qX1WZHf/8ufcwdc4LvfWW29pnz59TF3rClQ7ebJjxw7Nz89XVdWzZ8/q5MmTtXHjxm7LrWrcb3yJxYqs9i0zx29mm77EMeefABBaoT7/tDpGqhqPS/6cf6paH2cHDBigAwYM0OPHj2tRUZHeeuutetlll7kcg5llPJk0aZK2atVKt2/frkVFRTpixAht376913WNjsFMHUXq+ac/gv39zh9h/YSFnJwcmT17tpw4cULy8vKkS5cusmnTJlN3/NStW9fjY4DnzZsnI0eOlCVLljj/it8bo+W9fV5YWCh169Y13Ie/JkyYIFu2bJGzZ8/K6dOn5ezZs/Lf//5Xxo0bF/R9B1pOTo5s3rxZ6tSpI3FxcXL11VfLY489JpMmTfK63vHjxyUtLc3lvenTp4uqyt133225HNOmTZN+/fpJ69atLX2empoq+fn5lvdn1R133CGHDx+W4uJiKS4ulnPnzsnixYvl7bffDvq+AyVYfdyMXbt2ycSJE2XWrFlel7v44oslIyNDoqKipGnTpjJ79mw5ePCgfPXVV85lQtHPz549KzfddJMUFxfL6dOn5fTp01JWVibjx4+XLVu2BHXfgWyn1NRUEZEqbXfixAnnZxWZaSezbRmqfAzAWDDzf926deWBBx6QYcOGydatW6t8Tv43z85zcTPjhdkxhfwPhI9w+Y5fvr3K44XD4ZBevXpJ8+bNJT8/X86cOSMzZ86U/v37yw8//OBct7rn/4ref/99GTJkiMenDnpSu3ZtufPOO51/aRZoOTk5cuGFF0pKSorL++vXr5f69etLZmamx6cwWmFm2hEz04gEktWpEI2eHOnPts149NFH5e6775YhQ4ZIQkKCxMbGSpcuXaosF8qnVYZL//InjgMxvVlFZtvJE6tTtBn1m2DEojf+Hn+5mjZlEADUJL6O275MY2o0Lvl7/mllnD116pQsXbpUsrOzpU6dOpKcnCwTJ06UzZs3y7p160wv440vU0gbHUO4TfUXLuef4fr9TkQkxuyChYWFfu/Myjb27t0rhw8fdl5sqFu3rowfP16ysrLkhRdekPT0dFm/fr28/PLL8t5774mIyD333CNZWVnSr18/6dSpk9uL1LNnz5YxY8bIxx9/LN26dTMsh9HyRp//+OOPLo+pNctqfb/zzjty9uxZl/dKSkpk3rx58vzzz1vef6D4EjflF7Fuv/12yc/Pl6ysLFMXsSpfwCr/QeKbb76xXIZff/1VFi9eLB9++KHlz329eGWlrvLz8+Xrr7+u8v6ZM2dk9uzZcvPNN1vef6CYPY5g9XGzvvjiCzl27Jh06tTJ5f2srCwZPHiwTJ8+3e16UVFREhUVJarqfC8U/Xz16tVV+nh5eebMmSPjx48Pyn4D3U5paWmSkZEhGzZscNZZQUGB7Nq1Sy677LIq+zfTTmbb0pd2CsTYB9QU4ZT/HQ6HlJaWys8//yzt2rVz+Yz8b47d5+JmxguzYwr5Hwguu/O/1e/4FVUeL44fPy6//PKLfPjhh86LillZWZKZmSkrVqyQ9u3bi0jk5X9/HDhwQHr06OGx7OXfwd1dcG3SpImsX7/e63H7mm9zcnLc/pj47bffOt/fuHGj3HLLLVWWKZ/yKTExUbp16yZPP/20xz9UqMzdtCPjxo1zfg+vV6+e22lEvPGnPEZWr14tP/30k4waNSog2/PE0zGcOnVK1q9fL926dZPOnTvL7t27pU2bNvLUU09Jr169XLbRvn17mTFjhs9liITzq8p8jWM1Ob1ZZYFoJ2+WLl0qQ4YMkYKCAomKivI6RZu//cYMs33LyvEbbdOfOOb8EwBCw47zTytjpJlxKRTjaLny62AVr4eV//+mTZukR48eppbxxGi6zyuuuMKncpupo0g9//RHsL/feeLuj1WrMPsoBhEJ2MvMYzI++OADTUpKcnnkR2lpqdapU8f5iI6zZ8/qRRddpKqq3333nd50003OZVeuXKktWrRwWb/8MXg5OTmmjtloeTPb69q1q86aNcvU/lT/97iN6vYy+2iUPXv2qIjo1q1bne8tW7ZM4+LinI/NKSsr0969e2vPnj21U6dO2qxZM1VVHT16tN51113O9d544w2tXbu21qtXz/kSEU1NTdVRo0Z5LUd2dra2bt3a4yNnvH0+YcIEve6660wdr2rNbfNg9PFz585pcXGxLl++XEVEi4uLtbi42G07nTp1SnNzc11eIqLz5893xpqq6rx58/Tw4cOqqpqXl6dDhw7VjIwMl0c/RWo/tysXT5o0STMzM3XHjh168uRJHTlypMdHPJlpJ7NtaaWdwqWNePGKxJcd+X/KlCl68OBBVVU9fPiwjhgxQuvUqaOHDh3yKa+okv/D4VzczHhhZhnyPy9eoXnZlf+tfsc3Gi8uuugivfvuu7WgoEDLysp08eLFGhsb6/K49UjN/+H8svo41RYtWui0adOqvN++fXudMGGCqrqfRsTMlE+eeJp2xMw0Ip74Ux4zUyHefPPNeu2115oqi9Vtl/N2DOXnWY0bN3ZOrTFz5kxNSEjQXbt2uWzH6lQr5cKlf/nyOH9f49jM9GaVBaqdzDAzRZvZfmMlFiuy0rfMHn8wpoxTDZ8Y5sWLF6+a9grV+WdFZsZIM+OSP+efFZkdZ3v16qX9+/fXo0eP6okTJ3TQoEEaFRWlTz31lKVl3PFlCmkzxxCMqf7KMXZbf5lh+gkL/jx6vVxhYaG0aNHC1LI5OTly6aWXujw6JSYmRq677jqZP3++DBs2TGJjY6VevXqSl5cnY8aMcXm0b69evSQ9PV0++eQTGTBggIiIPPDAAxITEyNXXnmly762bdsmLVu2lFGjRsnevXvlP//5j6nljT7ftm2b7Ny5UwYPHmyyhv4nNzfX3B0n/8/jjz8us2bNcrlDp3bt2jJkyBCZMmWK5f0HipU2F/mt3ZOSkuTCCy90vterVy9JSEiQRYsWybBhwyQ6Olo+/fRTOXr0qNx9990yZ84cERG56aab5K677hKHwyHR0dFyyy23SO/evV2236JFC5k1a1aV9ys6d+6cvPbaa3L//fe7fXSk0ecrVqyQYcOGmT7mclbbvHfv3rJx40YpKytzvhcfHy8vvPCC3H777Zb3Hyhm2zwYffydd96Ru+66y7lMQkKCiIisWbNGrrzySpc+npiYKImJiVXK1aBBA5e7G999912577775NSpU5Keni5XXHGFrFy50vnop1D187Nnz8r5559f5e61mJgYWbt2raW7J+3OxWPHjpWCggLp3r27nDp1Srp37y5Llixx7sNqO5lZxtd2stovgZrMzvy/evVqeeaZZ6SoqEhSU1OlS5cusmrVKmnUqJGIWM8rIuT/cDgXNxovzCxD/geCz878bzWvGI0XIiKLFy+WMWPGyPnnny9nzpyRjIwMefXVV537iMT8748HH3xQ4uPj5dlnn3X7+YEDB6Rt27aybds2adasmctnTz75pBw4cEBmzpzpcftWrxmIiOTl5Ulubq78/ve/d3k/Pz9ftm3bJi+++KKIuJ9GpGK9lU/5lJaWJl999ZX06dPH4z7nzZsn99xzT5VpR8qnEbnqqqskPz9fUlJSZOnSpdK/f3/54osvnE/l8MTX8phh9OTIQPF2DH/4wx9ERGTYsGHSoUMHEREZMWKEvPzyy7J8+XK55557nOv6O9VKJJxfVeRrHPv6NNFAtZMZ5VPupKeny4UXXljliWf+9hszrPSt8vN7o+M3s01/4pjzTwAIjVCff1ZkNEaKGI9LI0eODPo4WtmcOXPkkUcekUsuuUSioqJkzJgxsmzZMqlfv76lZdyxOoW0GWbPNSL1/NMfwf5+5xfLt474ofyuE1/uOvZkzJgxOmjQIM3Ozq7y2erVq7VDhw4e/0o+2AYOHKivv/66pXV8raOioiL9/e9/r7GxsZqQkKAiou3bt9fjx49b2k6gWT2esWPHateuXau8P2TIEO3bt6/z3/v27dOsrCzdt2+fy3KXXHKJfvTRRx63L1L1rvORI0dqv379nP9esGCBxsXF6ZEjR9xuw9vnW7du1YYNG+rp06c9lqEyX9t8586d2qRJE42Pj1cR0ZiYGP3zn/+s586ds7SdQAt0Pw/nPq4a2n6+atUqTUhIcPbx6OhoffbZZy1tw5/9e1Pd2ikYdQRUd+R/Y+T/0CP/A8FH/jdmd/73x+rVq7V+/fpaXFzs9vPyvwDLzc11eb+kpESbNm2qH3/8sdft+1I3GzZsUBGp8pffU6dO1YYNG2ppaamqVn0KozulpaWamJioy5Yt87jMrFmzND09Xb/88ssqnx09elRFRLds2eLyfocOHXTy5MlmD8lSecoZ/UWc0ZMj/dm2N5WPITMzU5944gmXZdq1a1flLxStPq2ynN39y9f9+xrH/jxNtCJf28nK9hMSEnTRokVVPrPSb/yJxcrl8da3fDl+d9v0JY45/wSA0AqH809PY2Q5b+NSIM8/fR1nt2zZoiKi27dv92uZchkZGTp9+nTnv0+cOKFxcXG6du1aw3XdHYPZOorU809/BPv7nT8i/oaFRYsWaatWrTxWbqTxp44cDoeuWbNGn3/+eRUR229WUA1Om//3v//VgQMHur1hwO4LWKG8eKX62yNT58yZoyKin3/+ueX1gyHQbV7d+riqf3V04sQJnTFjhoqI/vDDDyHfvyfVrZ24YABYR/43Rv4Pf+R/wDryvzG7878/HA6HXnjhhfr222+7/dzTBa0PPvhAW7VqZXhDvS91c/LkSU1PT9cRI0Y4Hzk7d+5cTUlJ0TfffNO5nLtpRMxM+VSRmWlHjKYRyc7O1oyMDLfrWi2PqrmpEEtLS7Vp06ZuL4B6K4+VaRbNHsMLL7ygTZo00S1btui5c+f09ddf16SkJN29e7fLdqxOtVLO7v7l6/59jWOz05tVFoh28hY7VqZoUzXuN2ZiMZB9y8zxB2PKOFXOPwEg1EJ9/ml1jFQ1HpfMTGMXyHO+7du365EjR9ThcOiPP/6onTp10uHDh1taxlt5rEwhbfYYgjHVXzm7zz/9Eezvd/6I+BsWHnroIV28eHHAtme3QNRROJ3oBqMszZo1006dOmnPnj21Z8+eun///oBt2w7+1lE4tbdq4MtT3fq4qv1tTi42Fm79CogE5H9jdudv8r8x8j9gHfnfWDjmbytmzZqlTZo00b1791b5zN0FrQMHDmiLFi30lVdeMdy2r8f29ddf6xVXXKEpKSlat25d7d69u9u/Uqv8FMbrr79e69evrwkJCdq0aVO99dZb9eeff3ZZp+JTGMufZpiUlOTyqlgXP/30k2ZlZWmDBg00JSVFL774Ype5i4cOHap33nmn2+MwKk/lJ0Kq/vYX9uJmXtiKF1+9PRnSW3nMbLtymYyOweFw6JNPPqlNmjTRlJQU/eMf/6ifffaZy359eVplObv7lz/r+xrHlZl5mmgg2slb7GRlZWmjRo00MTFRGzdurDfccIN+9913Hstj1G/MxGIg+5aZ4zfapq9xbHeOB4CaJtTnn0ZjpKr1ccloHFX175yvcnlmz56tTZs21YSEBM3IyNAnn3yyyg/XRst4K09ZWZk++uij2qBBA01MTNQ+ffq43DToyzmxUR1F8vmnv4L5/c4fEXvDQm5urmZlZekjjzwSgJKFD25YqHkiPblVFqjyVNc+rmp/m5OLjYVbvwIiAfnfmN35m/xvjPwPWEf+NxZO+dsXDodD77nnHm3dunWVR7pWvqC1a9cubdOmjQ4dOlQdDofhtoN9bHY/hVFV9bzzzqsynaWdwq08qr49rbKc3f0rFP0zHOJYNfxiJ9zK42sc253jAaCmqQnnn6rhN06GW3ki+fzTX8H8fuePGIlQzZs3lw8//NDuYgAIEvp4ZKCdAAQaeSUy0E4AAo28Er6ioqJk6tSp8sQTT8ill14qN998s4wePVq6du3qXGbTpk3y+OOPy/z58+Wee+6RyZMnS1RUlI2l/s1VV10lGzdutLUMO3futHX/lYVbeUREFi5caHcRwlo4xLFI+MVOuJWHOAYAiDBuexJu5anJ43a4fr+LDurWAQAAAAAAENGio6Nl0qRJ8v3330vDhg3luuuuk9TUVOncubOIiAwZMkTq1KkjGzdulJdeeklq1aplc4kBAAAAAO6E4/e7iH3CAgAAAAAAAELnggsukJdeekmefvpp+eWXX2TXrl1y4403yoYNG6RNmzZ2Fw8AAAAAYFI4fb/jhgUAAAAAAACYlpiYKBdffLG0aNFCREQaNWpkc4kAAAAAAL4Ih+93TAkBAAAAAAAAy8rnMQ32fKYAAAAAgOCy8/sdNywAAAAAAAAAAAAAAICQ44YFAAAAAAAAAAAAAAAQctywAAAAAAAAAAAAAAAAQo4bFgAAAAAAAAAAAAAAQMhxwwIAAAAAAAAAAAAAAAg5blgAAAAAAAAAAAAAAAAhxw0LAAAAAAAAAAAAAAAg5LhhAQAAAAAAAAAAAAAAhFyMHTstLCy0Y7cRobrWTXU9rkCornVTXY8rEMKlbsKlHOGIugF8R//xLFzqJlzKEY6oG8B39B/PqBtj1BF8FS6xEy7lQOQhdgDAHuRf+IrYCY6Q3rAQGxsrjRs3lhYtWoRytxGncePGEhsba3cxAoI2N4c2r3nsbHPayJzq1C+BUCC3mEP+D3/kf8Aacos55Bb3iB8EAudXiHSMEQAQOozdCATG7sAL6Q0L8fHxsnv3bikpKQnlbiNObGysxMfH212MgKDNzaHNax4725w2Mqc69UsgFMgt5pD/wx/5H7CG3GIOucU94geBwPkVIh1jBACEDmM3AoGxO/BCPiVEfHw8jVjD0OY1D20e/mgjAMFAbgl/tBGAYCC3wB/EDyIdMQwAQGRh7AbCT7TdBQAAAAAAAAAAAAAAADUPNywAAAAAAAAAAAAAAICQ44YFAAAAAAAAAAAAAAAQctywAAAAAAAAAAAAAAAAQo4bFgAAAAAAAAAAAAAAQMhxwwIAAAAAAAAAAAAAAAg5blgAAAAAAAAAAAAAAAAhxw0LAAAAAAAAAAAAAAAg5LhhAQAAAAAAAAAAAAAAhFxMqHd45swZKSkpCfVuI0psbKzEx8fbXYyAoc2N0eY1j91tThsZ87WNqFtjxH/4I/6Dh/gPf8R/8BD/4Y/4Dx674z+cET/wl939ixiGvxh/YRfyJyId+RN2sTt/VkchvWHhzJkz0rp1azl06FAodxtxGjduLLt3764WwU6bm0Ob1zx2tjltZI4vbUTdmkP8hz/iP3iI//BH/AcP8R/+iP/gqU7f+QKJ+EEgML4g0jH+wi7kT0Q68ifswve7wAvpDQslJSVy6NAhyc3NldTU1FDuOmIUFhZKixYtpKSkpFoEOm1ujDaveexuc9rImK9tRN0aI/7DH/EfPMR/+CP+g4f4D3/Ef/DYHf/hjPiBv+zuX8Qw/MX4C7uQPxHpyJ+wi935s7oK+ZQQIiKpqakkghqGNq95aPPwRxsFD3Ub/mij4KFuwx9tFDzUbfijjYKHuoU/iB9EOmIYdiH2EOmIYdiF2APCS7TdBQAAAAAAAAAAAAAAADUPNywAAAAAAAAAAAAAAICQ44YFAAAAAAAAAAAAAAAQctywAAAAAAAAAAAAAAAAQo4bFgAAAAAAAAAAAAAAQMhxwwIAAAAAAAAAAAAAAAg5blgAAAAAAAAAAAAAAAAhxw0LAAAAAAAAAAAAAAAg5LhhoRr58ccf5c0335R//etfIiLy/fff21wiBJOqyhdffCFvvfWWiIi89957snfvXptLhWAqKSmRpUuXyuuvvy4iIgsWLJDjx4/bXCoAQLCR/wGgZiL/A8FD/wIAAEAocf7pXbW+YWHNmjXSsWNHcTgctpVh4MCB8uabbwZt++fOnZN58+ZJjx495Pe//7289dZb8umnn4qISN++feXyyy+XOXPmSElJSdDKgNAqKiqSV155Rdq2bSsDBw6U+fPni4jIa6+9Jm3atJGsrCxZvny5qKrNJQ0Nu/t5sPu4iMiBAwfkb3/7m7Rs2VLuu+8++fDDD0VE5IUXXpBmzZrJX/7yF9m8eXNQy+APu9tIJDTtFGrUa2SgnYKjptQr+d9/1TH+RajbSGF3O1XHNrK7TkXI/0Cko38BAAAglDj/NElDqKCgQEVECwoKTK/TqlUrjYuL06SkJE1OTtZu3brppk2bTK3bvn17/eijj5z/zs7O1ujoaE1KSnK+br31Vo/rT5w4UTMzMzU1NVXr1aunffr0qbLvsWPHatu2bTUlJUWbNGmiw4YN06NHjzo///HHH7VRo0ZaXFxsqsxW6qiwsFD79eunrVq10hdeeEGPHTumqqq5ubkqIrp161adMmWKnnfeeXrVVVfp8ePHTZUhkHxpc1+tXr1aO3TooGVlZUHflzc33nijvvHGG6aXt1JHu3fv1gsvvFA7d+6s77zzjhYXFzvbOzc3V/ft26fjx4/XevXq6ahRo7S0tNSPI/GN3f38vffe0+7du2tKSoqaSXFGfdgob1jt46rW6uiLL77QunXr6oABA3TZsmVaVlbm0uabN2/WkSNHamJior766qsB3385O3Oxqupnn32m3bt316SkJE1PT9cbbrjB5fNDhw7pbbfdpg0aNNC0tDS9/PLLde3atc7Pg5mL/Vmvpo1xqqEdFwK1fztzlFFsm2l34t+7G2+8UUVE16xZ4/K+3fFfHfO/mbxT0bFjx3TYsGHapEkTTU5O1htuuEFzc3NdlonU/K9qbx8wqreysjJ97LHHtGHDhpqUlKR9+/bVPXv2uGwjVHUbKL7u364xoG3bti7tmZCQoCKiCxcudC4TqfFvZ+ybaQOjXBWJ+T+Y/O3bducGRD67+xcxDH+F8vwTqMjuGLJ7/4h85E/Yxe7zz2Cys3+E9Q0LR44cURHRr776SlVVi4qKtF+/ftqxY0fDdVesWKHNmzd3+fE6Oztbe/bsabq8O3bs0Pz8fFVVPXv2rE6ePFkbN27sss3HHntMN27cqCUlJZqXl6fXXHONDhgwwGU7l19+uc6ePdvUPs3W0ZkzZ/TKK6/Uq6++Wk+cOOHyWcVgV/2t3q699lrt2rWrnj592lQ5AiWUF28rX7yqyNOPEZUZXZwyuiioGrwLgwcPHtSMjAy999579dy5c873K7e3qurevXv1oosu0r/85S/qcDhMlSNQ7O7ny5Yt07lz5+rs2bNN/Rho1IfN5A0rfVzVfB19++23mpycrP/6179c3nfX5uvWrdP09HSdPn16wPZfzu5cvHbtWk1NTdU5c+bo6dOn9ezZs7p+/XqXZW666Sbt2bOnHjlyRM+dO6eTJ0/W5ORklxu1gpGL/VnP7nq1Y4xTtf9Lgd3xbzVHGcW22XYn/t176623tE+fPm7PEeyM/+qa/83knYoGDBigAwYM0OPHj2tRUZHeeuutetlll7ksH4n5X9X+PmBUb5MmTdJWrVrp9u3btaioSEeMGKHt27ev0lahqNtA8WX/do8BFU2ZMkXr1avn8h0jEuPf7tg30wZmclWk5f9g4oYF2M3u/kUMw1/84Aa72B1Ddu8fkY/8CbvYff4ZTHb2j7CeEiInJ0diY2OlY8eOIiKSnJws3bp1k7y8PMN1Fy5cKL1795boaN8PsU2bNpKeni4iIqoqtWrVkkOHDklBQYFzmWeeeUY6dOggtWvXloYNG8r9998va9euddlOnz59ZNGiRT6Xw51JkyZJQUGBLFmyRNLS0rwum5ycLP/+97/F4XBIdnZ2QMsRaEePHpU9e/bImjVr5OTJk3Lw4EFJSUmR4cOHe13v008/lePHj8u1115b5bO3335bTp8+bWr/t9xyi2zYsEEKCgrk119/lT59+kj//v2djxwdPXq0/Prrr7Jt2zY5duyY3HzzzXLdddfJiRMnnNto166dZGZmyty5c80fuAkjRoyQbt26yT//+U+pVauW12VbtmwpK1askI8//tg5ZUS4CnQ/79u3r9x2222SmZlpav9m+rCRYPTx0tJSufnmm2XChAly9913Gy7ftWtXWbJkiTz00EOyffv2gJbF7lz86KOPyt133y1DhgyRhIQEiY2NlS5durgss3PnThk0aJDUr19fatWqJSNHjpSTJ0/Krl27nMsEo538YXe9hvMYF07szlFmYtuMcGsnu+NfRGT//v0yfvx4ee2119x+blf8V+f8bybvlDt16pQsXbpUsrOzpU6dOpKcnCwTJ06UzZs3y7p165zLRWL+F7G/DxjV24wZM2Ts2LFywQUXSHJysjz33HOyY8cO+fLLL122E451G0h2jwEVTZ8+XYYPHy7x8fHO9yIx/u2OfTNtYCZXVff8X52EwzQiMBbsqVYiuX8Rw5GBaZhgl+oYe4FEHEeG6hbHxF1k4Pwz/IT1DQvffvutXHbZZRIXFycOh0PWrVsn06ZNk9tvv91w3Y0bN8rFF19c5f0NGzZIgwYNJCMjQwYPHiy7d+/2up2lS5dKnTp1JD4+Xh5++GF5+OGHnRcv3Fm1apVceumlLu+1b99ecnJyDMtsVklJicyYMUOeeeYZSUpKMrVOfHy8PPvsszJr1iwpLi42XP7MmTPy5ptvyu233y5jx46Vn3/+2d9im+LrBSxPF6+MfoyozOjilNkfjgJ9AWvXrl2yYsUKef755yUqKsrUOs2bN5cxY8bI1KlTTS2fn58vzz//vAwePFgmTZokR44c8afIpgWjn/vDXR82yhuB7uMiIkuWLJHo6Gh58MEHTa/TvXt3uemmm2TGjBkBLYudufjUqVOyfv16ERHp3Lmz1KtXTy6//HJZtWqVy3Ljxo2ThQsXyqFDh6S0tFReffVVadOmjcu+g9FO/mCMsy4nJ0fuvfdeGTp0qCxevDgkJ/525ygzsW2m3Yl/V6oqw4YNk/Hjx0vLli1NlTlU8V/d87/ZvKOqLv+t+P+bNm1yvheJ+V/E/j7grd4KCgpk79690rlzZ+fyderUkfPPP7/KnIqhqls78r+I/WNAudWrV8tPP/0ko0aNcnk/EuPf7tg3yyhXRWr+/+WXX+Sxxx6TIUOGmL42EK4KCgokOjpa1qxZ4/J+WVmZJCcny7x580RE5IEHHpC///3vzmsFDodDHn/8cWnUqJEkJydLv379ZO/evV73NWHCBKlVq5YkJyc7X7fddpvbZQcOHChRUVHy2WefmT6WcePGSbt27SQ1NVWaNm0qw4cPl2PHjnlcft68edKjRw9JTU01dX3AlzL5su7atWulR48ekpycLHXr1pWsrCzT23zqqafk0UcflTNnzlguoxnhdH5VztcYthKP5fLz82X48OHStGlTSUlJkaysLNm/f7/pz60wEzNm+mG7du1cjjExMVGioqJMXWuz2qdEzNWrtxgPdgwHkq+xJ2K+n5czamtf2soTM7FnJn/60x986Z9Gx2C0Tbtiz67z83K+xvFTTz0l5513nqSlpUn9+vWlb9++hvPGG8Wx1XG5Mqvrm1nen75ldd28vDwZPHiwNGzYUOrUqSNdu3aVzz//vMpy1SGHhjLu/B2XjFiNO7Pn0L6WyWr+NIpTM8dXHc4/q9P3OxGx+BxKP1l9lMR1112nsbGxmpaWpjExMRobG6uvvPKKqUfc/+53v9PXXnvN5b0ffvhB9+zZow6HQw8cOKB33HGHZmZmalFRkeH2jh07pi+++KIuWLDA4zLvv/++Jicn63fffefy/ooVK7R27dqG+1A1V0fvv/++nnfeeR4fn+vucSKqqg6HQ9u1a6dvvPGG1zKcOnVKO3bs6JwnNTY2VmNjY3XZsmWmjsHq8VQ0YcIE7dKli6r+Nnful19+qU2aNNFx48Z5Xa9Lly46efJkl/ccDodec801zsetiIkpIVRVP/74Y01LS1MR0aioKH344Yedn7377rt69dVX68GDB7WkpESfffZZbdOmjZ45c8ZlGwsWLNBGjRqZOWRTdTRmzBgdNGiQ2888tbeqan5+viYkJOiWLVu8lmHPnj3aoEEDjY+PVxHR+Ph4TU9P159++snUMVRkdz8vt2bNGsuP2nXXh83kDSt9XNVcHV199dX67LPPuv3MW5uvW7dO09LS9OTJk37tvyI7c3H5sTZu3Nj5aPaZM2dqQkKC7tq1y7nc7t27tW/fvioiWqtWLW3YsKHzUcPlAp2L/V2vJo5xqr7X7dSpU7V27dpaq1YtZ57605/+ZHnaG7vjv5zZHGUU22bbnfh39eqrr2rv3r2d/zY6Rwhl/Ffn/F+RmbzTq1cv7d+/vx49elRPnDihgwYN0qioKH3qqaecy0Ri/le1vw94q7d9+/apiFQ5D+zatatOnDjR5b1Q1K1d+V/V/jGg3M0336zXXnttlfcjMf7tjv1yZtvAU66KtPyvqvrZZ59pXFycxsbGqohoQkKCtm3bVgsLC00fhzt2TQmxcuVKjY6OrlL+77//XkVEd+3a5XYaEbNT3lRkduoRb1NNeWNmGqqKrEwv42uZrK5rZho/o21anWqlnN39K9Qx7MtUaEbTbJmZhssMszHjSz90NzWSJ1b7lKpxvZqJ8WDGcCDX8zX2zPbzioza2pe2csds7JnJn/70B1+nKvR2DMGYqrZcJJ6fl/M1jq1OU6hqHMf+TPvmy/pmlvenb1ld18w0dcHKoZGSP32Ju0CMS95YjTszY7c/ZbKaP43i1OzxRer5p2r4fr/zR1jfsNCwYUN95513VPW3CwXdu3fXu+66y9S6f/jDH6r8gF1ZSUmJJiQk6PLly01ts6ysTFNTU/XHH3+s8tl7772nderU0dWrV1f5LNA/Xv9//9//p+PHj/f4ubdgf/rpp/VPf/qT1zJMmTLF+cN1xVezZs0sf1kJ1cVbdxevrP4YUZm7i1NmLgqqBv7CYNu2bXXRokVuP/PW3qq/nTR4SozlbrvtNo2JiXFp7+joaL3hhhtMHUNF4dLPrV4I9taHK3KXN6z0cVXjOjp9+rSKiO7bt8/t597a3OFwaEZGhn766ac+778yO3PxiRMnVET08ccfd3m/bdu2Om3aNFX9LTdnZmbq8OHDNT8/X0tLS/XDDz/UtLQ0l5t1Ap2L/V2vJo5xqr7VbX5+vtauXbvKuBQXF6crV640vR1f9m9njjIb2xV5anfi/3927typjRs31j179jjf83aOEMr4r2n531veUVU9ePCgDhkyRJs2barNmjXTl19+WVNSUnTGjBnO9SMx/6va2weM6q187M3JyXFZr23btjplyhSX94Jdt3bmf9XwOE89cOCAxsTE6Mcff+zyfqTGf7ic/1hpA3e5KtLyv8Ph0MzMzCp9KT4+3vC7ohG7bliYNGmStm3btsr7M2fO1Pr166uq6qhRo3To0KEun2dkZDi/R6iqHj9+XGNjY3Xt2rUe92XmAmpubq62aNFC9+7d69PNARV99NFHmpKSYricURz7Uyar615++eX6yCOP+LXN7Oxsn36otLt/hTqGrV7QP3nypEZFRbmM6z///LOKiH7++eeGn5tlJWZ86YcXXnihjh071nR5KjLTp4zq1UyMByuGA72er7Fnpg4qs9rWZvNfRb7kOk/509/+4OsNC96Owcw2Qxl7dp+fl/M1jis6c+aMvvTSSyoizh+T3TEbx7788Zw/61tZ3pe+ZXbdSy65RKdOner8d1FRkYqIbtiwwflesHJopOTPiszGXSDGJTPMxpGZfuBPmfy54UvVc5waHV+knn+G8/c7f5ieEqKwsDAgL7P27t0rhw8fdk4NULduXRk/frzMnTtXjh8/LiIi69evd3ksyD333CPLli0TEZFOnTrJ1q1bve4jKipKoqKiXB41643D4ZDS0tIq0yPMnj1bRo8eLR9//LFcddVVVdb78ccfXR6paoa3Ojxy5IikpaV5/LyoqEhERIqKiqp8lpaWJkeOHPG6/YULF7p9DMrBgwflhx9+CFqbi/z2OKnZs2fLiRMnJC8vT7p06SKbNm0yfCxN3bp1XeYU3bVrl0ycOFFmzZplaf+Vt/nAAw/IsGHDZOvWreJwOKRXr17SvHlzyc/PlzNnzsjMmTOlf//+8sMPP7isW1hYKHXr1rW0P291mJ+fLykpKZbbu7CwUNLT0+XgwYNet/+f//xHzp0751Ieh8Mhn376acT3czOM+nBF7vKGL31cxHOb5+bmiohIYmKi5TYvKiqS+vXry4EDByKmjbzl4rS0NMnMzKySAyr++/jx4/LLL7/IAw88IOnp6RITEyNZWVmSmZkpK1ascC4X6FzsT93aXa/uhHKME7FWtytXrpSYmJgq2ygtLZWPPvqo2uYos7Fdkad2J/7/54svvpBjx45Jp06dpH79+lK/fn0REcnKypJ77rnHZdlQx39Ny/+e8k65xo0by5w5c+TAgQOyf/9+ufrqq6WoqEiuvPJKEYnM/C9ifx8wqre0tDTJyMiQDRs2ONcpKCiQXbt2yWWXXeayrWDXrV35X8T+MaDczJkzpUWLFtK/f3+X9yMx/u2OfV+5y1WRlv937twpv/zyS5XynDlzRhYsWOBTm1duf3/XtyonJ0e6dOlS5f1vv/3W+X7laUQKLEx5U5m3qUfUh6mmvHE3DZVV/pTJ6rpmpvEzs01/p1qJhPOrinyJ4XJWp0Kr+N+K/79p0ybT03B5YyVmfOmHnqZGMstsn/JUr2anqgxWDIdD7Jmtg4p8aWur+S/Q+TcQ/cHqVFVmjiHYU9VGyvl5Rf7kUCvTo/pz7hBO/Dm3MFrXaJq6UOTQcM6f5axOyyvi/7gUKGb6QSDK5M9Uf77GeKSef4b79zuf+5zZOxuk0p0a/rzM3JnxwQcfaFJSkstf9JeWlmqdOnWcj+g4e/asXnTRRaqq+t133+lNN93kXHblypXaokULl/XnzZunhw8fVlXVvLw8HTp0qGZkZHh8RMaUKVP04MGDqqp6+PBhHTFihNapU0cPHTrksky9evWq/AVSRV27dtVZs2YZHrPq/+5eqW4vM22+Z88eFRHdunWr871ly5ZpXFyc826zsrIy7d27t/bs2VM7deqkzZo1U1XV0aNHu/xlzhtvvKG1a9fWevXqOV8ioqmpqTpq1ChTbaH6W8wlJCTookWL9OjRoyoiVf6qtUOHDlX+0mfChAl63XXXmdpHTW7zYPTzc+fOaXFxsS5fvlxFRIuLi7W4uNjj00GM+rCZvGGlj6uGT5tHSi5+4YUXtEmTJrplyxY9d+6cvv7665qUlKS7d+92LnPRRRfp3XffrQUFBVpWVqaLFy/W2NhYl7vSQ5mLjeo2HOrVjjFOlfi3mqOMYttsuxP//3Pq1CnNzc11eYmIzp8/3+XuduI/8O1kJu9UtH37dj1y5Ig6HA798ccftVOnTjp8+HCXZSIt/6va3wfM1NukSZM0MzNTd+zYoSdPntSRI0e6fVRzJH7PMftXAuEwBpSWlmrTpk09/oVEpMV/OMS+mTYwk6siNf+H88vqX/C0aNHC5a+8yrVv314nTJigqlWfxGhlypuKjKYe8ffpjhV5mobKHW9/MeZPmayua2YaPzPbtDrVSrlw6V+hiGFV36bCMZpmy8w0XN5YiRlf+qGnqZHMMNunvNWr2akq7YrhUMSe2TqoyGpbW8l/5XzNdd7ypz/9wZf+aXQMwZiqtlyk5k9V33NoRWamKbQSx+H6hAVf+paVdY2eSB3MHBoJ+bMyM3GnGphxyQwzcWSmH/hbJn+mOvYWp0bHF+n5M5JeZpjOgAUFBX6/yoPWTCIYO3asdu3atcr7Q4YM0b59+zr/3b17dz106JBeffXV+ssvv7gse8kll+hHH33k/Pf111+v9evX14SEBG3atKneeuut+vPPPzs/HzlypPbr18/576ysLG3UqJEmJiZq48aN9YYbbqgS9CKiMTExmpSU5PLau3evqqpu3bpVGzZsqKdPnzY8ZtX/BXpubq7Herzvvvt08ODBHj8vTyD79u2r8tmwYcP0rrvu8tpOn3zySZVHO9WuXVuvueaaoLa5mQtY5Y4cOaIDBw7U//73v6pa9eKV2R8jKjO6OGXmoqCqbxcGvbV5t27d9LnnnrPc3gUFBdqxY0d95ZVXvLbTM888o3FxcS5tHhcXp0888UTE9fM33njDbUIsb6PK/dyoDxvlDat9XNW4zfPz8zU1NVVXrFhhuc1//fVXTUlJ0c8//zxs28hqLnY4HPrkk09qkyZNNCUlRf/4xz/qZ5995rKPn376SbOysrRBgwaakpKiF198scvJYTBysT91Gw71ascYp+pb3R4/flwzMjI0OjrapV/Hxsbq1q1bq3WOMopto3ZXJf5Vq9ZrZRXboOJ7oY7/6p7/jfJO5XaaPXu2Nm3aVBMSEjQjI0OffPJJPXfunMs+Ii3/q4ZHHzCqt7KyMn300Ue1QYMGmpiYqH369HG5UVA1NHVrV/5XDY8xYMGCBRoXF6dHjhxxW8ZIi/9wiH2jNlA1zlWRmP8LCgr0xhtvdM5vWrEv/fvf/7bU3p7a32rc+No3VVUPHTqkIlWnrjl27JjWqlXL+fjUytOIWJnyxpuKU49YnWrKG7PTFJbzdAHWnzL5sq7RNH5mt2l1qpVydvevUMawO2amwjGaZsvoc2+sxozVfuhpaiQzrPapiirWq5mpKlWDF8PhEHtm66AiK23tS1v5k+u8/YDlT3+ozKh/+nIMgZiqtlyknZ+XC2QONZqm0Eoch+MNC/7kQTPrmpmmLpg5NBLypztGceeOL+OSGWbiyEw/CGSZVM1P9WcUp0bHF6nnn+H8/c7TywzfM6gPyhvR6iDkzZgxY3TQoEGanZ1d5bPVq1drhw4dPP7FSigMHDhQX3/9ddPLm6mjLVu2aHx8vB47dszSNgoLCzU5OVnXr19vWI5p06ZpYmKi80fsHj16eNyfN1ba3OwFrH379mlWVlaV+V8qX7yqzN0Jn9Uf8IwuCqr6fmHQWx298cYb2rZtW3U4HJbW37BhgyYlJemJEye8lqGsrEzvvfdejYmJ0fj4eBURveOOO7S0tNTUMVg9HqvCuZ9b7eOq5urovvvu0zvuuMPy+jNnztTLLrvMbaxY2b9V4dxGqsHJxYFcz5PqVq+qvtfRzp079aKLLtKYmBgVEU1PT9dPPvnE0jb82b831a2diH9zyP+/qW7tFC7xr0rdlgvn/K8a3u0UqfEfznWqGpn5v3wbffv21Vq1aqnIb/ObvvDCC5aOw2rZgrX+hg0bVESq/LXW1KlTtWHDhs7vsZWfxKj62/y706dPd/77xIkTGhcX53E+dXdKS0s1MTFRly1bFrCnO86aNUvT09P1yy+/NL2Opwuw/pTJ13UzMzP1iSeecHmvXbt2Om3aNNPbtPKkyors7l+hjuHKKsajWVu2bFER0e3bt/v0eUW+xIyVfpidna2tW7e2nPd96VMVVa5XbzFeLpgxHKj1/Ik9M3VQmZm29rWt/Ml1Vn4YttIfKjPqn74cg7tthjr27D4/D3QOLX+6sidmc1a43bDgTx40u67ZJ1IHK4dGSv6szEzcuVvH6rhkhtm4M9MPAlUmVXPnN2bi1Oj4IvX8s3wb4fj9zh8Rf8PCokWLtFWrVlpcXBywbdrJbB316NFDn3vuOUvb+Oc//6mdO3c2XZaTJ0/qypUrQ37xwZv//ve/OnDgQLd/ZRQOF69Ug3Nh8PTp01q3bl1dtWqVpfWHDh2qI0eONF2Ww4cP66effhpWba5aM/v5tm3bNC4uzu1jsj2tX1ZWppdeeqnOnDnT7/1bVRPbKJDreVLd6lXVvzpyOBz6zTffqIjo0aNHQ75/T6pbOxH/wUP+D3/hEv+q1G1F4Zr/VatXO4VL/FenOi1nd/6vqPyHl/3795s/AC/suGHh5MmTmp6eriNGjHA+snvu3LmakpKib775pnM5d9OImJ3ypiJvU4+Yfbpjdna2ZmRkuN2+mWmoKjKa2sRMmTyVx9enVXqbxs/sNq1OtVLO7v4V6hi2OhWOqvE0W2am4QpkzJjth96mRgpkn1I1rlczU1UGM4YDtZ4/sWemDiozamszbRXI2DMzNZRRf/AWe1b7p5ljCMZUteUi9fzcnzi2Ok2hqnEcm4krb3Fjddo4s1OceetbgcyhZp5IHawcGin505e4C8S4FMi4MzN2G5UpkPnTKE7NHl+knn9WFG7f7/wR8TcsPPTQQ7p48eKAbc9uZutoxYoVmpSU5PbuIXfbyMnJ0eTkZF2yZElQyhOs9Str1qyZdurUSXv27Kk9e/YMWCe0k9k6eu6557R58+aam5trav133nlHU1NTdceOHUEpT7DWd6em9vM///nP2r179ypP63C3vsPh0Iceekh/97vf6cmTJwOyfytqahsFaj1Pqlu9qtqfY4h/Y8R/8JD/w1+4xL8qdRtu63tSndopXOK/OtVpObvzvy9lCdX2fF3/66+/1iuuuEJTUlK0bt262r17d7d/pVb5SYxmpryp/CRGM1NwVSRS9emOQ4cO1TvvvNPj8t6mofJlahOjMnkrj9G67qbaMjONn7dt+jLVSjm7+1eoY9hMPFqdZsvMNFyBjBkz/VDV+9RIgexTqsb1ahTjoYjhQK3na+yZ6edW29qorVQDG3tm8qdRf/BWHn+nKnR3DMGYqrac3efX/qzvaxybmR7VahybiStvcWN12jgz+zPqW4HMoWaeSB2sHBop+dOXuPN3XFINbNyZGbuNyhTI/GkUp2b6SSSff/pSFru2Z0XE3rCQm5urWVlZ+sgjjwSgZOHDSh3NmDFDk5OT9YMPPnB5PEjFbTgcDl2yZImmpqbqSy+9FNTyBGP9msBsHTkcDh05cqS2bNnS5c6xyuuXlJToSy+9pElJSbpixYqglSdY61dU0/v5qVOntHv37tqtWzeXKVAqr19YWKgjR47UJk2a6M6dOwO2fzNqehsFar3Kqmu9qtqfY4h/Y8R/8JD/w5/d8a9K3Ybr+pVVx3ayO/6rY52Wszv/+1KWUG0v2NcMwuVJjOedd16VaS3tFG7l8WWqlXJ29y9i2B7hVp5QxHCg1jOL2HMv3MpjR+yFy/pmEMfuhVt5fI1j8qd34dbO4VaeSD7/9KUsdm3Pioi9YaG6slpH77//vtavX18vuOACffnll3XHjh26Y8cOFRGdPHmytmvXTuvWratvv/12SMoT6PVrAit15HA49O9//7smJCRo9+7dde7cubp582YVEf366681OztbmzRpoq1bt9Z169YFvTzBWL8msFJHp0+f1jvuuENr166tAwcO1GXLlukPP/ygIqKrVq3S0aNHa3Jysv7xj390uQM9UPuvqcL1hLc6sDvH0EbGiP/gIf+HP+I/eOzO37SRMeI/eOzO/76WJRTbI37gL7v7FzEMfzH+wi52j+HEMPxF/oRd7D7/9LUsdmzPimhBRLvllltk//798re//U3mz58vl1xyiVxwwQUiIvLee+/JmDFjZP/+/XLHHXfYXFIEQlRUlPztb3+TAwcOyM033ywTJ06UTp06iYjI1VdfLRs2bJBZs2bJzz//LF27drW5tAiEhIQEefvtt+Xnn3+Wiy66SP7yl7/IJZdcIiIiAwcOlNOnT8vq1avl66+/lpYtW9pcWgBAoJD/AaBmIv8DwUP/AgAAQChx/mlejN0FgP/i4uJkyJAhMmTIEBERKSkpkTNnzkhKSopERUXZXDoEQ3p6ujz44IPy4IMPisPhkOPHj0vdunVp72osIyNDnn76aXn66aelrKxMCgoKJD09nTYHgGqO/A8ANRP5Hwge+hcAAABCifNPY9ywUA3FxsZKbGys3cVAiERHR0u9evXsLgZCqFatWlK3bl27iwEACDHyPwDUTOR/IHjoXwAAAAglzj/dY0oIAAAAAAAAAAAAAAAQctywAAAAAAAAAAAAAAAAQo4bFgAAAAAAAAAAAAAAQMhxwwIAAAAAAAAAAAAAAAg5blgAAAAAAAAAAAAAAAAhxw0LAAAAAAAAAAAAAAAg5LhhAQAAAAAAAAAAAAAAhBw3LAAAAAAAAAAAAAAAgJCLsWOnhYWFduw2IlTXuqmuxxUI1bVuqutxBUK41E24lCMc+Vs31K1n4VI34VKOcET8B0+41E24lCMcEf/BEy51Ey7lCEfEf/BQN8aoI/gqXGInXMqByMP4C7uES+yESzkQecifsAuxExwhvWEhNjZWGjduLC1atAjlbiNO48aNJTY21u5iBARtbg5tXvPY2ea0kTm+tBF1aw7xH/6I/+Ah/sMf8R88xH/4I/6Dpzp95wsk4geBwPiCSMf4C7uQPxHpyJ+wC9/vAi9KVTWUOzxz5oyUlJSEcpcRJzY2VuLj4+0uhoj8dqdQWlqaFBQUSGpqqk/boM2N0eY1j91tThsZ87WNqFtj/sQ/OSo0iP/gIf+HP+I/eMj/4Y/4Dx6783+5QPSlQG+P+IG/7O5fxDD8xfgLu3B+jkhH/oRd7D7/LBeO3+98FfIpIeLj48OiERE6tHnNQ5uHP9ooeKjb8EcbBQ91G/5oo+ChbsMfbRQ81C38Qfwg0hHDsAuxh0hHDMMuxB4QfqLtLgAAAAAAAAAAAAAAAKh5uGEBAAAAAAAAAAAAAACEHDcsAAAAAAAAAAAAAACAkOOGBQAAAAAAAAAAAAAAEHLcsAAAAAAAAAAAAAAAAEKOGxYAAAAAAAAAAAAAAEDIccMCAAAAAAAAAAAAAAAIOW5YAAAAAAAAAAAAAAAAIccNCwAAAAAAAAAAAAAAIOS4YQEAAAAAAAAAAAAAAIRcTKh3eObMGSkpKQn1biNKbGysxMfH212MgKHNjVW3NgdqMnKeMbtzHm1kzO42AiIRucWY3bmFNjLmaxtRt8bsjn8AQPXD+At/2X1+QgzDX3x/gV3szp/VUUhvWDhz5oy0bt1aDh06FMrdRpzGjRvL7t27q0Ww0+bmVKc2B2oycp45duY82sgcxiXAGnKLOeT/8OdLG1G35jC2AgACifEXgcD5OSId319gF77fBV5Ib1goKSmRQ4cOSW5urqSmpoZy1xGjsLBQWrRoISUlJdUi0GlzY9WtzYGajJxnzO6cRxsZs7uNgEhEbjFmd26hjYz52kbUrTG74x8AUP0w/sJfdp+fEMPwF99fYBe782d1FfIpIUREUlNTSQQ1DG0OoCYh54U/2ghAMJBbwh9tFDzULQAAocf4i0hHDMMuxB4QXqLtLgAAAAAAAAAAAAAAAKh5uGEBAAAAAAAAAAAAAACEHDcsAAAAAAAAAAAAAACAkOOGBQAAAAAAAAAAAAAAEHLcsAAAAAAAAAAAAAAAAEKOGxYAAAAAAAAAAAAAAEDIccMCAAAAAAAAAAAAAAAIOW5YAAAAAAAAAAAAAAAAIRdjdwEQfsrKymTZsmWycuVKOXz4sIiITJkyRUaOHCkNGza0uXQIhuLiYpk/f75s2LBB8vPzRUTkrbfekmHDhklSUpLNpQMAkV9++UXmzJkjv/zyi4iIjB8/Xm699Va5/PLLJSoqyubSAQCChfwPBMbRo0dlzpw58sMPP4iIyLhx46Rfv34yYMAAqVWrls2lAwAAkYLzcwCwX3X8fletn7CwZs0a6dixozgcDtvKMHDgQHnzzTdt278VJSUl8vzzz8vvfvc7GTFihJSWlkrjxo1FRGT58uXSsmVLGTJkiGzdutXmkiJQjh49Ko888og0a9ZMnnvuOYmLi5MmTZqIiMj06dOlWbNm8tBDD0leXp7NJQVQWU0Z49auXSvXXnutXHTRRbJ582ZJSUkREZG8vDzp37+/dOzYUd58801R1aCWw1d2t1MknYcAMMfuvCJC/jejprRTqFGv1u3YsUPuvPNOadGihXz44YcSFxcnIiJnz56Vv/71r5KZmSnPPPOMnDlzxuaSAgCAcBbp5+cAUB1U6+93GkIFBQUqIlpQUGB6nVatWmlcXJwmJSVpcnKyduvWTTdt2mRq3fbt2+tHH33k9rMbb7xRRUTXrFnjdRufffaZdu/eXZOSkjQ9PV1vuOEGl8/Lysr0scce04YNG2pSUpL27dtX9+zZ4/z8xx9/1EaNGmlxcbGpMvtSR4FQWFiovXr10vbt2+uCBQu0pKREVVVzc3NVRDQ3N1d37Nih9957r6akpOjy5ctNbTeUx7N69Wrt0KGDlpWVBX1fntx44436xhtvWFrHrjbftWuXnn/++dq3b19du3atOhwOVf1fm+/bt0/XrVun119/vbZq1Uq3b98e0vIBkchqfw7kGPfee+9p9+7dNSUlRa0O797GRG/joNUxTtVaHf3rX//SpKQknTBhgv7666+q6jounTx5Ul977TVt1qyZDhs2TM+dOxfQ/Zezs53Gjh2rbdu21ZSUFG3SpIkOGzZMjx496rKMnW0E4Dd25n9V4+8sFRl9f1FVbdu2rSYlJTlfCQkJKiK6cOFCVSX/m1G5nSZOnKiZmZmampqq9erV0z59+njdlpnxIjs7W6Ojo13a6tZbb3V+HqrvonbGv9V6PXbsmA4bNkybNGmiycnJesMNN2hubq7H5d2dI0XS2LpmzRpNS0vTESNG6NatW1XVtS+Vlpbqhx9+qB07dtTu3btrfn6+5X1w3gAA9iD/wl+ReH4OVBSq7y9AZXy/C46wvmHhyJEjKiL61VdfqapqUVGR9uvXTzt27Gi47ooVK7R58+Zuf7x+6623tE+fPoY3LKxdu1ZTU1N1zpw5evr0aT179qyuX7/eZZlJkyY5f8wtKirSESNGaPv27V32e/nll+vs2bNNHbMdwVBSUqLXXHON9urVS4uKilw+qxjs5d59911NTk7Wb775xnDbobwwWPnilZmLsRUZXZg1uiCoGjkXr/Ly8vS8887T++67r0ofqdzmDodDx4wZoy1bttQDBw6ErIxAJLLSnwM9xi1btkznzp2rs2fPtnTDgrcx0cw4aGWMUzVfR3PnztWUlBT98ssvXd53Ny7t379fL7zwQr333nudN1/5u/9ydrfTY489phs3btSSkhLNy8vTa665RgcMGOD83M42AvA/duZ/M3mgIjPfXyqbMmWK1qtXz+Ucl/zvmbt22rFjh/NiwdmzZ3Xy5MnauHFjj/VuZrzIzs7Wnj17ei1LKL6L2hn/Vut1wIABOmDAAD1+/LgWFRXprbfeqpdddpnl6waRMLZu3LhRU1JSdNasWS7vu+tLp06d0muvvVZ79uypZ86csbQfzhsAwB7kX/gr0s7Pgcq4YQF24ftdcIT1DQuffPKJxsbGulToxIkTtVmzZobrjho1SocOHVrl/dzcXG3RooXu3bvX8IaFyy+/XB955BGv+8nIyNBp06Y5/338+HGNjY3VtWvXOt/Lzs52+XHBGzuCYebMmdqmTRstLCys8pm7YFdV/cc//qHt2rULmwuD7i5e+XIxtqLKF2bNXBBUjYyLVyNHjtQbbrjBbV24a3OHw6G33HKL3nHHHSErIxCJrPTnYIxxqr/daWn2hgWjMdHMOGhljFM1V0eFhYWakpKiS5YscVtmd+PSnj17NC0tTb/44gu/919ROLRTRR999JGmpKQ4/21XGwFwZWf+N5MHKjLz/aWyCy+8UMeOHevyHvnfM2/5X1X1zJkz+tJLL6mIGP7Fg7fxwsz3k1B8Fw2H8x9V43o9efKkRkVFaU5OjvO9n3/+WUVEP//8c5dljc6RImFs7dy5s2ZnZ1d531NfOnXqlLZv315ffvllS/vhvAEA7BHs/BsOT7KFMV+e9lsu0s7PfUEch79gx3Ag17OC2Atv/sSdKt/vgiVawti3334rl112mcTFxYnD4ZB169bJtGnT5Pbbbzdcd+PGjXLxxRe7vKeqMmzYMBk/fry0bNnS6/qnTp2S9evXi4hI586dpV69enL55ZfLqlWrnMsUFBTI3r17pXPnzs736tSpI+eff75s3rzZ+V779u0lJyfHzCGHnKrKtGnT5JFHHnHOO2XGX//6V/n111/liy++CGh5cnJyJDY2Vjp27CgiIsnJydKtWzfJy8vzut7ChQuld+/eEh39v5CeMWOGjB07Vi644AJJTk6W5557Tnbs2CFffvmlqbJMnz5dhg8fLvHx8ZaOoU+fPrJo0SJL64RSQUGBzJkzR7Kzs13qy5uoqCjJzs6W+fPny9GjR4NcQqBmCPQYZ5XRmGhmHBQJzhj37rvvSps2bWTAgAGm18nIyJC77rpLpk+fHtCy2N1Ola1atUouvfRSEbG3jQD4LpB5xWweKGf2+0tFq1evlp9++klGjRrl8j753zNP+X/p0qVSp04diY+Pl4cfflgefvhhSU9P96ucGzZskAYNGkhGRoYMHjxYdu/e7fJ5uI0Bdtar/r/5lLXCvMrl/79p0yaX94yuG4RbvVaWk5Mj27dvl//7v/8zvU5iYqKMHTtWpk+fbmru6U2bNsnAgQPlkksuERGR7777zufyAgBCp6CgQKKjo2XNmjUu75eVlUlycrLMmzdPREQeeOAB+fvf/+68djhv3jzp0aOHpKamSlRUlKl9Ga2Tn58vw4cPl6ZNm0pKSopkZWXJ/v37TR/LU089Jeedd56kpaVJ/fr1pW/fvh7Pac0eg9VtVjRhwgSpVauWJCcnO1+33Xabx+XHjRsn7dq1k9TUVGnatKkMHz5cjh07ZqksTz31lDz66KNBm6s8nM7PK/I1jn1pX6N2dTgc8vjjj0ujRo0kOTlZ+vXrJ3v37jV9LFbjxsz+/Iljq8fTrl07l7InJiZKVFSU8/cRo34e7BgONF9jz6i/u5OXlyeDBw+Whg0bSp06daRr167y+eefu1124MCBEhUVJZ999pmp47AaI0btbDWOK7OyvlFZyq1du1Z69OghycnJUrduXcnKynI5/kiKuxrz/S6Ud0dYvTPjuuuu09jYWE1LS9OYmBiNjY3VV155xfCv+lVVf/e73+lrr73m8t6rr76qvXv3dv5bvDxhofyulMaNGzsfxTxz5kxNSEjQXbt2qarqvn37VET0p59+clm3a9euOnHiROe/V6xYobVr1zZ1zKG+e+Wrr77S1NRUPXnypNvPPd2do6r6f//3f3rLLbd43b7V45kwYYJ26dJFVX+b0uHLL7/UJk2a6Lhx47yu16VLF508ebLz3ydOnFAR0W+//dZlubZt2+qUKVMMy7Fq1SqNjo7WX375xfledna2JiUlaf369bVly5Z62223uXxebsGCBdqoUSPDfZQLdZv/85//1D/84Q8eP/fW5ldeeaX+4x//CGbxgIhmpT8HeowrZ/Yv943GRDPjoKq1MU7VuI4cDoe2b9/e45NqvOWo7du3a2xsrObl5fm8/8rsbqeK3n//fU1OTtbvvvtOVe1rIwBV2ZX/zeaBcma/v1R0880367XXXlvlffK/Z97yv6rqsWPH9MUXX9QFCxYYbsvbePHDDz/onj171OFw6IEDB/SOO+7QzMxMl2n+QvFdNBzOf1TN1WuvXr20f//+evToUT1x4oQOGjRIo6Ki9KmnnnIuY+a6QbiPrUOHDtXRo0e7/cxbXyouLtb69evrqlWrvG7/m2++0djYWI2OjlYRURHR2rVre31SCwAgsHwdW1auXKnR0dFVnrT7/fffq4jorl27AjYNpdE6VqZqcicYU25Z3WZFZp/OW85oCkizZbH6tN9ykXZ+XpGvcexL+xq1q79PebYaN2b2508cB/qp1Wb6ebBiONDrqfoee0b93Z2bbrpJe/bsqUeOHNFz587p5MmTNTk5WY8fP+6ynLep7DzxJ0ZUfX86uSf+rO9uCstgTKFbEd/vgiOsn7CQk5Mjs2fPlhMnTkheXp506dJFNm3aZOouzrp160pBQYHz37t27ZKJEyfKrFmzTO27/GkDw4YNkw4dOkjt2rVlxIgR0rp1a1m+fLmIiKSmpoqIuOxHROTEiRPOz0RECgsLpW7duqb2G2pff/219O7dW5KSkiyve8MNN8jXX38d0PLk5OTI5s2bpU6dOhIXFydXX321PPbYYzJp0iSv6x0/flzS0tKc/y4sLBSR3/5irKI6deo4P/Nm2rRp0q9fP2ndurXzvT/96U+ydetWOXz4sHz99dcSExMjvXv3lpMnT7qsm5qaKvn5+Yb7sMvXX38tN9xwg0/rBqPNgZoqkGOcVWbGRDPjoEjgx7hTp07JDz/84FOeuuCCCyQzM1M2btwYsPLY2U4VzZs3T0aOHClLlixxPoXIrjYC4J9A5hWzeaCc2e8v5X799VdZvHixjB49uspn5H/PjPJ/3bp15YEHHpBhw4bJ1q1bfS7jxRdfLBkZGRIVFSVNmzaV2bNny8GDB+Wrr75yLhNuY4Dd9TpnzhypW7euXHLJJdKuXTvp1q2bJCcnS/369UXE/HWDcKvXyr766iuf+lJ8fLz07dvX8DvfY489JiUlJeJwOJzvlZaWytixYy3vEwAQWjk5OXLhhRdWedLu+vXrpX79+pKZmen2SbZ9+/aV2267TTIzM03vy9s6p06dkqVLl0p2drbUqVNHkpOTZeLEibJ582ZZt26dqe23adPG+VQlVZVatWrJoUOHPJ4vmDkGq9v0xzPPPOM8h2/YsKHcf//9snbtWstlCdbTfsPt/LwiX+M4GO3r71Oeg7E/f44zkE+tNtvPw/2J1RX5GntG/d2dnTt3yqBBg6R+/fpSq1YtGTlypJw8eVJ27drlXGb//v0yfvx4ee211ywdh799wdenkweDu7I8+uijcvfdd8uQIUMkISFBYmNjpUuXLi7rRVLc1ZTvdzFmFzTzI28gt7F37145fPiw86J83bp1Zfz48ZKVlSUvvPCCpKeny/r16+Xll1+W9957T0RE7rnnHsnKypJ+/fpJp06dXC5SfPHFF3Ls2DHp1KmTy36ysrJk8ODBVR5RlJaWJpmZmVUunFT8d1pammRkZMiGDRucj1UtKCiQXbt2yWWXXeZc7scff3R57KoZgahvM44cOSKJiYke91dUVOT8b+VlateuLQUFBV7LavU4yi9g3X777ZKfny9ZWVmmLmBVvnhl9WJsReUXZj/88EOX9ys+frT8gmBaWpp89dVX0qdPH+dnvl68ClWb5+fnS1xcnE9tHh8fL8eOHQtZWYFIY7ZvBHqMs8rMmGhmHBTxbYwT8VxXBw8eFBGR6Ohot8t4y1Eiv/14d/DgQY/bt/NcxFezZ8+WMWPGyMcffyzdunVzvm9XGwGoyq78bzYPVFzezPeXcjNnzpQWLVpI//79q3xG/vcv/zscDiktLZWff/5Z2rVrZ7ps3kRFRUlUVJTL4x5D8V00nM5/jOq1cePGMmfOHOe/f/jhB3nwwQflyiuvFBHz1w3CfWwtKCiQ2rVr+9SXEhMTJS8vz2tZPf348P3333P+AAAh4mu+zcnJqfKjjchv0zaVv79x40a55ZZb/CqfETWYqqlHjx6mtrN06VIZMmSIFBQUSFRUVECm3PJnm+XTdSUmJkq3bt3k6aefdvmDOG8qTgFppSzt27eXGTNmmDs4NyLh/Lwyf+LYl/b11K5GU+5dccUVpo7HbNxY2Z8vx+nv8VSeTtBsPw9WDAdq+YoClUPd9ffKxo0bJ7Nnz5abb75Z6tWrJ6+++qq0adPG+TuVmpjKzhtfc52naSP9yX++ru+uLOVTZ3br1k06d+4su3fvljZt2shTTz0lvXr1ci7nb9yJ8P3OCqPfZUXE/LOI5f89BiIQLzOPyfjggw80KSnJ5REkpaWlWqdOHedjOs6ePasXXXSRqqp+9913etNNNzmXXblypbZo0cK5/qlTpzQ3N9flJSI6f/5856NPKnvhhRe0SZMmumXLFj137py+/vrrmpSUpLt373YuM2nSJM3MzNQdO3boyZMndeTIkVUekdO1a1edNWuWqXouf5RIdXuZafM9e/aoiOjWrVud7y1btkzj4uKcbVRWVqa9e/fWnj17aqdOnbRZs2aqqjp69Gi96667XLaXkZGh06dPd/77xIkTGhcXZ/gYk+zsbG3durXh429KS0s1MTFRly1b5vL+hAkT9LrrrjM83nLVtc158arJL6OcF+gxTlX13LlzWlxcrMuXL1cR0eLiYi0uLnaby8yOiWbGQStjXDjlPDvORay2k+r/HmuWk5Pj9vPq3Ea8eEXiy478byYPVGTm+0t5uZo2barPPvus2+1Eam6xK/9PmTJFDx48qKqqhw8f1hEjRmidOnX00KFDbstgZryYN2+eHj58WFVV8/LydOjQoZqRkeHyeNJQfhe1I/6t1uv27dv1yJEj6nA49Mcff9ROnTrp8OHDnZ+bPUeK1PjnxYsXL17V72X1cdQtWrTQadOmVXm/ffv2OmHCBFUN/PSGntYxM1WTWYGacsvXbaqam67Lk8pTQFopi9WpqsqFy/mJL49U9zeOVc23r7d29WXKPSvbr8yX/VmJY3+Px910gmb6uV0xbFfsGfX3crt379a+ffuqiGitWrW0YcOG+tVXXzk/NzOVnRlWc527dvYn//mzvruyBGsK3YrCJX9G0ssM009YCMRjjwoLC6VFixamls3JyZFLL73U5bEpMTExct1118n8+fNl2LBhEhsbK/Xq1ZO8vDwZM2aMy2Mbe/XqJenp6fLJJ5/IgAEDJDExURITE6vsp0GDBs67hkaNGiV79+6V//znPyIi8tBDD8nJkyelb9++cvLkSWnXrp0sXbpUWrVq5Vx/7NixUlBQIN27d5dTp05J9+7dZcmSJc5yb9u2TXbu3CmDBw+2VFe5ubnm7jjx0/Lly+Whhx6SLVu2SExM1XAoKCiQli1byr59+1ymXBAReemll+Szzz6TxYsXe9y+1TZPSkqSCy+80Pler169JCEhQRYtWiTDhg2T6Oho+fTTT+Xo0aNy9913O/865qabbpK77rpLHA6Hs+5HjRolzz//vFx99dXSrFkzGTdunLRp00a6d+/usQznzp2T1157Te6//36X2BMRef/99+Xqq6+WBg0ayOHDh2XcuHHSoEED6dq1q8tyK1askGHDhpk65opC1eb/+Mc/ZOPGjfL++++7/dxbm995553SqlUrefLJJ4NeTiASmc15gR7jRETeeecdueuuu5zLJCQkiIjImjVr5Morr3QZ48yMiSLG46CvY5yI55zncDikXbt28uKLL7r9i15vOerw4cPSrl07Wb9+vcdHPNp5LiJirZ1ERB544AGJiYlx/uVnuW3btknLli1taSMAVdmZ/43yQOW8YvT9pdzixYvl2LFjMnz48CrHQf633k6rV6+WZ555RoqKiiQ1NVW6dOkiq1atkkaNGolI1XYyGi9ERN59912577775NSpU5Keni5XXHGFrFy50vl40lB9F7Uz/q3W67p16+Rvf/ubHD9+XBo2bCjDhg2TJ554wrkPM+dIkTC23nrrrXLppZfKY489VuUzb33J4XBIx44dJTs7WwYOHOhx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", + "image/png": "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kksu0YSEBG3YsKHWr19fExIS9Nlnn1WXy2W47h/+8Ad94YUXvN774YcfdMeOHepyuXTPnj163XXXaV5enpaVlfncRv/+/XXIkCF66NAhPXLkiA4fPlzj4uL0wQcf9Cyzfft2HTRokIqI1qtXT5s3b66ff/6513aWLVumDRo0MPWdrdaRW2lpqf7xj3/UxMRETUlJ0cTERD333HP18OHDlrYTbla/z9SpU7V79+6qqlpZWamfffaZtmzZUidPnhxwve7du+sTTzxR4/33339fGzZsqCKicXFxescdd/jdxuuvv679+vXTvXv3anl5uT766KParl07PXnypGeZgoICTU1N1aZNm2rr1q31mmuu0V9++cVrO2+//ba2aNHC1PdVDb7Nt27dqi1bttTk5GRNTk7W+vXr61/+8hc9deqUpe2Em5XvE+5jvKqioiJ96qmn9O233/b5+a5du1RE9KeffvJ6v2fPnvrAAw94/m0mD1g5xlWDb/Ply5drcnKypqSkaEpKitarV08fffRRS9sIZv+RbKc333xT09LS9Ouvv/a7jFEbFBYWqohoVlaWbtiwQcvLy3XWrFmanJys27Zt82zHjlwM1GXRkv/N5JWqjPqLQMuQ//2r3k5m+10ry5P/gejgZP5/7rnndMCAAZ5/i4iuXLnS7zasLu+vT4m1/B+KFStWaNOmTfXEiRM+P/f33crLyzU7O1vff//9gNsPtm4+/vhjjY+P19LSUq/3v/vuOxUR3bZtmy5btkxPO+00rays9Hx+9913e/qM/fv360UXXaRDhw4NuK9Vq1ZpRkaGzp07V48fP66//fabrl271vP50KFDdejQoXr48GEtKyvTq6++Ws877zyv/QZitUwFBQXat2/fkMocyJYtW7S4uFhVVX/77Td94oknNCsrK+D3Mdqfme/Yo0cPnTNnjqkyVuX08RXKuUOwcez2yiuv6MCBAw1zmZn6X7Jkic6bN0/nzJmjVm8XP/LII9qmTRv98ccftaysTMeOHaudOnXyGzNXXHGF9u3bVw8ePKinTp3SJ554QtPS0rzuYZqJc3+sxrCZ726mPHbHMAAgOHaff7qZ7bdVjfvWUM71VK33+8GcH06bNk2bNGni9zqiqmDO0Y3OwaOx764L13ehiOoBC82bN9fXXntNVX+/Udy7d2+94YYbTK37X//1Xz7/gF1VeXm5Jicn69KlS31+vnfvXh05cqRmZ2drq1at9JlnntH09HSdOXOmqv7+B/W8vDwdM2aMFhcXa0VFhb7zzjvasGFD/f777z3bsfIH7GAD/Y477tDExEQVEc8rISFBb7zxRkvbCTe7boyH+sdrVXODT8wMerHr5lWPHj20Xr16Xm2elJSkL774oqXthJuV7xPpY7yyslIzMjJ048aNNT47cuSIioiuW7fO6/0OHTrotGnTPP82ygOq9gxSOXnypGfwTdVX/fr19bvvvjO9nWD2H6l2euONN7RRo0a6YsWKgNswagN3W95zzz1e63Xo0EGff/55z7/tyMVAXRYN+d9sXqkuUH8RaBnyv3/V28lsv2tlefI/EB2cyv9bt27VrKws3bFjh+e9QDf/rC4fqE+JtfwfinHjxumtt97q9/NA3+3uu+/Wa6+9NuD2g827jzzyiHbo0KHG+7NmzdKmTZuqqur48eN11KhRAbfz3nvvaXp6esBlevTooXfeeafPz44ePapxcXFe/dXPP/+sIqKrV682+hpBlcnszVd/Zbbi5MmT+vTTT6uIeG5Sh2N/vr5jQUGB4Y1pX5w+vkI5dwgljgsLCzUnJ0d37txp6g8fVQWKsZUrV1oesJCbm+t17nX48GFNSEjQVatW+Vz+nHPO0enTp3v+XVZWpiKi69ev97wXyoCFqszGsGrg726mPHbGMAAgeE6cf1rtt4361nCd6wXT75vtW8866yydNGlSUOUyOh82cw4ebX13Xbm+C0V9f09eqK60tNTsomHZxs6dO+XAgQOeqQEaN24sU6ZMkfz8fHnyySclMzNT1q5dK88884y88cYbIiJy0003SX5+vgwePFi6du0qmzZtCriPuLg4iYuL83rUeFVZWVkyd+5cz79/+OEHue222+SCCy4QEZHDhw/LL7/8Iu+8847n8cD5+fmSl5cny5Ytk06dOomIyMaNG70eZ2uG1fp+7bXX5LfffvN6r7y8XObPny+PP/64pW2Fk9XvsW7dOpkzZ45ce+21UlxcLPn5+fLNN98YPpamcePGfqd6cH9+6623SmZmppx11lnSsWNHr89dLpf0799fLrzwQikuLpb09HT54IMPZMiQIfLpp5962rLqI0izs7Nlzpw50rBhQ/n8889l4MCBnu/cuHFjS9/bvZ5ZxcXF8sUXX9R4/+TJkzJnzhy58sorLe8/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R4wYUWMAgq/2dr+flZWl8+fPN12WcLDS5uE+xqsyOmZVVXNzc/X555/3/Pvw4cOakJBQY6BKYWGh5uTk6M6dO33eXLZyjKuaq6Py8nLNycnRJ554osZn/tr8008/1aSkJP3Pf/4T8v6rCnc7ma33qgK1wdGjRzUuLk7XrVvnee/nn39WEdHVq1d73otELg5lvUjGv6rqe++9p+np6X4/79Gjh955550Bt2FmmUjEfyQ5Hf9ugc4bqrLSl9l9LhLKetFwjmd3XlEl/0fqXDyc/bRdNzyc7gOMlif/R6aNjGI1kEBt6u/4sKuNoqFu3cxcA1R11lln6aRJk3x+Fq5+VdX5/B9JsTBgIRqexojAgnlapZvTx1ekY5j4jQ2RjuFwrmcWsRcbnIi9cCGGoUr+hHNi+fwzkpzsG+Ilin311Vdy3nnnSWJiorhcLlmzZo08//zzcu211xquu2HDBjn77LNrvL9+/Xpp1qyZ5ObmyogRI2T79u0Bt/PBBx9Io0aNJCkpSe644w654447JDMz09L36NSpk6xbt87SOoGUl5fLzJkz5eGHH5bU1FRT6yQlJcmjjz4qs2fPlhMnThguf/LkSXn55Zfl2muvlUmTJsnPP/8carFNWbdunSQkJEiXLl1ERCQtLU169eol+/fvD7jewoULZcCAARIfH3xIb926VYYPHy5NmzaVevXqybhx4+To0aOybds2v+vMmDFDxowZI0lJSZ73Bg4cKIsWLQq6HL5s27ZNli1bJo8//rjExcWZWue0006TiRMnyvTp000tX1xcLI8//riMGDFCHnnkETl48GAoRTYlEse42WO2pKREdu7cKd26dfO816hRIznjjDO85gtSVRk9erRMmTJFWrdu7bMs4T7GRUTeffddiY+Pl9tuu830Or1795YrrrhCZs6cGdayhLOdzNZ7VUZtoKpe/636/998843nvUi0UygiEf9VLV++XM4991yfnx07dkzWrl0rIiLdunWTJk2aSI8ePWT58uWWlhGxt17XrVsnN998s4waNUoWL15sy9zVkW4nM6yeu/hSF+LfSj1Fc16prfnfLdzn4k7106Fysg8wWp78/7twt5GZWA3EV5saHR/RGPsizl4DVLVixQr56aefZPz48Za/Q6zm/19++UXuvvtuGTlypOl7A9GspKRE4uPjZeXKlV7vV1ZWSlpamsyf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9tXdu3eHZbtOcqLNN27cqBkZGT6Tsa/yvP7665qWlqYbNmywrYxALAr38Vzb+jhV83V03333aZs2bbSwsNBw/RMnTujgwYO1f//+nhHNoe7fitrWTgxYAKwj/xsj/0e/aBmwUNvqVdWZvnXhwoWalpama9asMSyLy+XSO++8U9u2beu5UQgAiG7B9i1ffPGF/ulPf9L09HRt3Lix9u7d2+cflsPxJNuffvpJ8/PztVmzZpqenq5nn312wLndq29z1KhRev311/tc1sxTcKuX56WXXvI5r7Z7n2bKG6hMRtuvXh6Xy6X333+/tmzZUtPT0/X888/XTz75xNI2rT7pt6pYPj8PNo5FROvXr6+pqaler507d3qWsRrHRp+HEjO+ymMU+2a+YyjHVjBxXF317xhsHNt9/WJn3BnFxpw5czQ7O1uTk5M1NzdX77///ho/SA5nO5uJVaNYCGd5VI2flm5UR3bkz3CqC9d3MTtgobCwUPPz8/XOO+8MQ8mih1N/JNi2bZu2bdtWhw8f7vXI/6rlOXHihM6ZM0fT09P1qaeeMrVd/uhhzKk6WrFihWZkZOhdd93l9cSKquUpKirSgoICTUtLM/VINaCuC9fxXFv7OFXzdeRyuXTcuHHaqlUrfe+99zwnlNXXX79+vfbq1UvPP/98PXLkSNj2b0ZtbSf6bsA68r8x8n/0c3rAQm2tV1Xn+tYZM2Zoamqqzpgxw3MjrnpZtm/frtdee62edtppQT9CFgBgv0j3LdHwJNvTTz+9xpTATou2MgUzVZVbbTo/94c49i3ayhRsHDt9/eJPNMSdavS1c7SVx478GW61/fquvsSo0047Td555x2ni1Fr5OXlyRdffCF///vfpUOHDnLhhRfKVVddJampqSIict9998nrr78uTZs2lZdeekmuvPJKh0uMUF144YWyevVquf322+W0006T4cOHy5AhQ6R+/d/TwoQJE2ThwoXSrVs3WblypXTr1s3hEgN1B32cSFxcnMyYMUPat28v48aNkwYNGsjYsWOldevWIiIya9Yseeutt2TTpk0yatQoeeyxxyQlJcXWMtJOAMKNvEL+r8uo1/AbP368tGrVSu6++26555575IYbbpBOnTqJiMjrr78uH374oSxdulQuvfRS+fLLL6VVq1YOlxgAEC0uvPBC2bBhg6Nl2Lp1q6P79yXayrRw4cKI7yMWzs/9IY59i7Yy2RHHdoqGuBOJvnaOtvLEYtzV9uu7mB2wgPBr0aKFvPnmm7J3716ZPXu2vPLKK1JUVCQiIr/++qu89dZbcsEFF0hcXJzDJUW4nHvuubJixQrZvHmzzJw5U5577jk5cuSIiIgkJyfL2rVrPQkPAOwWFxcnt956q0yYMEHeffddee211+R//ud/RETkvffek+uuu06uu+46adiwocMlBQCEE/kfCJ9LL71Uhg4dKp999pnMmjVLpk+fLiIir732mlx00UUyY8YMOe200xwuJQAAiGacnwNAdKjN13dxqqp27ay0tFQaNmwoJSUlkpGRYdduY0q01ZGqSllZmaSnpwc1UCHavk80irY6CrXNgbos2o7naBRqHdEvRR51BFjHcWOM/B/9gq0j6tZYNNUR13sAUDtEU9+C2MT5OWId1y9wSjTFUG26vuMJCwgoLi7O8QMO9qLNAUQzchQA1E3kfyA8OJYAAEA4cE4BAM6rTbk43ukCAAAAAAAAAAAAAACAuocBCwAAAAAAAAAAAAAAwHYMWAAAAAAAAAAAAAAAALZjwAIAAAAAAAAAAAAAALAdAxYAAAAAAAAAAAAAAIDtGLAAAAAAAAAAAAAAAABsx4AFAAAAAAAAAAAAAABgOwYsAAAAAAAAAAAAAAAA29V3YqelpaVO7DYm1Na6qa3fKxyoG6D24bj2L1rqJlrKEY2oGyB4HD/+RUvdREs5olGodUPd+kfdAAAihT4GwYqW2ImWciD2cP0CpxA7kWHrgIWEhATJysqSnJwcO3cbc7KysiQhIcHpYoQFbW5ObWpzoC4j55njZM6jjcyhXwKsIbeYQ/6PfsG0EXVrDn0rACCc6H8RDpyfI9Zx/QKncH0XfnGqqnbu8OTJk1JeXm7nLmNOQkKCJCUlOV2MsKHNjdW2NgfqMnKeMadzHm1kzOk2AmIRucWY07mFNjIWbBtRt8acjn8AQO1D/4tQOX1+QgwjVFy/wClO58/ayPYBCwAAAAAAAAAAAAAAAPFOFwAAAAAAAAAAAAAAANQ9DFgAAAAAAAAAAAAAAAC2Y8ACAAAAAAAAAAAAAACwHQMWAAAAAAAAAAAAAACA7RiwAAAAAAAAAAAAAAAAbMeABQAAAAAAAAAAAAAAYDsGLAAAAAAAAAAAAAAAANsxYAEAAAAAAAAAAAAAANiOAQsAAAAAAAAAAAAAAMB2DFgAAAAAAAAAAAAAAAC2Y8ACAAAAAAAAAAAAAACwHQMWAAAAAAAAAAAAAACA7RiwAAAAAAAAAAAAAAAAbMeABQAAAAAAAAAAAAAAYLv/Dwa8nfm8da2DAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -555,7 +555,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -563,11 +563,11 @@ "output_type": "stream", "text": [ "The matrix of the gate at the 5th position is\n", - " tensor([[[ 0.7492+0.j, -0.6624+0.j],\n", - " [ 0.6624+0.j, 0.7492+0.j]],\n", + " tensor([[[ 0.0254+0.j, -0.9997+0.j],\n", + " [ 0.9997+0.j, 0.0254+0.j]],\n", "\n", - " [[ 0.8098+0.j, -0.5868+0.j],\n", - " [ 0.5868+0.j, 0.8098+0.j]]], grad_fn=)\n" + " [[ 0.0516+0.j, -0.9987+0.j],\n", + " [ 0.9987+0.j, 0.0516+0.j]]], grad_fn=)\n" ] } ], @@ -591,7 +591,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -603,7 +603,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -620,7 +620,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -662,7 +662,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -670,36 +670,36 @@ "output_type": "stream", "text": [ "the output state for inputting zero state is: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2, 2]\n", " System sequence: [2, 1, 0]\n", - "[0.67-0.62j 0.13-0.12j 0. +0.j 0. +0.j 0.35-0.07j 0.07-0.01j\n", + "[0.61-0.06j 0.78-0.07j 0. +0.j 0. +0.j 0.06+0.01j 0.08+0.01j\n", " 0. +0.j 0. +0.j ]\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", "\n", "the output state for inputting state rho is: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 2, 2]\n", " System sequence: [2, 1, 0]\n", - "[[ 0.13+0.j -0.03-0.03j -0.02+0.06j 0.02-0.01j -0.01+0.05j 0.04+0.1j\n", - " -0.04-0.03j 0.06-0.03j]\n", - " [-0.03+0.03j 0.18-0.j -0.03-0.02j -0.13+0.01j -0.07+0.j 0.01-0.01j\n", - " 0. -0.02j -0.09-0.02j]\n", - " [-0.02-0.06j -0.03+0.02j 0.1 +0.j 0.05+0.01j 0. -0.02j 0.02-0.03j\n", - " 0.04+0.03j -0. -0.03j]\n", - " [ 0.02+0.01j -0.13-0.01j 0.05-0.01j 0.15+0.j 0.03+0.01j -0.05+0.03j\n", - " 0.02-0.02j 0.08+0.03j]\n", - " [-0.01-0.05j -0.07-0.j 0. +0.02j 0.03-0.01j 0.11+0.j 0.04-0.01j\n", - " -0.06+0.04j 0.03-0.j ]\n", - " [ 0.04-0.1j 0.01+0.01j 0.02+0.03j -0.05-0.03j 0.04+0.01j 0.12+0.j\n", - " -0.05+0.04j -0.03-0.07j]\n", - " [-0.04+0.03j 0. +0.02j 0.04-0.03j 0.02+0.02j -0.06-0.04j -0.05-0.04j\n", - " 0.09+0.j -0.01+0.02j]\n", - " [ 0.06+0.03j -0.09+0.02j -0. +0.03j 0.08-0.03j 0.03+0.j -0.03+0.07j\n", - " -0.01-0.02j 0.13+0.j ]]\n", - "---------------------------------------------------\n", + "[[ 0.21+0.j -0.02+0.j 0.08-0.09j -0.01+0.07j 0.06+0.13j 0.02+0.04j\n", + " -0.02-0.07j -0.06-0.j ]\n", + " [-0.02-0.j 0.11+0.j -0.03-0.01j -0.06+0.12j 0.03+0.03j 0.07+0.j\n", + " 0.04+0.03j 0.09-0.03j]\n", + " [ 0.08+0.09j -0.03+0.01j 0.11+0.j -0.03+0.02j -0.03+0.08j -0.02+0.04j\n", + " 0. -0.03j -0.03-0.02j]\n", + " [-0.01-0.07j -0.06-0.12j -0.03-0.02j 0.23+0.j 0.09-0.1j -0.01-0.09j\n", + " -0.02-0.04j -0.09-0.06j]\n", + " [ 0.06-0.13j 0.03-0.03j -0.03-0.08j 0.09+0.1j 0.13+0.j 0.06-0.03j\n", + " -0.03-0.01j -0.01-0.02j]\n", + " [ 0.02-0.04j 0.07-0.j -0.02-0.04j -0.01+0.09j 0.06+0.03j 0.06+0.j\n", + " 0.01+0.01j 0.05-0.02j]\n", + " [-0.02+0.07j 0.04-0.03j 0. +0.03j -0.02+0.04j -0.03+0.01j 0.01-0.01j\n", + " 0.05-0.j 0.03-0.04j]\n", + " [-0.06+0.j 0.09+0.03j -0.03+0.02j -0.09+0.06j -0.01+0.02j 0.05+0.02j\n", + " 0.03+0.04j 0.09-0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -724,7 +724,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -733,9 +733,9 @@ "text": [ "the circuit depth is 2 \n", "\n", - "the gate history of the circuit is [{'gate': 'ry', 'which_system': [0], 'theta': tensor([[0.3819]], grad_fn=)}, {'gate': 'ry', 'which_system': [2], 'theta': tensor([[0.7412]], grad_fn=)}, {'gate': 'rz', 'which_system': [1], 'theta': tensor([[0.9501]])}, {'gate': 'rz', 'which_system': [2], 'theta': tensor([[0.5337]])}] \n", + "the gate history of the circuit is [{'gate': 'ry', 'which_system': [0], 'theta': tensor([[1.8177]], grad_fn=)}, {'gate': 'ry', 'which_system': [2], 'theta': tensor([[0.1988]], grad_fn=)}, {'gate': 'rz', 'which_system': [1], 'theta': tensor([[0.0056]])}, {'gate': 'rz', 'which_system': [2], 'theta': tensor([[0.1836]])}] \n", "\n", - "the qubit history of the circuit is [[[{'gate': 'ry', 'which_system': [0], 'theta': tensor([[0.3819]], grad_fn=)}, 0]], [[{'gate': 'rz', 'which_system': [1], 'theta': tensor([[0.9501]])}, 2]], [[{'gate': 'ry', 'which_system': [2], 'theta': tensor([[0.7412]], grad_fn=)}, 1], [{'gate': 'rz', 'which_system': [2], 'theta': tensor([[0.5337]])}, 3]]]\n" + "the qubit history of the circuit is [[[{'gate': 'ry', 'which_system': [0], 'theta': tensor([[1.8177]], grad_fn=)}, 0]], [[{'gate': 'rz', 'which_system': [1], 'theta': tensor([[0.0056]])}, 2]], [[{'gate': 'ry', 'which_system': [2], 'theta': tensor([[0.1988]], grad_fn=)}, 1], [{'gate': 'rz', 'which_system': [2], 'theta': tensor([[0.1836]])}, 3]]]\n" ] } ], @@ -756,14 +756,14 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "the trainable parameters of entire circuit are tensor([0.3819, 0.7412])\n", + "the trainable parameters of entire circuit are tensor([1.8177, 0.1988])\n", "the updated trainable parameters of entire circuit are tensor([1., 1.])\n" ] } @@ -817,7 +817,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -826,13 +826,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -861,7 +861,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/introduction/measure.ipynb b/tutorials/introduction/measure.ipynb index 9b4a5a8..d37443c 100644 --- a/tutorials/introduction/measure.ipynb +++ b/tutorials/introduction/measure.ipynb @@ -135,7 +135,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "The probability distribution of outcome tensor([0.8449, 0.1551])\n" + "The probability distribution of outcome tensor([0.6159, 0.3841])\n" ] } ], @@ -163,23 +163,23 @@ "output_type": "stream", "text": [ "The collapsed state for each outcome is \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", " Batch size: [2]\n", "\n", " # 0:\n", - "[[ 0.3+0.j -0. -0.24j 0.3+0.j -0. -0.24j]\n", - " [-0. +0.24j 0.2+0.j -0. +0.24j 0.2+0.j ]\n", - " [ 0.3+0.j -0. -0.24j 0.3+0.j -0. -0.24j]\n", - " [-0. +0.24j 0.2+0.j -0. +0.24j 0.2+0.j ]]\n", + "[[ 0.23+0.j -0.08+0.21j 0.23+0.j -0.08+0.21j]\n", + " [-0.08-0.21j 0.27+0.j -0.08-0.21j 0.27+0.j ]\n", + " [ 0.23+0.j -0.08+0.21j 0.23+0.j -0.08+0.21j]\n", + " [-0.08-0.21j 0.27+0.j -0.08-0.21j 0.27+0.j ]]\n", " # 1:\n", - "[[ 0.15+0.j 0.19+0.09j -0.15+0.j -0.19-0.09j]\n", - " [ 0.19-0.09j 0.35+0.j -0.19+0.09j -0.35+0.j ]\n", - " [-0.15+0.j -0.19-0.09j 0.15+0.j 0.19+0.09j]\n", - " [-0.19+0.09j -0.35+0.j 0.19-0.09j 0.35+0.j ]]\n", - "---------------------------------------------------\n", + "[[ 0.26+0.j -0.16+0.02j -0.26+0.j 0.16-0.02j]\n", + " [-0.16-0.02j 0.24+0.j 0.16+0.02j -0.24+0.j ]\n", + " [-0.26+0.j 0.16-0.02j 0.26+0.j -0.16+0.02j]\n", + " [ 0.16+0.02j -0.24+0.j -0.16-0.02j 0.24+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -205,16 +205,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "The probability for obtaining outcome 1 is tensor([0.1551]), with outcome state \n", - "---------------------------------------------------\n", + "The probability for obtaining outcome 1 is tensor([0.3841]), with outcome state \n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", - "[[ 0.15+0.j 0.19+0.09j -0.15+0.j -0.19-0.09j]\n", - " [ 0.19-0.09j 0.35+0.j -0.19+0.09j -0.35+0.j ]\n", - " [-0.15+0.j -0.19-0.09j 0.15+0.j 0.19+0.09j]\n", - " [-0.19+0.09j -0.35+0.j 0.19-0.09j 0.35+0.j ]]\n", - "---------------------------------------------------\n", + "[[ 0.26+0.j -0.16+0.02j -0.26+0.j 0.16-0.02j]\n", + " [-0.16-0.02j 0.24+0.j 0.16+0.02j -0.24+0.j ]\n", + " [-0.26+0.j 0.16-0.02j 0.26+0.j -0.16+0.02j]\n", + " [ 0.16+0.02j -0.24+0.j -0.16-0.02j 0.24+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -246,9 +246,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "The probability distribution of outcome tensor([0.5878, 0.4122])\n", + "The probability distribution of outcome tensor([0.3633, 0.6367])\n", "The collapsed state for each outcome is \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2]\n", " System sequence: [0]\n", @@ -260,7 +260,7 @@ " # 1:\n", "[[ 0.5+0.j -0.5+0.j]\n", " [-0.5+0.j 0.5+0.j]]\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", "\n" ] } @@ -300,8 +300,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "Time for measuring with pvm: 0.0069618225s\n", - "Time for measuring with povm: 0.0017402172s\n" + "Time for measuring with pvm: 0.0090117455s\n", + "Time for measuring with povm: 0.0029997826s\n" ] }, { @@ -309,9 +309,9 @@ "output_type": "stream", "text": [ "Traceback (most recent call last):\n", - " File \"C:\\Users\\Cloud\\AppData\\Local\\Temp\\ipykernel_24616\\2671688636.py\", line 11, in \n", + " File \"C:\\Users\\Cloud\\AppData\\Local\\Temp\\ipykernel_21928\\2671688636.py\", line 11, in \n", " rho.measure(pvm, is_povm=True, keep_state=True)\n", - " File \"c:\\Users\\Cloud\\anaconda3\\envs\\quair_test\\lib\\site-packages\\quairkit\\core\\state\\backend\\__init__.py\", line 633, in measure\n", + " File \"c:\\Users\\Cloud\\anaconda3\\envs\\quair_test\\lib\\site-packages\\quairkit\\core\\state\\backend\\__init__.py\", line 702, in measure\n", " raise ValueError(\n", "ValueError: `is_povm` and `keep_state` cannot be both True, since a general POVM does not distinguish states.\n" ] @@ -411,7 +411,7 @@ "output_type": "stream", "text": [ "The measured states for the first batch is \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2]\n", " System sequence: [0]\n", @@ -423,8 +423,8 @@ " # 1:\n", "[[ 0.5+0.j -0.5+0.j]\n", " [-0.5+0.j 0.5+0.j]]\n", - "---------------------------------------------------\n", - " with prob distribution tensor([0.5878, 0.4122])\n" + "-----------------------------------------------------\n", + " with prob distribution tensor([0.3633, 0.6367])\n" ] } ], @@ -454,20 +454,18 @@ "output_type": "stream", "text": [ "The measured states for the first batch is \n", - "---------------------------------------------------\n", - " Backend: density_matrix\n", + "-----------------------------------------------------\n", + " Backend: state_vector\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [2]\n", "\n", " # 0:\n", - "[[0.5+0.j 0.5+0.j]\n", - " [0.5+0.j 0.5+0.j]]\n", + "[0.68-0.18j 0.68-0.18j]\n", " # 1:\n", - "[[ 0.5+0.j -0.5+0.j]\n", - " [-0.5+0.j 0.5+0.j]]\n", - "---------------------------------------------------\n", - " with prob distribution tensor([0.6556, 0.3444])\n" + "[ 0.63-0.32j -0.63+0.32j]\n", + "-----------------------------------------------------\n", + " with prob distribution tensor([0.8764, 0.1236])\n" ] } ], @@ -517,18 +515,18 @@ "output_type": "stream", "text": [ "3 probability distributions are\n", - " tensor([[0.6556, 0.3444],\n", - " [0.7414, 0.2586],\n", - " [0.8497, 0.1503]])\n", + " tensor([[0.8764, 0.1236],\n", + " [0.3707, 0.6293],\n", + " [0.6343, 0.3657]])\n", "\n", "The outcomes of quantum measurements:\n", - "{'0': tensor([657, 753, 860]), '1': tensor([367, 271, 164])}\n", + "{'0': tensor([913, 349, 641]), '1': tensor([111, 675, 383])}\n", "\n", "The outcomes of quantum measurements with the decimal system of dictionary system:\n", - " {'0': tensor([658, 753, 864]), '1': tensor([366, 271, 160])}\n", + " {'0': tensor([908, 402, 645]), '1': tensor([116, 622, 379])}\n", "\n", "The outcomes of quantum measurements in proportion:\n", - " {'0': tensor([0.6494, 0.7432, 0.8350]), '1': tensor([0.3506, 0.2568, 0.1650])}\n" + " {'0': tensor([0.8809, 0.3799, 0.6299]), '1': tensor([0.1191, 0.6201, 0.3701])}\n" ] } ], @@ -589,13 +587,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -624,7 +622,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/introduction/operator.ipynb b/tutorials/introduction/operator.ipynb index 02463c7..83bb875 100644 --- a/tutorials/introduction/operator.ipynb +++ b/tutorials/introduction/operator.ipynb @@ -297,17 +297,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "The matrix form of x-axis rotation gate with parameter 2.537 is\n", - "tensor([[0.2977+0.0000j, 0.0000-0.9547j],\n", - " [0.0000-0.9547j, 0.2977+0.0000j]])\n", + "The matrix form of x-axis rotation gate with parameter 2.151 is\n", + "tensor([[0.4753+0.0000j, 0.0000-0.8798j],\n", + " [0.0000-0.8798j, 0.4753+0.0000j]])\n", "\n", - "The matrix form of y-axis rotation gate with parameter 2.537 is\n", - "tensor([[ 0.2977+0.j, -0.9547+0.j],\n", - " [ 0.9547+0.j, 0.2977+0.j]])\n", + "The matrix form of y-axis rotation gate with parameter 2.151 is\n", + "tensor([[ 0.4753+0.j, -0.8798+0.j],\n", + " [ 0.8798+0.j, 0.4753+0.j]])\n", "\n", - "The matrix form of z-axis rotation gate with parameter 2.537 is\n", - "tensor([[0.2977-0.9547j, 0.0000+0.0000j],\n", - " [0.0000+0.0000j, 0.2977+0.9547j]])\n" + "The matrix form of z-axis rotation gate with parameter 2.151 is\n", + "tensor([[0.4753-0.8798j, 0.0000+0.0000j],\n", + " [0.0000+0.0000j, 0.4753+0.8798j]])\n" ] } ], @@ -434,12 +434,12 @@ "output_type": "stream", "text": [ "pure output state after applying a unitary:\n", - " tensor([[0.4696+0.0464j],\n", - " [0.5735+0.6696j]])\n", + " tensor([[-0.3432+0.3498j],\n", + " [-0.5092-0.7075j]])\n", "\n", "mixed output state after applying a unitary:\n", - " tensor([[ 0.3775+1.3878e-17j, -0.1887+6.7681e-02j],\n", - " [-0.1887-6.7681e-02j, 0.6225-1.3878e-17j]])\n" + " tensor([[ 0.2989+3.4694e-18j, -0.0232+3.2499e-01j],\n", + " [-0.0232-3.2499e-01j, 0.7011-5.0307e-17j]])\n" ] } ], @@ -471,10 +471,14 @@ "output_type": "stream", "text": [ "state after applying a unitary on the first qubit:\n", - " tensor([[ 0.1232+0.0000j, -0.2102+0.0393j, -0.0415+0.1123j, 0.0775-0.2049j],\n", - " [-0.2102-0.0393j, 0.3710+0.0000j, 0.1065-0.1784j, -0.1975+0.3248j],\n", - " [-0.0415-0.1123j, 0.1065+0.1784j, 0.1163+0.0000j, -0.2128-0.0017j],\n", - " [ 0.0775+0.2049j, -0.1975-0.3248j, -0.2128+0.0017j, 0.3894+0.0000j]])\n" + " tensor([[ 0.3191-6.9389e-18j, 0.0254-1.6791e-02j, 0.0108+1.0972e-01j,\n", + " -0.1529-6.6787e-02j],\n", + " [ 0.0254+1.6791e-02j, 0.0523+3.4694e-18j, -0.1241-5.5073e-02j,\n", + " -0.0756-5.8328e-02j],\n", + " [ 0.0108-1.0972e-01j, -0.1241+5.5073e-02j, 0.4095-1.3878e-17j,\n", + " 0.1921+7.1530e-02j],\n", + " [-0.1529+6.6787e-02j, -0.0756+5.8328e-02j, 0.1921-7.1530e-02j,\n", + " 0.2191-6.9389e-18j]])\n" ] } ], @@ -504,28 +508,28 @@ "text": [ "batched states after applying a unitary:\n", " \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [5]\n", "\n", " # 0:\n", - "[[0.86-0.j 0.26-0.16j]\n", - " [0.26+0.16j 0.14-0.j ]]\n", + "[[0.27+0.j 0.1 +0.23j]\n", + " [0.1 -0.23j 0.73-0.j ]]\n", " # 1:\n", - "[[ 0.78+0.j -0.09-0.23j]\n", - " [-0.09+0.23j 0.22+0.j ]]\n", + "[[ 0.68-0.j -0.14+0.19j]\n", + " [-0.14-0.19j 0.32+0.j ]]\n", " # 2:\n", - "[[0.52+0.j 0.4 +0.03j]\n", - " [0.4 -0.03j 0.48+0.j ]]\n", + "[[0.8 +0.j 0.08+0.29j]\n", + " [0.08-0.29j 0.2 -0.j ]]\n", " # 3:\n", - "[[ 0.45+0.j -0.16+0.25j]\n", - " [-0.16-0.25j 0.55+0.j ]]\n", + "[[ 0.53+0.j -0.19+0.04j]\n", + " [-0.19-0.04j 0.47+0.j ]]\n", " # 4:\n", - "[[0.38-0.j 0.34-0.01j]\n", - " [0.34+0.01j 0.62-0.j ]]\n", - "---------------------------------------------------\n", + "[[ 0.31+0.j -0.16-0.07j]\n", + " [-0.16+0.07j 0.69+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -565,28 +569,23 @@ "text": [ "state after applying batched unitaries:\n", " \n", - "---------------------------------------------------\n", - " Backend: density_matrix\n", + "-----------------------------------------------------\n", + " Backend: state_vector\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [5]\n", "\n", " # 0:\n", - "[[0.11-0.j 0.19+0.17j]\n", - " [0.19-0.17j 0.89+0.j ]]\n", + "[-0.19-0.29j -0.82+0.45j]\n", " # 1:\n", - "[[0.6 +0.j 0.42+0.18j]\n", - " [0.42-0.18j 0.4 +0.j ]]\n", + "[0.31+0.83j 0.44+0.14j]\n", " # 2:\n", - "[[ 0.67+0.j -0.17-0.4j]\n", - " [-0.17+0.4j 0.33+0.j ]]\n", + "[0.35-0.63j 0.62-0.29j]\n", " # 3:\n", - "[[0.11+0.j 0.07-0.25j]\n", - " [0.07+0.25j 0.89+0.j ]]\n", + "[-0.9 -0.3j -0.29+0.1j]\n", " # 4:\n", - "[[0.78-0.j 0.21+0.31j]\n", - " [0.21-0.31j 0.22+0.j ]]\n", - "---------------------------------------------------\n", + "[ 0.73+0.25j -0.1 -0.63j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -629,7 +628,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -668,12 +667,15 @@ "text": [ "output state after applying a quantum circuit:\n", " \n", - "---------------------------------------------------\n", - " Backend: state_vector\n", + "-----------------------------------------------------\n", + " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", - "[-0.2 +0.57j 0.55+0.24j -0.05-0.48j -0.22-0.06j]\n", - "---------------------------------------------------\n", + "[[ 0.12+0.j 0.06-0.08j -0.18-0.04j 0.07+0.07j]\n", + " [ 0.06+0.08j 0.12+0.j -0.05-0.24j -0.03+0.07j]\n", + " [-0.18+0.04j -0.05+0.24j 0.65+0.j -0.13-0.09j]\n", + " [ 0.07-0.07j -0.03-0.07j -0.13+0.09j 0.11+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -703,23 +705,38 @@ "text": [ "output batched states after applying a quantum circuit:\n", " \n", - "---------------------------------------------------\n", - " Backend: state_vector\n", + "-----------------------------------------------------\n", + " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", " Batch size: [5]\n", "\n", " # 0:\n", - "[-0.21+0.18j -0.28-0.42j 0.3 +0.18j -0.71+0.2j ]\n", + "[[ 0.14+0.j -0.14+0.07j 0.1 -0.07j 0.07-0.03j]\n", + " [-0.14-0.07j 0.41+0.j -0.11+0.13j -0.16-0.16j]\n", + " [ 0.1 +0.07j -0.11-0.13j 0.26+0.j 0. -0.01j]\n", + " [ 0.07+0.03j -0.16+0.16j 0. +0.01j 0.19+0.j ]]\n", " # 1:\n", - "[ 0.24-0.41j 0.1 +0.62j 0.26-0.33j -0.06-0.44j]\n", + "[[ 0.27+0.j 0. -0.28j 0.11+0.09j 0.05-0.08j]\n", + " [ 0. +0.28j 0.52+0.j -0.17+0.05j 0.07+0.07j]\n", + " [ 0.11-0.09j -0.17-0.05j 0.12+0.j -0.02-0.07j]\n", + " [ 0.05+0.08j 0.07-0.07j -0.02+0.07j 0.09+0.j ]]\n", " # 2:\n", - "[-0.57+0.04j 0.32+0.26j -0.25-0.1j 0.54+0.37j]\n", + "[[ 0.34+0.j 0.02-0.01j 0.24+0.15j 0.12-0.14j]\n", + " [ 0.02+0.01j 0.14+0.j -0.01+0.06j -0.04+0.03j]\n", + " [ 0.24-0.15j -0.01-0.06j 0.26+0.j 0.08-0.12j]\n", + " [ 0.12+0.14j -0.04-0.03j 0.08+0.12j 0.27+0.j ]]\n", " # 3:\n", - "[-0.15-0.3j -0.34-0.08j -0. -0.43j -0.59-0.48j]\n", + "[[ 0.23+0.j 0.07+0.16j 0.03+0.03j -0.11-0.1j ]\n", + " [ 0.07-0.16j 0.32+0.j 0.08-0.08j -0.06+0.18j]\n", + " [ 0.03-0.03j 0.08+0.08j 0.08+0.j -0.03-0.01j]\n", + " [-0.11+0.1j -0.06-0.18j -0.03+0.01j 0.37+0.j ]]\n", " # 4:\n", - "[-0. +0.56j 0.61-0.1j 0.01-0.53j 0.02-0.18j]\n", - "---------------------------------------------------\n", + "[[ 0.14+0.j -0.07+0.16j 0.09+0.05j -0.06-0.11j]\n", + " [-0.07-0.16j 0.47+0.j 0.06-0.33j -0.12+0.15j]\n", + " [ 0.09-0.05j 0.06+0.33j 0.25+0.j -0.11-0.06j]\n", + " [-0.06+0.11j -0.12-0.15j -0.11+0.06j 0.13+0.j ]]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -835,23 +852,23 @@ "output_type": "stream", "text": [ "Kraus representation of a quantum channel:\n", - " tensor([[[-0.5809-0.0638j, 0.2919-0.2353j],\n", - " [-0.0027-0.5762j, -0.4139+0.0954j]],\n", + " tensor([[[ 0.6951+0.3158j, -0.0702+0.0241j],\n", + " [ 0.0831+0.1243j, 0.9700-0.0503j]],\n", "\n", - " [[ 0.3836-0.3976j, 0.5083-0.0660j],\n", - " [-0.1131-0.0923j, -0.3360+0.5509j]]])\n", + " [[ 0.0687+0.2816j, -0.1932+0.0771j],\n", + " [-0.5543-0.0587j, 0.0791-0.0387j]]])\n", "\n", "Choi representation of the same quantum channel:\n", - " tensor([[ 0.6467+0.0000j, 0.0316-0.2541j, 0.0667-0.3321j, -0.1136+0.0041j],\n", - " [ 0.0316+0.2541j, 0.3533+0.0000j, 0.0834-0.2232j, -0.0667+0.3321j],\n", - " [ 0.0667+0.3321j, 0.0834+0.2232j, 0.4033+0.0000j, -0.3504-0.1883j],\n", - " [-0.1136-0.0041j, -0.0667-0.3321j, -0.3504+0.1883j, 0.5967+0.0000j]])\n", + " tensor([[ 0.6669+0.0000j, 0.0424-0.2122j, -0.0328-0.0987j, 0.6529+0.3662j],\n", + " [ 0.0424+0.2122j, 0.3331+0.0000j, 0.0998+0.0433j, 0.0328+0.0987j],\n", + " [-0.0328+0.0987j, 0.0998-0.0433j, 0.0488+0.0000j, -0.0876+0.0185j],\n", + " [ 0.6529-0.3662j, 0.0328-0.0987j, -0.0876-0.0185j, 0.9512+0.0000j]])\n", "\n", "Stinespring representation of the same quantum channel:\n", - " tensor([[-0.5809-0.0638j, 0.2919-0.2353j],\n", - " [ 0.3836-0.3976j, 0.5083-0.0660j],\n", - " [-0.0027-0.5762j, -0.4139+0.0954j],\n", - " [-0.1131-0.0923j, -0.3360+0.5509j]])\n", + " tensor([[ 0.6951+0.3158j, -0.0702+0.0241j],\n", + " [ 0.0687+0.2816j, -0.1932+0.0771j],\n", + " [ 0.0831+0.1243j, 0.9700-0.0503j],\n", + " [-0.5543-0.0587j, 0.0791-0.0387j]])\n", "\n" ] } @@ -1221,12 +1238,12 @@ "output_type": "stream", "text": [ "state after applying a quantum channel in Kraus representation:\n", - " tensor([[0.0340+0.0000e+00j, 0.1522+9.8172e-02j],\n", - " [0.1522-9.8172e-02j, 0.9660-1.3878e-17j]])\n", + " tensor([[0.7352+6.9389e-18j, 0.0020-2.3601e-01j],\n", + " [0.0020+2.3601e-01j, 0.2648-3.4694e-18j]])\n", "\n", "state after applying a quantum channel in Choi representation:\n", - " tensor([[0.0340+0.0000j, 0.1522+0.0982j],\n", - " [0.1522-0.0982j, 0.9660+0.0000j]])\n" + " tensor([[0.7352+0.0000j, 0.0020-0.2360j],\n", + " [0.0020+0.2360j, 0.2648+0.0000j]])\n" ] } ], @@ -1259,14 +1276,14 @@ "output_type": "stream", "text": [ "state after applying a quantum channel on the first qubit:\n", - " tensor([[ 0.4647+0.0000e+00j, 0.1369+3.2492e-02j, -0.1272-1.2458e-01j,\n", - " 0.1082+8.6246e-02j],\n", - " [ 0.1369-3.2492e-02j, 0.1639-1.0408e-17j, -0.0345-2.4886e-02j,\n", - " 0.0253+1.0877e-01j],\n", - " [-0.1272+1.2458e-01j, -0.0345+2.4886e-02j, 0.1847+1.3878e-17j,\n", - " -0.0517+5.0142e-02j],\n", - " [ 0.1082-8.6246e-02j, 0.0253-1.0877e-01j, -0.0517-5.0142e-02j,\n", - " 0.1867-8.6736e-18j]])\n" + " tensor([[ 0.3431+1.3878e-17j, 0.0128-3.8003e-02j, 0.1459+9.0796e-02j,\n", + " -0.1977+9.7453e-02j],\n", + " [ 0.0128+3.8003e-02j, 0.1728-6.9389e-18j, 0.0826-7.0578e-02j,\n", + " -0.0519-2.5673e-02j],\n", + " [ 0.1459-9.0796e-02j, 0.0826+7.0578e-02j, 0.2661+0.0000e+00j,\n", + " -0.1339+2.5577e-02j],\n", + " [-0.1977-9.7453e-02j, -0.0519+2.5673e-02j, -0.1339-2.5577e-02j,\n", + " 0.2180-3.4694e-18j]])\n" ] } ], @@ -1296,28 +1313,23 @@ "text": [ "batched states after applying a quantum channel:\n", " \n", - "---------------------------------------------------\n", - " Backend: density_matrix\n", + "-----------------------------------------------------\n", + " Backend: state_vector\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [5]\n", "\n", " # 0:\n", - "[[0.11-0.j 0.19+0.17j]\n", - " [0.19-0.17j 0.89+0.j ]]\n", + "[-0.19-0.29j -0.82+0.45j]\n", " # 1:\n", - "[[0.6 +0.j 0.42+0.18j]\n", - " [0.42-0.18j 0.4 +0.j ]]\n", + "[0.31+0.83j 0.44+0.14j]\n", " # 2:\n", - "[[ 0.67+0.j -0.17-0.4j]\n", - " [-0.17+0.4j 0.33+0.j ]]\n", + "[0.35-0.63j 0.62-0.29j]\n", " # 3:\n", - "[[0.11+0.j 0.07-0.25j]\n", - " [0.07+0.25j 0.89+0.j ]]\n", + "[-0.9 -0.3j -0.29+0.1j]\n", " # 4:\n", - "[[0.78-0.j 0.21+0.31j]\n", - " [0.21-0.31j 0.22+0.j ]]\n", - "---------------------------------------------------\n", + "[ 0.73+0.25j -0.1 -0.63j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -1409,13 +1421,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -1444,7 +1456,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/introduction/qinfo.ipynb b/tutorials/introduction/qinfo.ipynb index 792b3c8..85161b5 100644 --- a/tutorials/introduction/qinfo.ipynb +++ b/tutorials/introduction/qinfo.ipynb @@ -47,12 +47,12 @@ "output_type": "stream", "text": [ "Matrix A is:\n", - "tensor([[-0.1954+0.2146j, 0.1822+0.9394j],\n", - " [-0.1701-0.9417j, 0.2599+0.1293j]])\n", + "tensor([[-0.6831+0.1926j, 0.1419+0.6900j],\n", + " [ 0.5660+0.4195j, -0.4625+0.5383j]])\n", "\n", "Matrix B is:\n", - "tensor([[ 0.1297-0.5157j, -0.4703-0.7043j],\n", - " [ 0.4578+0.7125j, -0.5246-0.0871j]])\n" + "tensor([[ 0.0309-0.3380j, 0.6674-0.6628j],\n", + " [ 0.9406+0.0033j, -0.2593-0.2190j]])\n" ] } ], @@ -86,24 +86,24 @@ "name": "stdout", "output_type": "stream", "text": [ - "The trace of matrix A is (0.06443467586598006+0.343978055135579j)\n", + "The trace of matrix A is (-1.1456075082500372+0.7309499027665167j)\n", "The direct sum of matrix A and B is: \n", - "tensor([[-0.1954+0.2146j, 0.1822+0.9394j, 0.0000+0.0000j, 0.0000+0.0000j],\n", - " [-0.1701-0.9417j, 0.2599+0.1293j, 0.0000+0.0000j, 0.0000+0.0000j],\n", - " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.1297-0.5157j, -0.4703-0.7043j],\n", - " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.4578+0.7125j, -0.5246-0.0871j]])\n", + "tensor([[-0.6831+0.1926j, 0.1419+0.6900j, 0.0000+0.0000j, 0.0000+0.0000j],\n", + " [ 0.5660+0.4195j, -0.4625+0.5383j, 0.0000+0.0000j, 0.0000+0.0000j],\n", + " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.0309-0.3380j, 0.6674-0.6628j],\n", + " [ 0.0000+0.0000j, 0.0000+0.0000j, 0.9406+0.0033j, -0.2593-0.2190j]])\n", "\n", "The tensor product of matrix A and B is: \n", - "tensor([[ 0.0853+0.1286j, 0.2431+0.0367j, 0.5081+0.0279j, 0.5760-0.5702j],\n", - " [-0.2424-0.0410j, 0.1212-0.0956j, -0.5859+0.5599j, -0.0138-0.5087j],\n", - " [-0.5077-0.0344j, -0.5832+0.5627j, 0.1004-0.1172j, -0.0311-0.2439j],\n", - " [ 0.5930-0.5524j, 0.0073+0.5088j, 0.0268+0.2444j, -0.1251-0.0905j]])\n", + "tensor([[ 0.0440+0.2368j, -0.3282+0.5813j, 0.2376-0.0267j, 0.5521+0.3665j],\n", + " [-0.6432+0.1789j, 0.2193+0.0996j, 0.1312+0.6495j, 0.1143-0.2100j],\n", + " [ 0.1593-0.1784j, 0.6558-0.0952j, 0.1677+0.1730j, 0.0481+0.6659j],\n", + " [ 0.5310+0.3964j, -0.0549-0.2327j, -0.4369+0.5048j, 0.2378-0.0383j]])\n", "\n", "The conjugate transpose of matrix A is: \n", - "tensor([[-0.1954-0.2146j, -0.1701+0.9417j],\n", - " [ 0.1822-0.9394j, 0.2599-0.1293j]])\n", + "tensor([[-0.6831-0.1926j, 0.5660-0.4195j],\n", + " [ 0.1419-0.6900j, -0.4625-0.5383j]])\n", "\n", - "The decomposition of single-qubit unitary operator A to Z-Y-Z rotation angles is (tensor(-4.0590), tensor(2.5525), tensor(2.2114))\n" + "The decomposition of single-qubit unitary operator A to Z-Y-Z rotation angles is (tensor(-2.2289), tensor(1.5634), tensor(1.6428))\n" ] } ], @@ -145,16 +145,16 @@ "output_type": "stream", "text": [ "The first quantum state is:\n", - " tensor([[ 0.7755+0.0000j, 0.0727-0.0237j, -0.1560-0.2811j, -0.2145-0.1373j],\n", - " [ 0.0727+0.0237j, 0.0075+0.0000j, -0.0060-0.0311j, -0.0159-0.0194j],\n", - " [-0.1560+0.2811j, -0.0060+0.0311j, 0.1333+0.0000j, 0.0929-0.0501j],\n", - " [-0.2145+0.1373j, -0.0159+0.0194j, 0.0929+0.0501j, 0.0836+0.0000j]])\n", + " tensor([[ 0.2031+0.0000j, 0.1826+0.0889j, -0.1991+0.0240j, 0.0808-0.2717j],\n", + " [ 0.1826-0.0889j, 0.2032+0.0000j, -0.1685+0.1088j, -0.0463-0.2798j],\n", + " [-0.1991-0.0240j, -0.1685-0.1088j, 0.1980+0.0000j, -0.1114+0.2568j],\n", + " [ 0.0808+0.2717j, -0.0463+0.2798j, -0.1114-0.2568j, 0.3958+0.0000j]])\n", "\n", "The second quantum state is:\n", - " tensor([[0.3182-0.1243j],\n", - " [0.0199-0.5031j],\n", - " [0.1631-0.3059j],\n", - " [0.3035-0.6461j]])\n" + " tensor([[ 0.6765+0.3616j],\n", + " [-0.4727-0.1993j],\n", + " [ 0.2708-0.0502j],\n", + " [-0.1490-0.2245j]])\n" ] } ], @@ -175,18 +175,18 @@ "output_type": "stream", "text": [ "The von Neumann entropy between state 1 is:\n", - "1.3013920171748103e-15\n", + "-3.844111804577901e-15\n", "torch.float64\n", "The trace distance between state 1 and state 2 is:\n", - "0.9986828156358498\n", + "0.989130913609007\n", "The state fidelity between state 1 and state 2 is:\n", - "0.05130919865131176\n", + "0.1470375336229326\n", "The purity of state 1 is:\n", - "0.9999999999999994\n", + "1.0000000000000009\n", "The relative entropy of state 1 and state 2 is:\n", - "55.26619734246961\n", + "53.29869042772144\n", "The Schatten 2-norm of state 1 is:\n", - "0.9999999999999998\n" + "1.0000000000000004\n" ] } ], @@ -305,13 +305,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -340,7 +340,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/introduction/state.ipynb b/tutorials/introduction/state.ipynb index eb42ac7..d2e6ea1 100644 --- a/tutorials/introduction/state.ipynb +++ b/tutorials/introduction/state.ipynb @@ -47,23 +47,23 @@ "output_type": "stream", "text": [ "zero states with 2 qubits: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", "[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", "\n", "Bell states: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", "[0.71+0.j 0. +0.j 0. +0.j 0.71+0.j]\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", "\n", "isotropic state: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: density_matrix\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", @@ -71,7 +71,7 @@ " [0. +0.j 0.22+0.j 0. +0.j 0. +0.j]\n", " [0. +0.j 0. +0.j 0.22+0.j 0. +0.j]\n", " [0.05+0.j 0. +0.j 0. +0.j 0.27+0.j]]\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", "\n" ] } @@ -129,12 +129,12 @@ "output_type": "stream", "text": [ "A state vector with 2 qubits following Haar random\n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2]\n", " System sequence: [0]\n", - "[0.23-0.11j 0.28-0.93j]\n", - "---------------------------------------------------\n", + "[-0.72-0.19j 0.34-0.58j]\n", + "-----------------------------------------------------\n", "\n", "type of the state: density_matrix\n" ] @@ -170,19 +170,19 @@ "output_type": "stream", "text": [ "3 random single-qubit pure states: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [3]\n", "\n", " # 0:\n", - "[-0.46-0.j -0.85-0.27j]\n", + "[-0.23-0.9j 0.28+0.25j]\n", " # 1:\n", - "[ 0.39-0.11j -0.87-0.26j]\n", + "[ 0.04-0.27j -0.95+0.12j]\n", " # 2:\n", - "[ 0.82-0.32j -0.42+0.24j]\n", - "---------------------------------------------------\n", + "[ 0.56-0.62j -0.14-0.54j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -209,31 +209,31 @@ "output_type": "stream", "text": [ "Its density matrix is :\n", - " tensor([[[ 0.2082+0.0000j, 0.3876-0.1210j],\n", - " [ 0.3876+0.1210j, 0.7918+0.0000j]],\n", + " tensor([[[ 0.8570+0.0000j, -0.2895-0.1968j],\n", + " [-0.2895+0.1968j, 0.1430+0.0000j]],\n", "\n", - " [[ 0.1690+0.0000j, -0.3152+0.2027j],\n", - " [-0.3152-0.2027j, 0.8310+0.0000j]],\n", + " [[ 0.0764+0.0000j, -0.0707+0.2560j],\n", + " [-0.0707-0.2560j, 0.9236+0.0000j]],\n", "\n", - " [[ 0.7664+0.0000j, -0.4182-0.0642j],\n", - " [-0.4182+0.0642j, 0.2336+0.0000j]]])\n", + " [[ 0.6902+0.0000j, 0.2560+0.3851j],\n", + " [ 0.2560-0.3851j, 0.3098+0.0000j]]])\n", "\n", "Its ket is :\n", - " tensor([[[-0.4563-0.0035j],\n", - " [-0.8473-0.2717j]],\n", + " tensor([[[-0.2323-0.8961j],\n", + " [ 0.2843+0.2494j]],\n", "\n", - " [[ 0.3947-0.1150j],\n", - " [-0.8741-0.2588j]],\n", + " [[ 0.0396-0.2735j],\n", + " [-0.9535+0.1203j]],\n", "\n", - " [[ 0.8157-0.3179j],\n", - " [-0.4185+0.2418j]]])\n", + " [[ 0.5555-0.6178j],\n", + " [-0.1386-0.5391j]]])\n", "\n", "Its bra is :\n", - " tensor([[[-0.4563+0.0035j, -0.8473+0.2717j]],\n", + " tensor([[[-0.2323+0.8961j, 0.2843-0.2494j]],\n", "\n", - " [[ 0.3947+0.1150j, -0.8741+0.2588j]],\n", + " [[ 0.0396+0.2735j, -0.9535-0.1203j]],\n", "\n", - " [[ 0.8157+0.3179j, -0.4185-0.2418j]]])\n" + " [[ 0.5555+0.6178j, -0.1386+0.5391j]]])\n" ] } ], @@ -261,9 +261,9 @@ "text": [ "\n", "The state is :\n", - " [[-0.45629326-0.00350509j -0.8473218 -0.2717167j ]\n", - " [ 0.39468753-0.1149976j -0.8740804 -0.25880632j]\n", - " [ 0.8156662 -0.31794474j -0.41849422+0.24178998j]]\n" + " [[-0.23232111-0.8960976j 0.2843098 +0.24940717j]\n", + " [ 0.0396465 -0.27353507j -0.95348746+0.12028483j]\n", + " [ 0.5554969 -0.61775345j -0.13859613-0.53906864j]]\n" ] } ], @@ -339,17 +339,17 @@ "output_type": "stream", "text": [ "the second and third state in the batch: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2]\n", " System sequence: [0]\n", " Batch size: [2]\n", "\n", " # 0:\n", - "[ 0.39-0.11j -0.87-0.26j]\n", + "[ 0.04-0.27j -0.95+0.12j]\n", " # 1:\n", - "[ 0.82-0.32j -0.42+0.24j]\n", - "---------------------------------------------------\n", + "[ 0.56-0.62j -0.14-0.54j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -358,42 +358,6 @@ "print(f\"the second and third state in the batch: {state[1:]}\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or if the length of the batch dimension is larger than 1, one can index elements in a batch dimension. See [torch.index_select](https://pytorch.org/docs/stable/generated/torch.index_select.html) for more understanding." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The index of batch dimension is 0: \n", - "---------------------------------------------------\n", - " Backend: state_vector\n", - " System dimension: [2]\n", - " System sequence: [0]\n", - " Batch size: [2]\n", - "\n", - " # 0:\n", - "[ 0.39-0.11j -0.87-0.26j]\n", - " # 1:\n", - "[ 0.82-0.32j -0.42+0.24j]\n", - "---------------------------------------------------\n", - "\n" - ] - } - ], - "source": [ - "print(f\"The index of batch dimension is 0: {state.index_select(0, torch.tensor([1, 2]))}\")" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -405,7 +369,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -413,9 +377,9 @@ "output_type": "stream", "text": [ "matrix multiplication:\n", - "tensor([[0.6244+0.0000j, 0.1924+0.4444j],\n", + "tensor([[0.0980+0.0000j, 0.2842+0.0874j],\n", " [0.0000+0.0000j, 0.0000+0.0000j]])\n", - "The overlap of state_1 and state_2 is : tensor(0.6244+0.j)\n" + "The overlap of state_1 and state_2 is : tensor(0.0980+0.j)\n" ] } ], @@ -436,7 +400,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -444,8 +408,8 @@ "output_type": "stream", "text": [ "tensor product:\n", - "tensor([[0.6244+0.0000j, 0.1924+0.4444j, 0.0000+0.0000j, 0.0000+0.0000j],\n", - " [0.1924-0.4444j, 0.3756+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j],\n", + "tensor([[0.0980+0.0000j, 0.2842+0.0874j, 0.0000+0.0000j, 0.0000+0.0000j],\n", + " [0.2842-0.0874j, 0.9020+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j],\n", " [0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j],\n", " [0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j, 0.0000+0.0000j]])\n" ] @@ -465,7 +429,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -473,20 +437,20 @@ "output_type": "stream", "text": [ "1 random 2-qubit pure states: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", - "[-0.56+0.12j -0.28+0.56j -0.3 +0.26j -0.24+0.24j]\n", - "---------------------------------------------------\n", + "[-0.2 +0.37j 0.22+0.77j -0.26+0.22j -0.16+0.19j]\n", + "-----------------------------------------------------\n", "\n", "state after permutation: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [1, 0]\n", - "[-0.56+0.12j -0.3 +0.26j -0.28+0.56j -0.24+0.24j]\n", - "---------------------------------------------------\n", + "[-0.2 +0.37j -0.26+0.22j 0.22+0.77j -0.16+0.19j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -508,7 +472,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -544,7 +508,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -552,12 +516,12 @@ "output_type": "stream", "text": [ "state after evolving with unitary: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [1, 0]\n", - "[0.24+0.56j 0.22+0.15j 0.35+0.48j 0.21+0.4j ]\n", - "---------------------------------------------------\n", + "[-0.4 +0.57j -0.17-0.04j 0.53-0.24j 0.38+0.02j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -577,7 +541,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -585,12 +549,12 @@ "output_type": "stream", "text": [ "state after transformation: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", - "[-0.56+0.12j -0.28+0.56j -0.3 +0.26j -0.24+0.24j]\n", - "---------------------------------------------------\n", + "[-0.2 +0.37j 0.22+0.77j -0.26+0.22j -0.16+0.19j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -603,7 +567,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -611,12 +575,12 @@ "output_type": "stream", "text": [ "state after transformation: \n", - "---------------------------------------------------\n", + "-----------------------------------------------------\n", " Backend: state_vector\n", " System dimension: [2, 2]\n", " System sequence: [0, 1]\n", - "[-0.56+0.12j -0.28+0.56j -0.3 +0.26j -0.24+0.24j]\n", - "---------------------------------------------------\n", + "[-0.2 +0.37j 0.22+0.77j -0.26+0.22j -0.16+0.19j]\n", + "-----------------------------------------------------\n", "\n" ] } @@ -636,14 +600,14 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "the expectation value under the given observable: tensor(0.9029)\n" + "the expectation value under the given observable: tensor(1.2991)\n" ] } ], @@ -664,14 +628,14 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Theoretical value is : tensor([0.3325, 0.3932, 0.1569, 0.1173])\n" + "Theoretical value is : tensor([0.1780, 0.6468, 0.1167, 0.0586])\n" ] } ], @@ -705,7 +669,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -714,13 +678,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -749,7 +713,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/tutorials/introduction/training.ipynb b/tutorials/introduction/training.ipynb index 8de6614..f962ea4 100644 --- a/tutorials/introduction/training.ipynb +++ b/tutorials/introduction/training.ipynb @@ -361,17 +361,17 @@ "output_type": "stream", "text": [ "Training:\n", - "iter: 0, loss: -1.03517652, lr: 5.00E-02, avg_time: 0.0497s\n", - "iter: 20, loss: -2.40390968, lr: 5.00E-02, avg_time: 0.0109s\n", - "iter: 40, loss: -2.79073524, lr: 5.00E-02, avg_time: 0.0117s\n", - "iter: 60, loss: -3.16234064, lr: 5.00E-02, avg_time: 0.0105s\n", - "iter: 80, loss: -3.45437813, lr: 5.00E-02, avg_time: 0.0104s\n", - "iter: 100, loss: -3.48992562, lr: 5.00E-02, avg_time: 0.0119s\n", - "iter: 120, loss: -3.49346781, lr: 5.00E-02, avg_time: 0.0108s\n", - "iter: 140, loss: -3.49388337, lr: 5.00E-02, avg_time: 0.0106s\n", - "iter: 160, loss: -3.49395490, lr: 5.00E-02, avg_time: 0.0099s\n", - "iter: 180, loss: -3.49395800, lr: 5.00E-02, avg_time: 0.0119s\n", - "iter: 199, loss: -3.49395871, lr: 5.00E-02, avg_time: 0.0141s\n", + "iter: 0, loss: -1.03517652, lr: 5.00E-02, avg_time: 0.0361s\n", + "iter: 20, loss: -2.40390968, lr: 5.00E-02, avg_time: 0.0113s\n", + "iter: 40, loss: -2.79073524, lr: 5.00E-02, avg_time: 0.0122s\n", + "iter: 60, loss: -3.16234064, lr: 5.00E-02, avg_time: 0.0111s\n", + "iter: 80, loss: -3.45437813, lr: 5.00E-02, avg_time: 0.0147s\n", + "iter: 100, loss: -3.48992562, lr: 5.00E-02, avg_time: 0.0105s\n", + "iter: 120, loss: -3.49346781, lr: 5.00E-02, avg_time: 0.0103s\n", + "iter: 140, loss: -3.49388337, lr: 5.00E-02, avg_time: 0.0119s\n", + "iter: 160, loss: -3.49395490, lr: 5.00E-02, avg_time: 0.0103s\n", + "iter: 180, loss: -3.49395800, lr: 5.00E-02, avg_time: 0.0130s\n", + "iter: 199, loss: -3.49395871, lr: 5.00E-02, avg_time: 0.0122s\n", "\n", "----------------------------------------------------------------------------------------------------\n", "\n", @@ -380,7 +380,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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2Hp6E9xf5eXlkpeX57D91KlTMn/+fBERaWhocIhj06ZNAkCWLFni9ZgbN26UmTNn+nzy3Fm8eLHs2LHD5f758+fL3r177bZ1LYKoqCi77VFRUS4XiKdjfOnTn3i627NnjxQVFcmJEyc8tu3JYDBIfX29y/1JSUluj//d734nK1ascNsmPT3d5T5f1rvVapXx48d7fVxPnubW23zNPRGRWbNmSWNjo9TX18uOHTu8LpA9+ZPPDQ0NYrVaZefOnfLRRx/JmDFjZPv27TJnzhypqqqStLQ0u/a+rG9vrhnexuNLTK7i8ZQ/njC/lAOgqJ3iYmsymXwOpovZbHY60WvXronRaJRJkybZba+vr5dz587JW2+9JSIiMTExdnFcvnxZXn/9dfnss8+8juW7776TAwcOyP79+70+VokNGzZIYWGhy/0hISEO27qeIfV8rBsbG10+e/J0jC99+hNPl927d8sLL7wgBw8elMzMTLdtnTGbzQ4fJejOaDS6jGH16tVSX18vmzZtcrrfZDJJcnKyXLlyxSHpX375ZQEg69atczn2J598InPnzpX29nbbtiFDhshDDz3k8ATKG1354W5uSo73hq+511NMTIz867/+q0RHR8uoUaNk9OjRXsfvTz6LiOj1ehERycnJkQkTJoiISG5urqxbt06OHDkiL7zwgl17b9e3t9cMb+PxNiZ38XjKH0+YXyoI5GvWrl4zr6iosN2I0d2GDRswfPhwtLe3AwBefPFFPPfcc7b927Ztw5AhQxAbG2v7EREYDAYsW7bMbSz5+flITU11+R5AMN+z3bRpk+33xsZGhISEeHzP1t0xvvTpTzxFRUWIjo7Gn/70J7d9u3uMX331VcyaNcthu5L3XSorKxEaGoqbN2863e+qD7PZjIiICI83sADAxo0bER4ejpCQEIgIpk+f7nI8pYLxnq2vuedMe3s7wsLC8MEHH3gc19m59yefu6SlpWH16tV220aPHm33Hmh33qxvT9eM3ojHm5jcxeMqfzxhfqmnTxTb5uZmREdHIzc3Fzdu3EBjYyN27doFvV6P7du329odO3YMSUlJtsV169YtGI1Gux8RwZ49e9zepNHe3o7ExES8+eabDvs6OjrQ0tKCI0eOQETQ0tKClpYWuwWdn5+PlJQUPx8N5woKCpCWloYLFy6gubkZS5cuVXQ3srtjPO13Nx9v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", "text/plain": [ "
" ] @@ -400,7 +400,7 @@ }, { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -480,13 +480,13 @@ "text": [ "\n", "---------VERSION---------\n", - "quairkit: 0.2.0\n", - "torch: 2.4.1+cpu\n", + "quairkit: 0.3.0\n", + "torch: 2.5.1+cpu\n", "numpy: 1.26.0\n", "scipy: 1.14.1\n", - "matplotlib: 3.9.2\n", + "matplotlib: 3.10.0\n", "---------SYSTEM---------\n", - "Python version: 3.10.15\n", + "Python version: 3.10.16\n", "OS: Windows\n", "OS version: 10.0.26100\n", "---------DEVICE---------\n", @@ -515,7 +515,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.15" + "version": "3.10.16" } }, "nbformat": 4, diff --git a/version.sh b/version.sh index 63b2fea..c35efaf 100644 --- a/version.sh +++ b/version.sh @@ -55,7 +55,12 @@ for tag in "${tags[@]}"; do sphinx-build docs/sphinx_src docs/api/$tag rm -rf docs/sphinx_src ;; - v0.2.0 | *) + v0.2.0) + python docs/update_quairkit_rst.py + sphinx-build docs/sphinx_src docs/api/$tag + rm -rf docs/sphinx_src + ;; + v0.3.0 | *) python docs/update_quairkit_rst.py cp -r tutorials docs/sphinx_src/ sphinx-build docs/sphinx_src docs/api/$tag