From a8aea997f875803459414992105042be4e00fada Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Wed, 1 Nov 2023 19:56:11 +0800 Subject: [PATCH 001/200] Update qcnn.py 1. Now accepts arbitrary 2-qubit circuit blocks as input 2. Switched from scipy.optimize.minimize to qibo.optimizers.optimize --- src/qibo/models/qcnn.py | 55 +++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 5d569facac..6604c32f4a 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -1,6 +1,7 @@ import numpy as np -from qibo import Circuit, gates +from qibo import gates, set_backend +from qibo.models import Circuit class QuantumCNN: @@ -16,6 +17,7 @@ class QuantumCNN: nclasses (int): number of classes to be classified. Default setting of 2 (phases). params: initial list of variational parameters. If not provided, all parameters will be initialized to zero. + twoqubitansatz (Qibo.models.Circuit object): A two qubit ansatz that can be input by the user to form the two qubit ansatz. Example: .. testcode:: import qibo @@ -42,12 +44,17 @@ class QuantumCNN: """ - def __init__(self, nqubits, nlayers, nclasses=2, params=None): + def __init__(self, nqubits, nlayers, nclasses=2, params=None, twoqubitansatz = None, Dividend = 2): self.nclasses = nclasses self.nqubits = nqubits self.nlayers = nlayers - - self.nparams_conv = 15 + self.twoqubitansatz = twoqubitansatz + + if self.twoqubitansatz == None: + self.nparams_conv = 15 + else: + self.nparams_conv = len(self.twoqubitansatz.get_parameters()) + self.nparams_pool = 6 self.nparams_layer = self.nparams_conv + self.nparams_pool self.measured_qubits = int(np.ceil(np.log2(self.nclasses))) @@ -160,17 +167,23 @@ def two_qubit_unitary(self, bits, symbols): Returns: Circuit containing the unitaries added to the specified qubits. """ - - c = Circuit(self.nqubits) - c += self.one_qubit_unitary(bits[0], symbols[0:3]) - c += self.one_qubit_unitary(bits[1], symbols[3:6]) - c.add(gates.RZZ(bits[0], bits[1], symbols[6])) - c.add(gates.RYY(bits[0], bits[1], symbols[7])) - c.add(gates.RXX(bits[0], bits[1], symbols[8])) - - c += self.one_qubit_unitary(bits[0], symbols[9:12]) - c += self.one_qubit_unitary(bits[1], symbols[12:]) - + + if self.twoqubitansatz == None: + c = Circuit(self.nqubits) + c += self.one_qubit_unitary(bits[0], symbols[0:3]) + c += self.one_qubit_unitary(bits[1], symbols[3:6]) + c.add(gates.RZZ(bits[0], bits[1], symbols[6])) + c.add(gates.RYY(bits[0], bits[1], symbols[7])) + c.add(gates.RXX(bits[0], bits[1], symbols[8])) + + c += self.one_qubit_unitary(bits[0], symbols[9:12]) + c += self.one_qubit_unitary(bits[1], symbols[12:]) + + else: + c = Circuit(self.nqubits) + c.add(self.twoqubitansatz.on_qubits(bits[0], bits[1])) + c.set_parameters(symbols[0:self.nparams_conv]) + return c def two_qubit_pool(self, source_qubit, sink_qubit, symbols): @@ -219,6 +232,7 @@ def set_circuit_params(self, angles, has_bias=False): pool_params = params[ param_start + self.nparams_conv : param_start + self.nparams_layer ] + #print(pool_params) pool_params += [-pool_params[2], -pool_params[1], -pool_params[0]] expanded_params += conv_params * int(nleft if nleft > 2 else 1) expanded_params += pool_params * int(nleft / 2) @@ -313,13 +327,16 @@ def minimize( Returns: numpy.float64 with value of the minimum found, numpy.ndarray with the optimal angles. """ - from scipy.optimize import minimize + from qibo.optimizers import optimize + + set_backend("numpy") - result = minimize( + if method == "sgd": + set_backend("tensorflow") + + loss, optimal_angles, result = optimize( self.Cost_function, init_theta, args=(data, labels, nshots), method=method ) - loss = result.fun - optimal_angles = result.x self._optimal_angles = optimal_angles From fa205a2d234c6e6dec7b459a36c75a9da6a04cc4 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Wed, 1 Nov 2023 21:10:15 +0800 Subject: [PATCH 002/200] Update test_models_qcnn.py Update test for qcnn upgrade: 1. Now accepts arbitrary 2-qubit circuit blocks as input 2. Switched from scipy.optimize.minimize to qibo.optimizers.optimize --- tests/test_models_qcnn.py | 42 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 871e73ed8d..096f639326 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,8 +3,9 @@ import numpy as np import pytest -from qibo import Circuit, gates -from qibo.models.qcnn import QuantumCNN +from qibo.models import Circuit +from qibo import gates +from QuantumCNNwAnsatz import QuantumCNN num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] @@ -303,3 +304,40 @@ def test_qcnn_training(): predictions.append(1) labels = np.array([[1], [-1], [1]]) test_qcnn.Accuracy(labels, predictions) + +def test_two_qubit_ansatz(): + c = Circuit(2) + c.add(gates.H(0)) + c.add(gates.RX(0,0)) + c.add(gates.CNOT(1,0)) + test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) + +def test_two_qubit_ansatz_training(): + c = Circuit(2) + c.add(gates.H(0)) + c.add(gates.RX(0,0)) + c.add(gates.CNOT(1,0)) + test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) + + data = np.zeros([2, 16]) + for i in range(2): + data_i = np.random.rand(16) + data[i] = data_i / np.linalg.norm(data_i) + labels = [[1], [-1]] + + totalNParams = test_qcnn.nparams_layer*2 + init_theta = [0 for i in range(totalNParams+1)] #totalNParams+1 to account for bias parameter. + + result = test_qcnn.minimize( + init_theta, data=data, labels=labels, nshots=10000, method="Powell" + ) + + # test Predictions function + predictions = [] + for n in range(len(data)): + predictions.append(test_qcnn.predict(data[n], nshots=10000)[0]) + + # test Accuracy function + predictions.append(1) + labels = np.array([[1], [-1], [1]]) + test_qcnn.Accuracy(labels, predictions) From eb12cadbda0c1c00269da7e38818074109870eb3 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Wed, 1 Nov 2023 21:28:05 +0800 Subject: [PATCH 003/200] Update test_models_qcnn.py correction --- tests/test_models_qcnn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 096f639326..7bb1cd5127 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,9 +3,8 @@ import numpy as np import pytest -from qibo.models import Circuit +from qibo.models import Circuit, qcnn from qibo import gates -from QuantumCNNwAnsatz import QuantumCNN num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] From c369f5714b2e30726a5b3d473adc371395941fc7 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Wed, 1 Nov 2023 23:45:15 +0800 Subject: [PATCH 004/200] Update test_models_qcnn.py From 8cb02f7218ac68b3649c4b31eda92357cd1c5a45 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Tue, 7 Nov 2023 16:00:52 +0800 Subject: [PATCH 005/200] Update test_models_qcnn.py fix pytest --- tests/test_models_qcnn.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 7bb1cd5127..98cb1c442e 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,8 +3,9 @@ import numpy as np import pytest -from qibo.models import Circuit, qcnn from qibo import gates +from qibo.models import Circuit +from qibo.models.qcnn import QuantumCNN num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] From fecdcb857cc189c266b8b60a2186b23f506960b1 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:09:55 +0800 Subject: [PATCH 006/200] Update qcnn.py fix #print --- src/qibo/models/qcnn.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 6604c32f4a..fadb0f2788 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -232,7 +232,6 @@ def set_circuit_params(self, angles, has_bias=False): pool_params = params[ param_start + self.nparams_conv : param_start + self.nparams_layer ] - #print(pool_params) pool_params += [-pool_params[2], -pool_params[1], -pool_params[0]] expanded_params += conv_params * int(nleft if nleft > 2 else 1) expanded_params += pool_params * int(nleft / 2) From 321c16729d27bc61d9de0e2f1837967ccad0e4ae Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Wed, 8 Nov 2023 05:10:52 +0800 Subject: [PATCH 007/200] Update test_models_qcnn.py fix pytest for 100% coverage of updated qcnn class --- tests/test_models_qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 98cb1c442e..3148e2c2e4 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -292,7 +292,7 @@ def test_qcnn_training(): test_qcnn = QuantumCNN(nqubits=4, nlayers=1, nclasses=2, params=init_theta) testcircuit = test_qcnn._circuit result = test_qcnn.minimize( - init_theta, data=data, labels=labels, nshots=10000, method="Powell" + init_theta, data=data, labels=labels, nshots=10000, method="sgd" ) # test Predictions function From 8d6fdaa0df623e770104d8bfe87524554bea048d Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Wed, 8 Nov 2023 18:52:00 +0800 Subject: [PATCH 008/200] Update test_models_qcnn.py install tensorflow --- tests/test_models_qcnn.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 3148e2c2e4..e4361d9558 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -1,4 +1,5 @@ import math +import subprocess, sys import numpy as np import pytest @@ -7,6 +8,8 @@ from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN +subprocess.call([sys.executable, '-m', 'pip', 'install', 'tensorflow']) + num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] From 3aac965664c0bdd96ee6c1d77c3cb875d97a69e0 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Thu, 9 Nov 2023 05:57:27 +0800 Subject: [PATCH 009/200] Update qcnn.py remove backend settings in minimize --- src/qibo/models/qcnn.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index fadb0f2788..6a35c77813 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -322,16 +322,11 @@ def minimize( data: the training data to be used in the minimization. labels: the corresponding ground truth for the training data. nshots: int number of runs of the circuit during the sampling process (default=10000). - method: str 'classical optimizer for the minimization'. All methods from scipy.optimize.minmize are suported (default='Powell'). + method: str 'classical optimizer for the minimization'. All methods from qibo.optimizers.optimize are suported (default='Powell'). Returns: numpy.float64 with value of the minimum found, numpy.ndarray with the optimal angles. """ from qibo.optimizers import optimize - - set_backend("numpy") - - if method == "sgd": - set_backend("tensorflow") loss, optimal_angles, result = optimize( self.Cost_function, init_theta, args=(data, labels, nshots), method=method From 470622ad0bdd964c666ece64eb3c171fa364be90 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Thu, 9 Nov 2023 05:59:51 +0800 Subject: [PATCH 010/200] Update test_models_qcnn.py remove explicit sgd check since use case follows as per qibo.optimizer.optimize --- tests/test_models_qcnn.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index e4361d9558..98cb1c442e 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -1,5 +1,4 @@ import math -import subprocess, sys import numpy as np import pytest @@ -8,8 +7,6 @@ from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN -subprocess.call([sys.executable, '-m', 'pip', 'install', 'tensorflow']) - num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] @@ -295,7 +292,7 @@ def test_qcnn_training(): test_qcnn = QuantumCNN(nqubits=4, nlayers=1, nclasses=2, params=init_theta) testcircuit = test_qcnn._circuit result = test_qcnn.minimize( - init_theta, data=data, labels=labels, nshots=10000, method="sgd" + init_theta, data=data, labels=labels, nshots=10000, method="Powell" ) # test Predictions function From d61ed1606e6eece6b5fa0d2a43a804b4880c7487 Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:11:12 +0800 Subject: [PATCH 011/200] Update qcnn.py make initial state copy in Predictions function if backend is qibojit --- src/qibo/models/qcnn.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 6a35c77813..6b8e4e1433 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -264,7 +264,11 @@ def Predictions(self, circuit, theta, init_state, nshots=10000): numpy.array() with predictions for each qubit, for the initial state. """ bias = np.array(theta[0 : self.measured_qubits]) - circuit_exec = circuit(init_state, nshots) + if qibo.get_backend()=='qibojit': + init_state_copy = init_state.copy() + else: + init_state_copy = init_state + circuit_exec = circuit(init_state_copy, nshots) result = circuit_exec.frequencies(binary=False) prediction = np.zeros(self.measured_qubits) From 5d0139f8b05be32bbb3ec8fd71dfdd9ff8ab67cf Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:14:52 +0800 Subject: [PATCH 012/200] Update test_models_qcnn.py test qibojit backend case to create copy of initial state --- tests/test_models_qcnn.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 98cb1c442e..61459b80e6 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,6 +3,7 @@ import numpy as np import pytest +import qibo from qibo import gates from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN @@ -313,6 +314,9 @@ def test_two_qubit_ansatz(): test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) def test_two_qubit_ansatz_training(): + # test qibojit case (copy initial state as quick-fix for in-place update) + qibo.set_backend("qibojit") + c = Circuit(2) c.add(gates.H(0)) c.add(gates.RX(0,0)) From baa44b30913d067e07e52c47b4dd04cb0f33969f Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:16:15 +0800 Subject: [PATCH 013/200] Update qcnn.py add import qibo to check backend --- src/qibo/models/qcnn.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 6b8e4e1433..cc68ac6ddf 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -1,5 +1,6 @@ import numpy as np +import qibo from qibo import gates, set_backend from qibo.models import Circuit From fe22938f27761011c308da062ddf640b17021b5a Mon Sep 17 00:00:00 2001 From: jykhoo1987 <90653892+jykhoo1987@users.noreply.github.com> Date: Thu, 9 Nov 2023 16:39:45 +0800 Subject: [PATCH 014/200] Update qcnn.py add copy flag during initialization --- src/qibo/models/qcnn.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index cc68ac6ddf..692b25519d 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -45,11 +45,17 @@ class QuantumCNN: """ - def __init__(self, nqubits, nlayers, nclasses=2, params=None, twoqubitansatz = None, Dividend = 2): + def __init__(self, nqubits, nlayers, nclasses=2, params=None, twoqubitansatz = None, Dividend = 2, copy_init_state=None): self.nclasses = nclasses self.nqubits = nqubits self.nlayers = nlayers self.twoqubitansatz = twoqubitansatz + + if copy_init_state is None: + if qibo.get_backend()[:7]=='qibojit': + self.copy_init_state = True + else: + self.copy_init_state = False if self.twoqubitansatz == None: self.nparams_conv = 15 @@ -265,7 +271,7 @@ def Predictions(self, circuit, theta, init_state, nshots=10000): numpy.array() with predictions for each qubit, for the initial state. """ bias = np.array(theta[0 : self.measured_qubits]) - if qibo.get_backend()=='qibojit': + if self.copy_init_state is True: init_state_copy = init_state.copy() else: init_state_copy = init_state From ae83dbc66d8b4fdd15da1738a793617c2cfe1bb1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:55:20 +0000 Subject: [PATCH 015/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/models/qcnn.py | 31 ++++++++++++++++++++----------- tests/test_models_qcnn.py | 22 +++++++++++++--------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 692b25519d..8abae35dbd 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -45,23 +45,32 @@ class QuantumCNN: """ - def __init__(self, nqubits, nlayers, nclasses=2, params=None, twoqubitansatz = None, Dividend = 2, copy_init_state=None): + def __init__( + self, + nqubits, + nlayers, + nclasses=2, + params=None, + twoqubitansatz=None, + Dividend=2, + copy_init_state=None, + ): self.nclasses = nclasses self.nqubits = nqubits self.nlayers = nlayers self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if qibo.get_backend()[:7]=='qibojit': + if qibo.get_backend()[:7] == "qibojit": self.copy_init_state = True else: self.copy_init_state = False - + if self.twoqubitansatz == None: self.nparams_conv = 15 else: self.nparams_conv = len(self.twoqubitansatz.get_parameters()) - + self.nparams_pool = 6 self.nparams_layer = self.nparams_conv + self.nparams_pool self.measured_qubits = int(np.ceil(np.log2(self.nclasses))) @@ -174,23 +183,23 @@ def two_qubit_unitary(self, bits, symbols): Returns: Circuit containing the unitaries added to the specified qubits. """ - - if self.twoqubitansatz == None: + + if self.twoqubitansatz == None: c = Circuit(self.nqubits) c += self.one_qubit_unitary(bits[0], symbols[0:3]) c += self.one_qubit_unitary(bits[1], symbols[3:6]) c.add(gates.RZZ(bits[0], bits[1], symbols[6])) c.add(gates.RYY(bits[0], bits[1], symbols[7])) c.add(gates.RXX(bits[0], bits[1], symbols[8])) - + c += self.one_qubit_unitary(bits[0], symbols[9:12]) c += self.one_qubit_unitary(bits[1], symbols[12:]) - + else: c = Circuit(self.nqubits) c.add(self.twoqubitansatz.on_qubits(bits[0], bits[1])) - c.set_parameters(symbols[0:self.nparams_conv]) - + c.set_parameters(symbols[0 : self.nparams_conv]) + return c def two_qubit_pool(self, source_qubit, sink_qubit, symbols): @@ -338,7 +347,7 @@ def minimize( numpy.float64 with value of the minimum found, numpy.ndarray with the optimal angles. """ from qibo.optimizers import optimize - + loss, optimal_angles, result = optimize( self.Cost_function, init_theta, args=(data, labels, nshots), method=method ) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 61459b80e6..7e9168b007 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -306,22 +306,24 @@ def test_qcnn_training(): labels = np.array([[1], [-1], [1]]) test_qcnn.Accuracy(labels, predictions) + def test_two_qubit_ansatz(): c = Circuit(2) c.add(gates.H(0)) - c.add(gates.RX(0,0)) - c.add(gates.CNOT(1,0)) - test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) + c.add(gates.RX(0, 0)) + c.add(gates.CNOT(1, 0)) + test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) + def test_two_qubit_ansatz_training(): # test qibojit case (copy initial state as quick-fix for in-place update) qibo.set_backend("qibojit") - + c = Circuit(2) c.add(gates.H(0)) - c.add(gates.RX(0,0)) - c.add(gates.CNOT(1,0)) - test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) + c.add(gates.RX(0, 0)) + c.add(gates.CNOT(1, 0)) + test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) data = np.zeros([2, 16]) for i in range(2): @@ -329,8 +331,10 @@ def test_two_qubit_ansatz_training(): data[i] = data_i / np.linalg.norm(data_i) labels = [[1], [-1]] - totalNParams = test_qcnn.nparams_layer*2 - init_theta = [0 for i in range(totalNParams+1)] #totalNParams+1 to account for bias parameter. + totalNParams = test_qcnn.nparams_layer * 2 + init_theta = [ + 0 for i in range(totalNParams + 1) + ] # totalNParams+1 to account for bias parameter. result = test_qcnn.minimize( init_theta, data=data, labels=labels, nshots=10000, method="Powell" From fb49d45dc7410ebff7a4e07eeb9032dcbb625b0e Mon Sep 17 00:00:00 2001 From: rahul Date: Thu, 23 Nov 2023 10:47:07 +0100 Subject: [PATCH 016/200] remove dividend from src/qibo/models/qcnn.py Co-authored-by: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> --- src/qibo/models/qcnn.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 8abae35dbd..bc26ed7e0f 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -52,7 +52,6 @@ def __init__( nclasses=2, params=None, twoqubitansatz=None, - Dividend=2, copy_init_state=None, ): self.nclasses = nclasses From 6af5b684f1a691dd5675fa26c65884321d0958f0 Mon Sep 17 00:00:00 2001 From: rahul Date: Thu, 23 Nov 2023 10:48:13 +0100 Subject: [PATCH 017/200] Update src/qibo/models/qcnn.py Co-authored-by: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> --- src/qibo/models/qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index bc26ed7e0f..ba79f6d47d 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -60,7 +60,7 @@ def __init__( self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if qibo.get_backend()[:7] == "qibojit": + if "qibojit" in qibo.get_backend(): self.copy_init_state = True else: self.copy_init_state = False From cff29f8809b7276f4cb3b0e390271b46d24fd9ae Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 11 Dec 2023 02:46:14 +0800 Subject: [PATCH 018/200] Update qcnn.py update in response to comments. --- src/qibo/models/qcnn.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index ba79f6d47d..49b1123304 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -1,7 +1,6 @@ import numpy as np -import qibo -from qibo import gates, set_backend +from qibo import gates, get_backend from qibo.models import Circuit @@ -18,15 +17,16 @@ class QuantumCNN: nclasses (int): number of classes to be classified. Default setting of 2 (phases). params: initial list of variational parameters. If not provided, all parameters will be initialized to zero. - twoqubitansatz (Qibo.models.Circuit object): A two qubit ansatz that can be input by the user to form the two qubit ansatz. + twoqubitansatz (Qibo.models.Circuit object): A two qubit ansatz that can be input by the user to form the two qubit ansatz used in the convolutional circuit. Example: .. testcode:: - import qibo - from qibo.models.qcnn import QuantumCNN + import math - import qibo import numpy as np import random + import qibo + from qibo.models.qcnn import QuantumCNN + qibo.set_backend("numpy") data = np.random.rand(16) @@ -60,7 +60,7 @@ def __init__( self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if "qibojit" in qibo.get_backend(): + if "qibojit" in get_backend(): self.copy_init_state = True else: self.copy_init_state = False From ce5441e89dd14ae0e88e451422a17f559635942c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Dec 2023 18:46:35 +0000 Subject: [PATCH 019/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/models/qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 49b1123304..92a940102c 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -20,7 +20,7 @@ class QuantumCNN: twoqubitansatz (Qibo.models.Circuit object): A two qubit ansatz that can be input by the user to form the two qubit ansatz used in the convolutional circuit. Example: .. testcode:: - + import math import numpy as np import random From bbae84691b675f2d1e3dc27afb8ee9a46a4c6c4e Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 11 Dec 2023 02:49:26 +0800 Subject: [PATCH 020/200] Update test_models_qcnn.py The last two training tests now test both qibojit and numpy backends. --- tests/test_models_qcnn.py | 49 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 7e9168b007..cc8ed5e2c9 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -1,17 +1,15 @@ import math - import numpy as np -import pytest -import qibo -from qibo import gates +import pytest + from qibo.models import Circuit +from qibo import gates, set_backend from qibo.models.qcnn import QuantumCNN num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] - def test_classifier_circuit2(): """ """ nqubits = 2 @@ -275,10 +273,18 @@ def test_1_qubit_classifier_circuit_error(): except: pass +def test_two_qubit_ansatz(): + c = Circuit(2) + c.add(gates.H(0)) + c.add(gates.RX(0,0)) + c.add(gates.CNOT(1,0)) + test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) + +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) -def test_qcnn_training(): +def test_qcnn_training(backend): + set_backend(backend) import random - # generate 2 random states and labels for pytest data = np.zeros([2, 16]) for i in range(2): @@ -304,26 +310,16 @@ def test_qcnn_training(): # test Accuracy function predictions.append(1) labels = np.array([[1], [-1], [1]]) - test_qcnn.Accuracy(labels, predictions) - - -def test_two_qubit_ansatz(): - c = Circuit(2) - c.add(gates.H(0)) - c.add(gates.RX(0, 0)) - c.add(gates.CNOT(1, 0)) - test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) -def test_two_qubit_ansatz_training(): - # test qibojit case (copy initial state as quick-fix for in-place update) - qibo.set_backend("qibojit") - +def test_two_qubit_ansatz_training(backend): + set_backend(backend) c = Circuit(2) c.add(gates.H(0)) - c.add(gates.RX(0, 0)) - c.add(gates.CNOT(1, 0)) - test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) + c.add(gates.RX(0,0)) + c.add(gates.CNOT(1,0)) + test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) data = np.zeros([2, 16]) for i in range(2): @@ -331,10 +327,8 @@ def test_two_qubit_ansatz_training(): data[i] = data_i / np.linalg.norm(data_i) labels = [[1], [-1]] - totalNParams = test_qcnn.nparams_layer * 2 - init_theta = [ - 0 for i in range(totalNParams + 1) - ] # totalNParams+1 to account for bias parameter. + totalNParams = test_qcnn.nparams_layer*2 + init_theta = [0 for i in range(totalNParams+1)] #totalNParams+1 to account for bias parameter. result = test_qcnn.minimize( init_theta, data=data, labels=labels, nshots=10000, method="Powell" @@ -349,3 +343,4 @@ def test_two_qubit_ansatz_training(): predictions.append(1) labels = np.array([[1], [-1], [1]]) test_qcnn.Accuracy(labels, predictions) + From 09d7e01810af3ac06a92fb413366b863caca6b43 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 10 Dec 2023 18:49:46 +0000 Subject: [PATCH 021/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_models_qcnn.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index cc8ed5e2c9..1a22ab80ba 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -1,15 +1,16 @@ import math -import numpy as np -import pytest +import numpy as np +import pytest -from qibo.models import Circuit from qibo import gates, set_backend +from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] + def test_classifier_circuit2(): """ """ nqubits = 2 @@ -273,18 +274,20 @@ def test_1_qubit_classifier_circuit_error(): except: pass + def test_two_qubit_ansatz(): c = Circuit(2) c.add(gates.H(0)) - c.add(gates.RX(0,0)) - c.add(gates.CNOT(1,0)) - test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) + c.add(gates.RX(0, 0)) + c.add(gates.CNOT(1, 0)) + test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_qcnn_training(backend): set_backend(backend) import random + # generate 2 random states and labels for pytest data = np.zeros([2, 16]) for i in range(2): @@ -311,15 +314,15 @@ def test_qcnn_training(backend): predictions.append(1) labels = np.array([[1], [-1], [1]]) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_two_qubit_ansatz_training(backend): set_backend(backend) c = Circuit(2) c.add(gates.H(0)) - c.add(gates.RX(0,0)) - c.add(gates.CNOT(1,0)) - test_qcnn = QuantumCNN(4,2,2, twoqubitansatz = c) + c.add(gates.RX(0, 0)) + c.add(gates.CNOT(1, 0)) + test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) data = np.zeros([2, 16]) for i in range(2): @@ -327,8 +330,10 @@ def test_two_qubit_ansatz_training(backend): data[i] = data_i / np.linalg.norm(data_i) labels = [[1], [-1]] - totalNParams = test_qcnn.nparams_layer*2 - init_theta = [0 for i in range(totalNParams+1)] #totalNParams+1 to account for bias parameter. + totalNParams = test_qcnn.nparams_layer * 2 + init_theta = [ + 0 for i in range(totalNParams + 1) + ] # totalNParams+1 to account for bias parameter. result = test_qcnn.minimize( init_theta, data=data, labels=labels, nshots=10000, method="Powell" @@ -343,4 +348,3 @@ def test_two_qubit_ansatz_training(backend): predictions.append(1) labels = np.array([[1], [-1], [1]]) test_qcnn.Accuracy(labels, predictions) - From f34ca9659304afec35aa14c1b32faa62ec301684 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 9 Jan 2024 16:15:03 +0800 Subject: [PATCH 022/200] Update src/qibo/models/qcnn.py Co-authored-by: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> --- src/qibo/models/qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 92a940102c..1f64e967ef 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -17,7 +17,7 @@ class QuantumCNN: nclasses (int): number of classes to be classified. Default setting of 2 (phases). params: initial list of variational parameters. If not provided, all parameters will be initialized to zero. - twoqubitansatz (Qibo.models.Circuit object): A two qubit ansatz that can be input by the user to form the two qubit ansatz used in the convolutional circuit. + twoqubitansatz (:class:`qibo.models.Circuit`): a two qubit ansatz that can be input by the user to form the two qubit ansatz used in the convolutional circuit. Example: .. testcode:: From d4c0374ee5f91a3481b3b01095d444a1128f7198 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 9 Jan 2024 17:36:37 +0800 Subject: [PATCH 023/200] added backend parameter to all the tests --- tests/test_models_qcnn.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 86af4e070b..c873aaf945 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -11,7 +11,7 @@ angles0 = [i * math.pi / num_angles for i in range(num_angles)] -def test_classifier_circuit2(): +def test_classifier_circuit2(backend): """ """ nqubits = 2 nlayers = int(nqubits / 2) @@ -35,7 +35,7 @@ def test_classifier_circuit2(): np.testing.assert_allclose(statevector.imag, real_vector.imag, atol=1e-5) -def get_real_vector2(): +def get_real_vector2(backend): nqubits = 2 bits = range(nqubits) init_state = np.ones(2**nqubits) / np.sqrt(2**nqubits) # @@ -75,7 +75,7 @@ def get_real_vector2(): return a -def test_classifier_circuit4(): +def test_classifier_circuit4(backend): """ """ nqubits = 4 nlayers = int(nqubits / 2) @@ -93,7 +93,7 @@ def test_classifier_circuit4(): np.testing.assert_allclose(statevector.imag, real_vector.imag, atol=1e-5) -def get_real_vector4(): +def get_real_vector4(backend): nqubits = 4 init_state = np.ones(2**nqubits) / np.sqrt(2**nqubits) # angles = angles0 @@ -231,7 +231,7 @@ def get_real_vector4(): return a -def one_qubit_unitary(nqubits, bit, symbols): +def one_qubit_unitary(nqubits, bit, symbols, backend): c = Circuit(nqubits) c.add(gates.RX(bit, symbols[0])) c.add(gates.RY(bit, symbols[1])) @@ -240,42 +240,42 @@ def one_qubit_unitary(nqubits, bit, symbols): return c -def RXX_unitary(nqubits, bit0, bit1, angle): +def RXX_unitary(nqubits, bit0, bit1, angle, backend): c = Circuit(nqubits) c.add(gates.RXX(bit0, bit1, angle)) return c -def RYY_unitary(nqubits, bit0, bit1, angle): +def RYY_unitary(nqubits, bit0, bit1, angle, backend): c = Circuit(nqubits) c.add(gates.RYY(bit0, bit1, angle)) return c -def RZZ_unitary(nqubits, bit0, bit1, angle): +def RZZ_unitary(nqubits, bit0, bit1, angle, backend): c = Circuit(nqubits) c.add(gates.RZZ(bit0, bit1, angle)) return c -def CNOT_unitary(nqubits, bit0, bit1): +def CNOT_unitary(nqubits, bit0, bit1, backend): c = Circuit(nqubits) c.add(gates.CNOT(bit0, bit1)) return c -def test_1_qubit_classifier_circuit_error(): +def test_1_qubit_classifier_circuit_error(backend): try: QuantumCNN(nqubits=1, nlayers=1, nclasses=2) except: pass -def test_two_qubit_ansatz(): +def test_two_qubit_ansatz(backend): c = Circuit(2) c.add(gates.H(0)) c.add(gates.RX(0, 0)) @@ -283,7 +283,6 @@ def test_two_qubit_ansatz(): test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_qcnn_training(backend): set_backend(backend) import random @@ -315,7 +314,6 @@ def test_qcnn_training(backend): labels = np.array([[1], [-1], [1]]) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_two_qubit_ansatz_training(backend): set_backend(backend) c = Circuit(2) From 0c5302333d882527d342c3056717cfd1b3441358 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 9 Jan 2024 18:38:46 +0800 Subject: [PATCH 024/200] small fixes --- tests/test_models_qcnn.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index c873aaf945..ed1d6e84af 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from qibo import gates, set_backend +from qibo import gates from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN @@ -28,7 +28,7 @@ def test_classifier_circuit2(backend): # circuit = qcnn._circuit statevector = circuit(init_state).state() - real_vector = get_real_vector2() + real_vector = get_real_vector2(backend) # to compare statevector and real_vector np.testing.assert_allclose(statevector.real, real_vector.real, atol=1e-5) @@ -86,7 +86,7 @@ def test_classifier_circuit4(backend): circuit = qcnn.Classifier_circuit(angles) statevector = circuit(init_state).state() - real_vector = get_real_vector4() + real_vector = get_real_vector4(backend) # to compare statevector and real_vector np.testing.assert_allclose(statevector.real, real_vector.real, atol=1e-5) @@ -284,7 +284,6 @@ def test_two_qubit_ansatz(backend): def test_qcnn_training(backend): - set_backend(backend) import random # generate 2 random states and labels for pytest @@ -315,7 +314,6 @@ def test_qcnn_training(backend): def test_two_qubit_ansatz_training(backend): - set_backend(backend) c = Circuit(2) c.add(gates.H(0)) c.add(gates.RX(0, 0)) From 82a892d4de3f794c47e1ce01a1f3edffc20c19ff Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 9 Jan 2024 19:04:49 +0800 Subject: [PATCH 025/200] small fixes --- tests/test_models_qcnn.py | 116 +++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index ed1d6e84af..9f5d66d5fc 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -44,29 +44,29 @@ def get_real_vector2(backend): # convolution k = 0 a = np.dot( - one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), init_state + one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), init_state ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[0], bits[1], angles[k]).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[0], bits[1], angles[k]).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[0], bits[1], angles[k]).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) k += 3 # pooling ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), a) - a = np.dot(CNOT_unitary(nqubits, bits[0], bits[1]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[0], bits[1], backend).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[1], angles[ksink : ksink + 3]) + one_qubit_unitary(nqubits, bits[1], angles[ksink : ksink + 3], backend) .invert() .unitary(), a, @@ -105,81 +105,81 @@ def get_real_vector4(backend): b1 = 1 k = 0 a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), init_state + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), init_state ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) b0 = 2 b1 = 3 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) b0 = 1 b1 = 2 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) b0 = 3 b1 = 0 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) # pooling - layer 1 k = 15 # k+=3 ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), a) - a = np.dot(CNOT_unitary(nqubits, bits[0], bits[2]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[0], bits[2], backend).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[2], angles[ksink : ksink + 3]) + one_qubit_unitary(nqubits, bits[2], angles[ksink : ksink + 3], backend) .invert() .unitary(), a, @@ -187,12 +187,12 @@ def get_real_vector4(backend): k = 15 # k+=3 ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) - a = np.dot(CNOT_unitary(nqubits, bits[1], bits[3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[1], bits[3], backend).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3]) + one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3], backend) .invert() .unitary(), a, @@ -200,29 +200,29 @@ def get_real_vector4(backend): # convolution - layer 2 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[2], bits[3], angles[k]).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[2], bits[3], angles[k]).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[2], bits[3], angles[k]).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) k += 3 # pooling - layer 2 ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) - a = np.dot(CNOT_unitary(nqubits, bits[2], bits[3]).unitary(), a) + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[2], bits[3], backend).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3]) + one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3], backend) .invert() .unitary(), a, From d6e9c081b2f0eb28d9246050abdbe357f6f3be2b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:05:08 +0000 Subject: [PATCH 026/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_models_qcnn.py | 174 ++++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 44 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 9f5d66d5fc..eb31d246ee 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -44,10 +44,13 @@ def get_real_vector2(backend): # convolution k = 0 a = np.dot( - one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), init_state + one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), + init_state, ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a + ) k += 3 a = np.dot(RZZ_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) k += 1 @@ -55,15 +58,23 @@ def get_real_vector2(backend): k += 1 a = np.dot(RXX_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a + ) k += 3 # pooling ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a + ) a = np.dot(CNOT_unitary(nqubits, bits[0], bits[1], backend).unitary(), a) a = np.dot( one_qubit_unitary(nqubits, bits[1], angles[ksink : ksink + 3], backend) @@ -105,78 +116,137 @@ def get_real_vector4(backend): b1 = 1 k = 0 a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), init_state + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), + init_state, ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) b0 = 2 b1 = 3 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) b0 = 1 b1 = 2 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) b0 = 3 b1 = 0 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a) + a = np.dot( + RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a + ) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a + ) # pooling - layer 1 k = 15 # k+=3 ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a + ) a = np.dot(CNOT_unitary(nqubits, bits[0], bits[2], backend).unitary(), a) a = np.dot( one_qubit_unitary(nqubits, bits[2], angles[ksink : ksink + 3], backend) @@ -187,9 +257,13 @@ def get_real_vector4(backend): k = 15 # k+=3 ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a + ) a = np.dot(CNOT_unitary(nqubits, bits[1], bits[3], backend).unitary(), a) a = np.dot( one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3], backend) @@ -200,9 +274,13 @@ def get_real_vector4(backend): # convolution - layer 2 k = 0 - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a + ) k += 3 a = np.dot(RZZ_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) k += 1 @@ -210,16 +288,24 @@ def get_real_vector4(backend): k += 1 a = np.dot(RXX_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) k += 1 - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a + ) k += 3 # pooling - layer 2 ksink = k - a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a + ) k += 3 - a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a) + a = np.dot( + one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a + ) a = np.dot(CNOT_unitary(nqubits, bits[2], bits[3], backend).unitary(), a) a = np.dot( one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3], backend) From 5bbe8b9b2b8c795187fd63266ecc09e06480065d Mon Sep 17 00:00:00 2001 From: rahul Date: Thu, 11 Jan 2024 14:24:15 +0800 Subject: [PATCH 027/200] testing --- tests/test_models_qcnn.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index eb31d246ee..17e1fe1575 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,10 +3,14 @@ import numpy as np import pytest -from qibo import gates +from qibo import gates, get_backend from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN +import warnings + +text = str(get_backend()) + num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] @@ -400,6 +404,7 @@ def test_qcnn_training(backend): def test_two_qubit_ansatz_training(backend): + warnings.warn(UserWarning("{}".format(text))) c = Circuit(2) c.add(gates.H(0)) c.add(gates.RX(0, 0)) From ed9ad977a966c096cdcfda5f78b15a95d2bf4f1f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 06:24:36 +0000 Subject: [PATCH 028/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_models_qcnn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 17e1fe1575..e6b5c6b569 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -1,4 +1,5 @@ import math +import warnings import numpy as np import pytest @@ -7,8 +8,6 @@ from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN -import warnings - text = str(get_backend()) num_angles = 21 From 0f3993b7a2bf05db5fc965f3f0e681e8dddeef21 Mon Sep 17 00:00:00 2001 From: rahul Date: Thu, 11 Jan 2024 14:57:45 +0800 Subject: [PATCH 029/200] test --- tests/test_models_qcnn.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index e6b5c6b569..9d7f858f64 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -1,14 +1,12 @@ import math -import warnings import numpy as np import pytest -from qibo import gates, get_backend +from qibo import gates from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN -text = str(get_backend()) num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] @@ -403,7 +401,6 @@ def test_qcnn_training(backend): def test_two_qubit_ansatz_training(backend): - warnings.warn(UserWarning("{}".format(text))) c = Circuit(2) c.add(gates.H(0)) c.add(gates.RX(0, 0)) From 6ed2ae8c4f8ec1a0e914d5e0e33fc8c27aaf80bc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 06:58:04 +0000 Subject: [PATCH 030/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_models_qcnn.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 9d7f858f64..eb31d246ee 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -7,7 +7,6 @@ from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN - num_angles = 21 angles0 = [i * math.pi / num_angles for i in range(num_angles)] From 687705f4e6ed061caa49625dc06b8be52bc44e98 Mon Sep 17 00:00:00 2001 From: rahul Date: Thu, 11 Jan 2024 14:58:45 +0800 Subject: [PATCH 031/200] test (hopefully will fix) --- src/qibo/models/qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 1f64e967ef..51146ff34e 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -60,7 +60,7 @@ def __init__( self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if "qibojit" in get_backend(): + if ("qibojit" in get_backend()) or ("qibojit-numba" in get_backend()) or ("qibojit-cuquantum" in get_backend()) or ("qibojit-cupy" in get_backend()): self.copy_init_state = True else: self.copy_init_state = False From c95ec9252ca1a9361fa444a65e0e950cbf07b3a1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 06:59:03 +0000 Subject: [PATCH 032/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/models/qcnn.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 51146ff34e..640904e6ee 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -60,7 +60,12 @@ def __init__( self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if ("qibojit" in get_backend()) or ("qibojit-numba" in get_backend()) or ("qibojit-cuquantum" in get_backend()) or ("qibojit-cupy" in get_backend()): + if ( + ("qibojit" in get_backend()) + or ("qibojit-numba" in get_backend()) + or ("qibojit-cuquantum" in get_backend()) + or ("qibojit-cupy" in get_backend()) + ): self.copy_init_state = True else: self.copy_init_state = False From 2d6037e8ec616200edd1f368a3b6994b814b488c Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Tue, 16 Jan 2024 13:04:51 +0400 Subject: [PATCH 033/200] split star transpiler into placer and router --- src/qibo/transpiler/placer.py | 77 +++++++++++++ src/qibo/transpiler/router.py | 102 +++++++++++++++++ src/qibo/transpiler/star_connectivity.py | 126 --------------------- tests/test_transpiler_router.py | 74 +++++++++++- tests/test_transpiler_star_connectivity.py | 98 ---------------- 5 files changed, 251 insertions(+), 226 deletions(-) delete mode 100644 src/qibo/transpiler/star_connectivity.py delete mode 100644 tests/test_transpiler_star_connectivity.py diff --git a/src/qibo/transpiler/placer.py b/src/qibo/transpiler/placer.py index 96c5ae04d0..1d1940f236 100644 --- a/src/qibo/transpiler/placer.py +++ b/src/qibo/transpiler/placer.py @@ -84,6 +84,83 @@ def _find_gates_qubits_pairs(circuit: Circuit): return gates_qubits_pairs +class StarConnectivityPlacer(Placer): + """Find an optimized qubit placement for the following connectivity: + + q + | + q -- q -- q + | + q + + Args: + connectivity (:class:`networkx.Graph`): chip connectivity, not used for this transpiler. + middle_qubit (int, optional): qubit id of the qubit that is in the middle of the star. + """ + + def __init__(self, connectivity=None, middle_qubit: int = 2): + self.middle_qubit = middle_qubit + self.connectivity = connectivity + + def __call__(self, circuit: Circuit): + """Apply the transpiler transformation on a given circuit. + + Args: + circuit (:class:`qibo.models.circuit.Circuit`): The original Qibo circuit to transform. + This circuit must contain up to two-qubit gates. + + Returns: + (dict): physical to logical qubit mapping. + """ + + # find the number of qubits for hardware circuit + nqubits = max(circuit.nqubits, self.middle_qubit + 1) + hardware_qubits = list(range(nqubits)) + + for i, gate in enumerate(circuit.queue): + if len(gate.qubits) > 2: + raise_error( + PlacementError, + "Gates targeting more than 2 qubits are not supported", + ) + if len(gate.qubits) == 2: + if self.middle_qubit not in gate.qubits: + new_middle = self._find_connected_qubit( + gate.qubits, circuit.queue[i + 1 :], hardware_qubits + ) + hardware_qubits[self.middle_qubit], hardware_qubits[new_middle] = ( + new_middle, + self.middle_qubit, + ) + break + + return dict( + zip(["q" + str(i) for i in range(circuit.nqubits)], range(circuit.nqubits)) + ) + + def _find_connected_qubit(qubits, queue, hardware_qubits): + """ + Finds which qubit should be mapped to hardware middle qubit + by looking at the two-qubit gates that follow. + """ + possible_qubits = set(qubits) + for next_gate in queue: + if len(next_gate.qubits) > 2: + raise_error( + PlacementError, + "Gates targeting more than 2 qubits are not supported", + ) + if len(next_gate.qubits) == 2: + possible_qubits &= {hardware_qubits.index(q) for q in next_gate.qubits} + if not possible_qubits: + # freedom of choice + return qubits[0] + elif len(possible_qubits) == 1: + return possible_qubits.pop() + # freedom of choice + return qubits[0] + + class Trivial(Placer): """Place qubits according to the following notation: diff --git a/src/qibo/transpiler/router.py b/src/qibo/transpiler/router.py index 00e6a86da5..617e234581 100644 --- a/src/qibo/transpiler/router.py +++ b/src/qibo/transpiler/router.py @@ -40,6 +40,108 @@ def assert_connectivity(connectivity: nx.Graph, circuit: Circuit): ) +class StarConnectivityRouter(Router): + """Transforms an arbitrary circuit to one that can be executed on hardware. + + This transpiler produces a circuit that respects the following connectivity: + + q + | + q -- q -- q + | + q + + by adding SWAP gates when needed. + + Args: + connectivity (:class:`networkx.Graph`): chip connectivity, not used for this transpiler. + middle_qubit (int, optional): qubit id of the qubit that is in the middle of the star. + """ + + def __init__(self, connectivity=None, middle_qubit: int = 2): + self.middle_qubit = middle_qubit + self.connectivity = connectivity + + def __call__(self, circuit: Circuit, initial_layout=None): + """Apply the transpiler transformation on a given circuit. + + Args: + circuit (:class:`qibo.models.circuit.Circuit`): The original Qibo circuit to transform. + This circuit must contain up to two-qubit gates. + initial_layout (dict): initial physical-to-logical qubit mapping, + use `qibo.transpiler.placer.StarConnectivityPlacer` for better performance. + + Returns: + (:class:`qibo.models.circuit.Circuit`, list): circuit that performs the same operation + as the original but respects the hardware connectivity, + and list that maps logical to hardware qubits. + """ + + middle_qubit = self.middle_qubit + nqubits = max(circuit.nqubits, middle_qubit + 1) + # new circuit object that will be compatible with hardware connectivity + new = circuit.__class__(nqubits) + # list to maps logical to hardware qubits + hardware_qubits = list(initial_layout.values()) + + for i, gate in enumerate(circuit.queue): + # map gate qubits to hardware + qubits = tuple(hardware_qubits.index(q) for q in gate.qubits) + if isinstance(gate, gates.M): + new_gate = gates.M(*qubits, **gate.init_kwargs) + new_gate.result = gate.result + new.add(new_gate) + continue + + if len(qubits) > 2: + raise ConnectivityError( + "Gates targeting more than two qubits are not supported." + ) + + elif len(qubits) == 2 and middle_qubit not in qubits: + # find which qubit should be moved + new_middle = _find_connected_qubit( + qubits, circuit.queue[i + 1 :], hardware_qubits + ) + # update hardware qubits according to the swap + hardware_qubits[middle_qubit], hardware_qubits[new_middle] = ( + hardware_qubits[new_middle], + hardware_qubits[middle_qubit], + ) + new.add(gates.SWAP(middle_qubit, new_middle)) + # update gate qubits according to the new swap + qubits = tuple(hardware_qubits.index(q) for q in gate.qubits) + + # add gate to the hardware circuit + if isinstance(gate, gates.Unitary): + # gates.Unitary requires matrix as first argument + matrix = gate.init_args[0] + new.add(gate.__class__(matrix, *qubits, **gate.init_kwargs)) + else: + new.add(gate.__class__(*qubits, **gate.init_kwargs)) + hardware_qubits_keys = ["q" + str(i) for i in range(5)] + return new, dict(zip(hardware_qubits_keys, hardware_qubits)) + + +def _find_connected_qubit(qubits, queue, hardware_qubits): + """Helper method for :meth:`qibo.transpiler.StarConnectivity`. + + Finds which qubit should be mapped to hardware middle qubit + by looking at the two-qubit gates that follow. + """ + possible_qubits = set(qubits) + for next_gate in queue: + if len(next_gate.qubits) == 2: + possible_qubits &= {hardware_qubits.index(q) for q in next_gate.qubits} + if not possible_qubits: + # freedom of choice + return qubits[0] + elif len(possible_qubits) == 1: + return possible_qubits.pop() + # freedom of choice + return qubits[0] + + class CircuitMap: """Class that stores the circuit and physical-logical mapping during routing. diff --git a/src/qibo/transpiler/star_connectivity.py b/src/qibo/transpiler/star_connectivity.py deleted file mode 100644 index 693df030c1..0000000000 --- a/src/qibo/transpiler/star_connectivity.py +++ /dev/null @@ -1,126 +0,0 @@ -from qibo import Circuit, gates -from qibo.transpiler.abstract import Router -from qibo.transpiler.router import ConnectivityError - - -# TODO: split into routing plus placer steps -class StarConnectivity(Router): - """Transforms an arbitrary circuit to one that can be executed on hardware. - - This transpiler produces a circuit that respects the following connectivity: - - q - | - q -- q -- q - | - q - - by adding SWAP gates when needed. - - Args: - connectivity (:class:`networkx.Graph`): chip connectivity, not used for this transpiler. - middle_qubit (int, optional): qubit id of the qubit that is in the middle of the star. - """ - - def __init__(self, connectivity=None, middle_qubit: int = 2): - self.middle_qubit = middle_qubit - self.connectivity = connectivity - - def __call__(self, circuit: Circuit, initial_layout=None): - """Apply the transpiler transformation on a given circuit. - - Args: - circuit (:class:`qibo.models.circuit.Circuit`): The original Qibo circuit to transform. - This circuit must contain up to two-qubit gates. - - Returns: - (:class:`qibo.models.circuit.Circuit`, list): circuit that performs the same operation - as the original but respects the hardware connectivity, - and list that maps logical to hardware qubits. - """ - - middle_qubit = self.middle_qubit - # find the number of qubits for hardware circuit - if circuit.nqubits == 1: - nqubits = 1 - else: - nqubits = max(circuit.nqubits, middle_qubit + 1) - # new circuit object that will be compatible with hardware connectivity - new = circuit.__class__(nqubits) - # list to maps logical to hardware qubits - hardware_qubits = list(range(nqubits)) - - # find initial qubit mapping - for i, gate in enumerate(circuit.queue): - if len(gate.qubits) == 2: - if middle_qubit not in gate.qubits: - new_middle = _find_connected_qubit( - gate.qubits, circuit.queue[i + 1 :], hardware_qubits - ) - hardware_qubits[middle_qubit], hardware_qubits[new_middle] = ( - hardware_qubits[new_middle], - hardware_qubits[middle_qubit], - ) - break - - # the first SWAP is not needed as it can be applied via virtual mapping - add_swap = False - for i, gate in enumerate(circuit.queue): - # map gate qubits to hardware - qubits = tuple(hardware_qubits.index(q) for q in gate.qubits) - if isinstance(gate, gates.M): - new_gate = gates.M(*qubits, **gate.init_kwargs) - new_gate.result = gate.result - new.add(new_gate) - continue - - if len(qubits) > 2: - raise ConnectivityError( - "Gates targeting more than two qubits are not supported." - ) - - elif len(qubits) == 2 and middle_qubit not in qubits: - # find which qubit should be moved to 0 - new_middle = _find_connected_qubit( - qubits, circuit.queue[i + 1 :], hardware_qubits - ) - # update hardware qubits according to the swap - hardware_qubits[middle_qubit], hardware_qubits[new_middle] = ( - hardware_qubits[new_middle], - hardware_qubits[middle_qubit], - ) - if add_swap: - new.add(gates.SWAP(middle_qubit, new_middle)) - # update gate qubits according to the new swap - qubits = tuple(hardware_qubits.index(q) for q in gate.qubits) - - # add gate to the hardware circuit - if isinstance(gate, gates.Unitary): - # gates.Unitary requires matrix as first argument - matrix = gate.init_args[0] - new.add(gate.__class__(matrix, *qubits, **gate.init_kwargs)) - else: - new.add(gate.__class__(*qubits, **gate.init_kwargs)) - if len(qubits) == 2: - add_swap = True - hardware_qubits_keys = ["q" + str(i) for i in range(5)] - return new, dict(zip(hardware_qubits_keys, hardware_qubits)) - - -def _find_connected_qubit(qubits, queue, hardware_qubits): - """Helper method for :meth:`qibo.transpiler.StarConnectivity`. - - Finds which qubit should be mapped to hardware middle qubit - by looking at the two-qubit gates that follow. - """ - possible_qubits = set(qubits) - for next_gate in queue: - if len(next_gate.qubits) == 2: - possible_qubits &= {hardware_qubits.index(q) for q in next_gate.qubits} - if not possible_qubits: - # freedom of choice - return qubits[0] - elif len(possible_qubits) == 1: - return possible_qubits.pop() - # freedom of choice - return qubits[0] diff --git a/tests/test_transpiler_router.py b/tests/test_transpiler_router.py index 716f0f02bd..420b1d3a81 100644 --- a/tests/test_transpiler_router.py +++ b/tests/test_transpiler_router.py @@ -10,8 +10,21 @@ assert_circuit_equivalence, restrict_connectivity_qubits, ) -from qibo.transpiler.placer import Custom, Random, Subgraph, Trivial, assert_placement -from qibo.transpiler.router import CircuitMap, Sabre, ShortestPaths, assert_connectivity +from qibo.transpiler.placer import ( + Custom, + Random, + StarConnectivityPlacer, + Subgraph, + Trivial, + assert_placement, +) +from qibo.transpiler.router import ( + CircuitMap, + Sabre, + ShortestPaths, + StarConnectivityRouter, + assert_connectivity, +) def star_connectivity(): @@ -331,3 +344,60 @@ def test_restrict_qubits(router_algorithm): ) assert_connectivity(restricted_connectivity, routed_circ) assert_placement(routed_circ, final_layout, connectivity=restricted_connectivity) + + +def test_star_error_multi_qubit(): + circuit = Circuit(3) + circuit.add(gates.TOFFOLI(0, 1, 2)) + transpiler = StarConnectivityRouter(middle_qubit=2) + with pytest.raises(ConnectivityError): + transpiled, hardware_qubits = transpiler(circuit) + + +@pytest.mark.parametrize("nqubits", [1, 2, 3, 4, 5]) +@pytest.mark.parametrize("middle_qubit", [0, 1, 2, 3, 4]) +@pytest.mark.parametrize("depth", [2, 10]) +@pytest.mark.parametrize("measurements", [True, False]) +def test_star_fix_connectivity(nqubits, depth, middle_qubit, measurements): + """Checks that the transpiled circuit can be executed and is equivalent to original.""" + original = generate_random_circuit(nqubits, depth, middle_qubit=middle_qubit) + if measurements: + original.add(gates.M(0)) + transpiler = StarConnectivityRouter(middle_qubit=middle_qubit) + transpiled, hardware_qubits = transpiler(original) + final_state = backend.execute_circuit(transpiled).state() + target_state = backend.execute_circuit(original).state() + hardware_qubits = list(hardware_qubits.values()) + target_state = _transpose_qubits(target_state, hardware_qubits) + np.testing.assert_allclose(final_state, target_state) + + +@pytest.mark.parametrize("nqubits", [2, 3, 4, 5]) +@pytest.mark.parametrize("middle_qubit", [0, 1, 2, 3, 4]) +@pytest.mark.parametrize("unitary_dim", [1, 2]) +@pytest.mark.parametrize("depth", [2, 10]) +def test_fix_connectivity_unitaries(nqubits, unitary_dim, depth, middle_qubit): + """Checks that the transpiled circuit can be executed and is equivalent to original + when using unitaries.""" + # find the number of qubits for hardware circuit + n_hardware_qubits = max(nqubits, middle_qubit + 1) + + original = Circuit(n_hardware_qubits) + pairs = list(itertools.combinations(range(n_hardware_qubits), unitary_dim)) + for _ in range(depth): + qubits = pairs[int(np.random.randint(len(pairs)))] + original.add( + gates.Unitary( + random_unitary(2**unitary_dim, backend=NumpyBackend()), *qubits + ) + ) + + transpiler = StarConnectivity(middle_qubit=middle_qubit) + transpiled, hardware_qubits = transpiler(original) + # check that execution results agree with original (using simulation) + backend = NumpyBackend() + final_state = backend.execute_circuit(transpiled).state() + target_state = backend.execute_circuit(original).state() + hardware_qubits = list(hardware_qubits.values()) + target_state = _transpose_qubits(target_state, hardware_qubits) + np.testing.assert_allclose(final_state, target_state) diff --git a/tests/test_transpiler_star_connectivity.py b/tests/test_transpiler_star_connectivity.py deleted file mode 100644 index 2330afd76c..0000000000 --- a/tests/test_transpiler_star_connectivity.py +++ /dev/null @@ -1,98 +0,0 @@ -import itertools - -import numpy as np -import pytest - -from qibo import gates -from qibo.backends import NumpyBackend -from qibo.models import Circuit -from qibo.quantum_info.random_ensembles import random_unitary -from qibo.transpiler._exceptions import ConnectivityError -from qibo.transpiler.pipeline import _transpose_qubits -from qibo.transpiler.star_connectivity import StarConnectivity - - -def generate_random_circuit(nqubits, depth, seed=None, middle_qubit=2): - """Generate random circuits one-qubit rotations and CZ gates.""" - # find the number of qubits for hardware circuit - if nqubits == 1: - hardware_qubits = 1 - else: - hardware_qubits = max(nqubits, middle_qubit + 1) - - pairs = list(itertools.combinations(range(hardware_qubits), 2)) - if seed is not None: # pragma: no cover - np.random.seed(seed) - - rotations = [gates.RX, gates.RY, gates.RZ] - circuit = Circuit(hardware_qubits) - for _ in range(depth): - for i in range(hardware_qubits): - # generate a random rotation - rotation = rotations[int(np.random.randint(0, 3))] - theta = 2 * np.pi * np.random.random() - circuit.add(rotation(i, theta=theta)) - # add CZ gates on random qubit pairs - for i in np.random.randint(0, len(pairs), len(pairs)): - q1, q2 = pairs[i] - circuit.add(gates.CZ(q1, q2)) - - return circuit - - -def test_error_multi_qubit(): - circuit = Circuit(3) - circuit.add(gates.TOFFOLI(0, 1, 2)) - transpiler = StarConnectivity(middle_qubit=2) - with pytest.raises(ConnectivityError): - transpiled, hardware_qubits = transpiler(circuit) - - -@pytest.mark.parametrize("nqubits", [1, 2, 3, 4, 5]) -@pytest.mark.parametrize("middle_qubit", [0, 1, 2, 3, 4]) -@pytest.mark.parametrize("depth", [2, 10]) -@pytest.mark.parametrize("measurements", [True, False]) -def test_fix_connectivity(nqubits, depth, middle_qubit, measurements): - """Checks that the transpiled circuit can be executed and is equivalent to original.""" - original = generate_random_circuit(nqubits, depth, middle_qubit=middle_qubit) - if measurements: - original.add(gates.M(0)) - transpiler = StarConnectivity(middle_qubit=middle_qubit) - transpiled, hardware_qubits = transpiler(original) - backend = NumpyBackend() - final_state = backend.execute_circuit(transpiled).state() - target_state = backend.execute_circuit(original).state() - hardware_qubits = list(hardware_qubits.values()) - target_state = _transpose_qubits(target_state, hardware_qubits) - np.testing.assert_allclose(final_state, target_state) - - -@pytest.mark.parametrize("nqubits", [2, 3, 4, 5]) -@pytest.mark.parametrize("middle_qubit", [0, 1, 2, 3, 4]) -@pytest.mark.parametrize("unitary_dim", [1, 2]) -@pytest.mark.parametrize("depth", [2, 10]) -def test_fix_connectivity_unitaries(nqubits, unitary_dim, depth, middle_qubit): - """Checks that the transpiled circuit can be executed and is equivalent to original - when using unitaries.""" - # find the number of qubits for hardware circuit - n_hardware_qubits = max(nqubits, middle_qubit + 1) - - original = Circuit(n_hardware_qubits) - pairs = list(itertools.combinations(range(n_hardware_qubits), unitary_dim)) - for _ in range(depth): - qubits = pairs[int(np.random.randint(len(pairs)))] - original.add( - gates.Unitary( - random_unitary(2**unitary_dim, backend=NumpyBackend()), *qubits - ) - ) - - transpiler = StarConnectivity(middle_qubit=middle_qubit) - transpiled, hardware_qubits = transpiler(original) - # check that execution results agree with original (using simulation) - backend = NumpyBackend() - final_state = backend.execute_circuit(transpiled).state() - target_state = backend.execute_circuit(original).state() - hardware_qubits = list(hardware_qubits.values()) - target_state = _transpose_qubits(target_state, hardware_qubits) - np.testing.assert_allclose(final_state, target_state) From 3177c277c52a008f9937ae1e7b3c41239ea8d6c6 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 17 Jan 2024 12:48:14 +0400 Subject: [PATCH 034/200] tests --- src/qibo/transpiler/__init__.py | 12 +++++++++--- src/qibo/transpiler/pipeline.py | 13 ++++++++----- src/qibo/transpiler/placer.py | 4 ++-- src/qibo/transpiler/router.py | 2 +- src/qibo/transpiler/test.py | 19 +++++++++++++++++++ 5 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 src/qibo/transpiler/test.py diff --git a/src/qibo/transpiler/__init__.py b/src/qibo/transpiler/__init__.py index 3ed3779d69..bfe576776c 100644 --- a/src/qibo/transpiler/__init__.py +++ b/src/qibo/transpiler/__init__.py @@ -1,6 +1,12 @@ from qibo.transpiler.optimizer import Preprocessing, Rearrange from qibo.transpiler.pipeline import Passes -from qibo.transpiler.placer import Custom, Random, ReverseTraversal, Subgraph, Trivial -from qibo.transpiler.router import Sabre, ShortestPaths -from qibo.transpiler.star_connectivity import StarConnectivity +from qibo.transpiler.placer import ( + Custom, + Random, + ReverseTraversal, + StarConnectivityPlacer, + Subgraph, + Trivial, +) +from qibo.transpiler.router import Sabre, ShortestPaths, StarConnectivityRouter from qibo.transpiler.unroller import NativeGates diff --git a/src/qibo/transpiler/pipeline.py b/src/qibo/transpiler/pipeline.py index d1bd6fdc6c..4452a90eca 100644 --- a/src/qibo/transpiler/pipeline.py +++ b/src/qibo/transpiler/pipeline.py @@ -10,9 +10,12 @@ from qibo.transpiler._exceptions import TranspilerPipelineError from qibo.transpiler.abstract import Optimizer, Placer, Router from qibo.transpiler.optimizer import Preprocessing -from qibo.transpiler.placer import Trivial, assert_placement -from qibo.transpiler.router import ConnectivityError, assert_connectivity -from qibo.transpiler.star_connectivity import StarConnectivity +from qibo.transpiler.placer import StarConnectivityPlacer, Trivial, assert_placement +from qibo.transpiler.router import ( + ConnectivityError, + StarConnectivityRouter, + assert_connectivity, +) from qibo.transpiler.unroller import ( DecompositionError, NativeGates, @@ -203,9 +206,9 @@ def default(self): # preprocessing default_passes.append(Preprocessing(connectivity=self.connectivity)) # default placer pass - default_passes.append(Trivial(connectivity=self.connectivity)) + default_passes.append(StarConnectivityPlacer(connectivity=self.connectivity)) # default router pass - default_passes.append(StarConnectivity()) + default_passes.append(StarConnectivityRouter(connectivity=self.connectivity)) # default unroller pass default_passes.append(Unroller(native_gates=self.native_gates)) diff --git a/src/qibo/transpiler/placer.py b/src/qibo/transpiler/placer.py index 1d1940f236..48160ec72b 100644 --- a/src/qibo/transpiler/placer.py +++ b/src/qibo/transpiler/placer.py @@ -135,10 +135,10 @@ def __call__(self, circuit: Circuit): break return dict( - zip(["q" + str(i) for i in range(circuit.nqubits)], range(circuit.nqubits)) + zip(["q" + str(i) for i in range(circuit.nqubits)], hardware_qubits) ) - def _find_connected_qubit(qubits, queue, hardware_qubits): + def _find_connected_qubit(self, qubits, queue, hardware_qubits): """ Finds which qubit should be mapped to hardware middle qubit by looking at the two-qubit gates that follow. diff --git a/src/qibo/transpiler/router.py b/src/qibo/transpiler/router.py index 617e234581..3f94ea1df1 100644 --- a/src/qibo/transpiler/router.py +++ b/src/qibo/transpiler/router.py @@ -62,7 +62,7 @@ def __init__(self, connectivity=None, middle_qubit: int = 2): self.middle_qubit = middle_qubit self.connectivity = connectivity - def __call__(self, circuit: Circuit, initial_layout=None): + def __call__(self, circuit: Circuit, initial_layout: dict): """Apply the transpiler transformation on a given circuit. Args: diff --git a/src/qibo/transpiler/test.py b/src/qibo/transpiler/test.py new file mode 100644 index 0000000000..63c08dca53 --- /dev/null +++ b/src/qibo/transpiler/test.py @@ -0,0 +1,19 @@ +from qibo import gates +from qibo.models import Circuit +from qibo.transpiler.placer import StarConnectivityPlacer +from qibo.transpiler.router import StarConnectivityRouter + +circ = Circuit(3) +circ.add(gates.H(0)) +circ.add(gates.H(1)) +circ.add(gates.CZ(0, 1)) +circ.add(gates.CZ(1, 2)) +circ.add(gates.CZ(0, 2)) + +placer = StarConnectivityPlacer(middle_qubit=2) +lay = placer(circ) +print(lay) +router = StarConnectivityRouter() +transpiled, final = router(circuit=circ, initial_layout=lay) +print(transpiled.draw()) +print(final) From 4a78a0338eed45abe5d263fd29c29c5c52c99043 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 17 Jan 2024 16:05:58 +0400 Subject: [PATCH 035/200] fixed tests --- src/qibo/transpiler/placer.py | 4 +- src/qibo/transpiler/router.py | 2 +- src/qibo/transpiler/test.py | 19 --------- tests/test_transpiler_placer.py | 12 ++++++ tests/test_transpiler_router.py | 71 ++++++++++++--------------------- 5 files changed, 40 insertions(+), 68 deletions(-) delete mode 100644 src/qibo/transpiler/test.py diff --git a/src/qibo/transpiler/placer.py b/src/qibo/transpiler/placer.py index 48160ec72b..1817c04df2 100644 --- a/src/qibo/transpiler/placer.py +++ b/src/qibo/transpiler/placer.py @@ -134,9 +134,7 @@ def __call__(self, circuit: Circuit): ) break - return dict( - zip(["q" + str(i) for i in range(circuit.nqubits)], hardware_qubits) - ) + return dict(zip(["q" + str(i) for i in range(nqubits)], hardware_qubits)) def _find_connected_qubit(self, qubits, queue, hardware_qubits): """ diff --git a/src/qibo/transpiler/router.py b/src/qibo/transpiler/router.py index 3f94ea1df1..558fc7f6ba 100644 --- a/src/qibo/transpiler/router.py +++ b/src/qibo/transpiler/router.py @@ -80,7 +80,7 @@ def __call__(self, circuit: Circuit, initial_layout: dict): middle_qubit = self.middle_qubit nqubits = max(circuit.nqubits, middle_qubit + 1) # new circuit object that will be compatible with hardware connectivity - new = circuit.__class__(nqubits) + new = Circuit(nqubits) # list to maps logical to hardware qubits hardware_qubits = list(initial_layout.values()) diff --git a/src/qibo/transpiler/test.py b/src/qibo/transpiler/test.py deleted file mode 100644 index 63c08dca53..0000000000 --- a/src/qibo/transpiler/test.py +++ /dev/null @@ -1,19 +0,0 @@ -from qibo import gates -from qibo.models import Circuit -from qibo.transpiler.placer import StarConnectivityPlacer -from qibo.transpiler.router import StarConnectivityRouter - -circ = Circuit(3) -circ.add(gates.H(0)) -circ.add(gates.H(1)) -circ.add(gates.CZ(0, 1)) -circ.add(gates.CZ(1, 2)) -circ.add(gates.CZ(0, 2)) - -placer = StarConnectivityPlacer(middle_qubit=2) -lay = placer(circ) -print(lay) -router = StarConnectivityRouter() -transpiled, final = router(circuit=circ, initial_layout=lay) -print(transpiled.draw()) -print(final) diff --git a/tests/test_transpiler_placer.py b/tests/test_transpiler_placer.py index 434037e7a4..f89e3671e1 100644 --- a/tests/test_transpiler_placer.py +++ b/tests/test_transpiler_placer.py @@ -9,6 +9,7 @@ Custom, Random, ReverseTraversal, + StarConnectivityPlacer, Subgraph, Trivial, _find_gates_qubits_pairs, @@ -321,3 +322,14 @@ def test_reverse_traversal_restricted(): assert_placement( circuit=circuit, layout=layout, connectivity=restricted_connectivity ) + + +def test_star_connectivity_placer(): + circ = Circuit(3) + circ.add(gates.CZ(0, 1)) + circ.add(gates.CZ(1, 2)) + circ.add(gates.CZ(0, 2)) + placer = StarConnectivityPlacer(middle_qubit=2) + layout = placer(circ) + assert_placement(circ, layout) + assert layout == {"q0": 0, "q1": 2, "q2": 1} diff --git a/tests/test_transpiler_router.py b/tests/test_transpiler_router.py index 420b1d3a81..bc58aa332f 100644 --- a/tests/test_transpiler_router.py +++ b/tests/test_transpiler_router.py @@ -27,11 +27,11 @@ ) -def star_connectivity(): +def star_connectivity(middle_qubit=2): Q = [i for i in range(5)] chip = nx.Graph() chip.add_nodes_from(Q) - graph_list = [(Q[i], Q[2]) for i in range(5) if i != 2] + graph_list = [(Q[i], Q[middle_qubit]) for i in range(5) if i != middle_qubit] chip.add_edges_from(graph_list) return chip @@ -351,53 +351,34 @@ def test_star_error_multi_qubit(): circuit.add(gates.TOFFOLI(0, 1, 2)) transpiler = StarConnectivityRouter(middle_qubit=2) with pytest.raises(ConnectivityError): - transpiled, hardware_qubits = transpiler(circuit) + transpiled, hardware_qubits = transpiler( + initial_layout={"q0": 0, "q1": 1, "q2": 2}, circuit=circuit + ) @pytest.mark.parametrize("nqubits", [1, 2, 3, 4, 5]) -@pytest.mark.parametrize("middle_qubit", [0, 1, 2, 3, 4]) +@pytest.mark.parametrize("middle_qubit", [3, 4]) @pytest.mark.parametrize("depth", [2, 10]) @pytest.mark.parametrize("measurements", [True, False]) -def test_star_fix_connectivity(nqubits, depth, middle_qubit, measurements): - """Checks that the transpiled circuit can be executed and is equivalent to original.""" - original = generate_random_circuit(nqubits, depth, middle_qubit=middle_qubit) +def test_star_router(nqubits, depth, middle_qubit, measurements): + circuit = generate_random_circuit(nqubits, depth) + connectivity = star_connectivity(middle_qubit) if measurements: - original.add(gates.M(0)) + circuit.add(gates.M(0)) transpiler = StarConnectivityRouter(middle_qubit=middle_qubit) - transpiled, hardware_qubits = transpiler(original) - final_state = backend.execute_circuit(transpiled).state() - target_state = backend.execute_circuit(original).state() - hardware_qubits = list(hardware_qubits.values()) - target_state = _transpose_qubits(target_state, hardware_qubits) - np.testing.assert_allclose(final_state, target_state) - - -@pytest.mark.parametrize("nqubits", [2, 3, 4, 5]) -@pytest.mark.parametrize("middle_qubit", [0, 1, 2, 3, 4]) -@pytest.mark.parametrize("unitary_dim", [1, 2]) -@pytest.mark.parametrize("depth", [2, 10]) -def test_fix_connectivity_unitaries(nqubits, unitary_dim, depth, middle_qubit): - """Checks that the transpiled circuit can be executed and is equivalent to original - when using unitaries.""" - # find the number of qubits for hardware circuit - n_hardware_qubits = max(nqubits, middle_qubit + 1) - - original = Circuit(n_hardware_qubits) - pairs = list(itertools.combinations(range(n_hardware_qubits), unitary_dim)) - for _ in range(depth): - qubits = pairs[int(np.random.randint(len(pairs)))] - original.add( - gates.Unitary( - random_unitary(2**unitary_dim, backend=NumpyBackend()), *qubits - ) - ) - - transpiler = StarConnectivity(middle_qubit=middle_qubit) - transpiled, hardware_qubits = transpiler(original) - # check that execution results agree with original (using simulation) - backend = NumpyBackend() - final_state = backend.execute_circuit(transpiled).state() - target_state = backend.execute_circuit(original).state() - hardware_qubits = list(hardware_qubits.values()) - target_state = _transpose_qubits(target_state, hardware_qubits) - np.testing.assert_allclose(final_state, target_state) + placer = StarConnectivityPlacer(middle_qubit=middle_qubit) + initial_layout = placer(circuit=circuit) + transpiled_circuit, final_qubit_map = transpiler( + circuit=circuit, initial_layout=initial_layout + ) + assert_connectivity(connectivity, transpiled_circuit) + assert_placement(transpiled_circuit, final_qubit_map) + matched_original = Circuit(max(circuit.nqubits, middle_qubit + 1)) + for gate in circuit.queue: + matched_original.add(gate) + assert_circuit_equivalence( + original_circuit=matched_original, + transpiled_circuit=transpiled_circuit, + final_map=final_qubit_map, + initial_map=initial_layout, + ) From 92a152cb690ae5708a964da022ff6e6a70982644 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Thu, 18 Jan 2024 14:41:05 +0400 Subject: [PATCH 036/200] fixed coverage --- tests/test_transpiler_placer.py | 8 ++++++++ tests/test_transpiler_router.py | 25 +++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/test_transpiler_placer.py b/tests/test_transpiler_placer.py index f89e3671e1..3df725a112 100644 --- a/tests/test_transpiler_placer.py +++ b/tests/test_transpiler_placer.py @@ -333,3 +333,11 @@ def test_star_connectivity_placer(): layout = placer(circ) assert_placement(circ, layout) assert layout == {"q0": 0, "q1": 2, "q2": 1} + + +def test_star_connectivity_placer_error(): + circ = Circuit(3) + circ.add(gates.TOFFOLI(0, 1, 2)) + placer = StarConnectivityPlacer(middle_qubit=2) + with pytest.raises(PlacementError): + layout = placer(circ) diff --git a/tests/test_transpiler_router.py b/tests/test_transpiler_router.py index bc58aa332f..2cf2364fe9 100644 --- a/tests/test_transpiler_router.py +++ b/tests/test_transpiler_router.py @@ -1,9 +1,13 @@ +import itertools + import networkx as nx import numpy as np import pytest from qibo import gates +from qibo.backends import NumpyBackend from qibo.models import Circuit +from qibo.quantum_info.random_ensembles import random_unitary from qibo.transpiler._exceptions import ConnectivityError from qibo.transpiler.optimizer import Preprocessing from qibo.transpiler.pipeline import ( @@ -356,13 +360,26 @@ def test_star_error_multi_qubit(): ) -@pytest.mark.parametrize("nqubits", [1, 2, 3, 4, 5]) -@pytest.mark.parametrize("middle_qubit", [3, 4]) +@pytest.mark.parametrize("nqubits", [1, 3, 5]) +@pytest.mark.parametrize("middle_qubit", [0, 2, 4]) @pytest.mark.parametrize("depth", [2, 10]) @pytest.mark.parametrize("measurements", [True, False]) -def test_star_router(nqubits, depth, middle_qubit, measurements): - circuit = generate_random_circuit(nqubits, depth) +@pytest.mark.parametrize("unitaries", [True, False]) +def test_star_router(nqubits, depth, middle_qubit, measurements, unitaries): + unitary_dim = min(2, nqubits) connectivity = star_connectivity(middle_qubit) + if unitaries: + circuit = Circuit(nqubits) + pairs = list(itertools.combinations(range(nqubits), unitary_dim)) + for _ in range(depth): + qubits = pairs[int(np.random.randint(len(pairs)))] + circuit.add( + gates.Unitary( + random_unitary(2**unitary_dim, backend=NumpyBackend()), *qubits + ) + ) + else: + circuit = generate_random_circuit(nqubits, depth) if measurements: circuit.add(gates.M(0)) transpiler = StarConnectivityRouter(middle_qubit=middle_qubit) From c6e323a25874cae24493dcb64ad66332c2602eed Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Fri, 19 Jan 2024 13:35:27 +0400 Subject: [PATCH 037/200] fix coverage --- tests/test_transpiler_placer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_transpiler_placer.py b/tests/test_transpiler_placer.py index 3df725a112..801304bc31 100644 --- a/tests/test_transpiler_placer.py +++ b/tests/test_transpiler_placer.py @@ -335,8 +335,11 @@ def test_star_connectivity_placer(): assert layout == {"q0": 0, "q1": 2, "q2": 1} -def test_star_connectivity_placer_error(): +@pytest.mark.parametrize("first", [True, False]) +def test_star_connectivity_placer_error(first): circ = Circuit(3) + if first: + circ.add(gates.CZ(0, 1)) circ.add(gates.TOFFOLI(0, 1, 2)) placer = StarConnectivityPlacer(middle_qubit=2) with pytest.raises(PlacementError): From e10c04383df081002e9262c21d16cd54253aa610 Mon Sep 17 00:00:00 2001 From: Rahul Arvind Date: Tue, 23 Jan 2024 15:48:25 +0800 Subject: [PATCH 038/200] Testing using capsys --- pyproject.toml | 8 +------- tests/test_models_qcnn.py | 8 +++++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1209f86ad7..ef72a489af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,10 +95,4 @@ output-format = "colorized" [tool.pytest.ini_options] testpaths = ['tests/'] filterwarnings = ['ignore::RuntimeWarning'] -addopts = [ - '--cov=qibo', - '--cov-append', - '--cov-report=xml', - '--cov-report=html', - '--durations=60', -] + diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index eb31d246ee..43e9718dfa 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -4,6 +4,7 @@ import pytest from qibo import gates +from qibo import get_backend from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN @@ -11,8 +12,13 @@ angles0 = [i * math.pi / num_angles for i in range(num_angles)] -def test_classifier_circuit2(backend): +def test_classifier_circuit2(backend, capsys, mad): """ """ + + with capsys.disabled(): + backender = get_backend() + print(str(backender)) + nqubits = 2 nlayers = int(nqubits / 2) init_state = np.ones(2**nqubits) / np.sqrt(2**nqubits) # From de0d253f24ae3c20d9a155b0da913753cbb6240e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 07:50:19 +0000 Subject: [PATCH 039/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyproject.toml | 1 - tests/test_models_qcnn.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ef72a489af..61641cc190 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,4 +95,3 @@ output-format = "colorized" [tool.pytest.ini_options] testpaths = ['tests/'] filterwarnings = ['ignore::RuntimeWarning'] - diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 43e9718dfa..2c58653193 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,8 +3,7 @@ import numpy as np import pytest -from qibo import gates -from qibo import get_backend +from qibo import gates, get_backend from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN From 27eefac7de76abb400fe0879a0c5bbdf9b08d6dc Mon Sep 17 00:00:00 2001 From: Rahul Arvind Date: Tue, 23 Jan 2024 16:02:48 +0800 Subject: [PATCH 040/200] Conftest test --- tests/test_models_qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 43e9718dfa..bfb37084ea 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -12,7 +12,7 @@ angles0 = [i * math.pi / num_angles for i in range(num_angles)] -def test_classifier_circuit2(backend, capsys, mad): +def test_classifier_circuit2(backend, capsys): """ """ with capsys.disabled(): From d578f96a34fffe47ce3eaf806266ee25d2e036d8 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 23 Jan 2024 16:47:34 +0800 Subject: [PATCH 041/200] Update pyproject.toml --- pyproject.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 61641cc190..1209f86ad7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,3 +95,10 @@ output-format = "colorized" [tool.pytest.ini_options] testpaths = ['tests/'] filterwarnings = ['ignore::RuntimeWarning'] +addopts = [ + '--cov=qibo', + '--cov-append', + '--cov-report=xml', + '--cov-report=html', + '--durations=60', +] From 4bad7cc199c7864a1b789a0885b1ee1b08872838 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 23 Jan 2024 18:17:02 +0400 Subject: [PATCH 042/200] refactoring `random_statevector` --- src/qibo/quantum_info/random_ensembles.py | 24 +++++------------------ 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 9ef63a653d..d831da5c84 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -415,7 +415,7 @@ def random_quantum_channel( return super_op -def random_statevector(dims: int, haar: bool = False, seed=None, backend=None): +def random_statevector(dims: int, seed=None, backend=None): """Creates a random statevector :math:`\\ket{\\psi}`. .. math:: @@ -427,10 +427,6 @@ def random_statevector(dims: int, haar: bool = False, seed=None, backend=None): Args: dims (int): dimension of the matrix. - haar (bool, optional): if ``True``, statevector is created by sampling a - Haar random unitary :math:`U_{\\text{haar}}` and acting with it on a - random computational basis state :math:`\\ket{k}`, i.e. - :math:`\\ket{\\psi} = U_{\\text{haar}} \\ket{k}`. Defaults to ``False``. seed (int or :class:`numpy.random.Generator`, optional): Either a generator of random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. @@ -445,9 +441,6 @@ def random_statevector(dims: int, haar: bool = False, seed=None, backend=None): if dims <= 0: raise_error(ValueError, "dim must be of type int and >= 1") - if not isinstance(haar, bool): - raise_error(TypeError, f"haar must be type bool, but it is type {type(haar)}.") - if ( seed is not None and not isinstance(seed, int) @@ -464,18 +457,11 @@ def random_statevector(dims: int, haar: bool = False, seed=None, backend=None): np.random.default_rng(seed) if seed is None or isinstance(seed, int) else seed ) - if not haar: - # sample real and imag parts of complex amplitude in [-1, 1] - state = 1j * (2 * local_state.random(dims) - 1) - state += 2 * local_state.random(dims) - 1 - state /= np.linalg.norm(state) - state = backend.cast(state, dtype=state.dtype) - else: - # select a random column of a haar random unitary - k = local_state.integers(low=0, high=dims) - state = random_unitary(dims, measure="haar", seed=seed, backend=backend)[:, k] + state = local_state.standard_normal(dims).astype(complex) + state += 1.0j * local_state.standard_normal(dims) + state /= np.linalg.norm(state) - return state + return backend.cast(state, dtype=state.dtype) def random_density_matrix( From 4b64d1956efb36707ec04f3fddbb5baeac5cfa1a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 23 Jan 2024 18:19:13 +0400 Subject: [PATCH 043/200] adjust `random_density_matrix` --- src/qibo/quantum_info/random_ensembles.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index d831da5c84..495081c1c9 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -567,7 +567,7 @@ def random_density_matrix( if pure: state = random_statevector(dims, seed=seed, backend=backend) - state = np.outer(state, np.transpose(np.conj(state))) + state = np.outer(state, np.conj(state)) else: if metric in ["hilbert-schmidt", "ginibre"]: state = random_gaussian_matrix( @@ -583,7 +583,7 @@ def random_density_matrix( state, random_gaussian_matrix(dims, rank, seed=seed, backend=backend) ) state = np.dot(state, np.transpose(np.conj(state))) - state = state / np.trace(state) + state /= np.trace(state) state = backend.cast(state, dtype=state.dtype) From f9bb2a7e6fa00548d77512b5709f129bcd3f12d0 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 23 Jan 2024 18:20:12 +0400 Subject: [PATCH 044/200] adjust tests --- tests/test_quantum_info_random.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index 01000ab822..0c46afe4ab 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -228,25 +228,21 @@ def test_random_quantum_channel(backend, representation, measure, rank, order): ) -@pytest.mark.parametrize("haar", [False, True]) @pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)]) -def test_random_statevector(backend, haar, seed): +def test_random_statevector(backend, seed): with pytest.raises(TypeError): dims = "10" random_statevector(dims, backend=backend) with pytest.raises(ValueError): dims = 0 random_statevector(dims, backend=backend) - with pytest.raises(TypeError): - dims = 2 - random_statevector(dims, haar=1, backend=backend) with pytest.raises(TypeError): dims = 2 random_statevector(dims, seed=0.1, backend=backend) # tests if random statevector is a pure state dims = 4 - state = random_statevector(dims, haar=haar, seed=seed, backend=backend) + state = random_statevector(dims, seed=seed, backend=backend) backend.assert_allclose(purity(state) <= 1.0 + PRECISION_TOL, True) backend.assert_allclose(purity(state) >= 1.0 - PRECISION_TOL, True) From 9c761843944d0e6c1d67a897aea29db162ae6bc0 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 23 Jan 2024 18:22:19 +0400 Subject: [PATCH 045/200] fix `haar_integral` --- src/qibo/quantum_info/utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/qibo/quantum_info/utils.py b/src/qibo/quantum_info/utils.py index eb5a447d8d..991b23172a 100644 --- a/src/qibo/quantum_info/utils.py +++ b/src/qibo/quantum_info/utils.py @@ -339,9 +339,7 @@ def haar_integral( rand_unit_density, dtype=rand_unit_density.dtype ) for _ in range(samples): - haar_state = np.reshape( - random_statevector(dim, haar=True, backend=backend), (-1, 1) - ) + haar_state = np.reshape(random_statevector(dim, backend=backend), (-1, 1)) rho = haar_state @ np.conj(np.transpose(haar_state)) From 90252c54aba927e675277f74e1a1e2882e6baf20 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 24 Jan 2024 12:33:12 +0400 Subject: [PATCH 046/200] find connected qubit improved --- src/qibo/transpiler/placer.py | 30 ++++++------------------------ src/qibo/transpiler/router.py | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/qibo/transpiler/placer.py b/src/qibo/transpiler/placer.py index 1817c04df2..c6b1f8f5fb 100644 --- a/src/qibo/transpiler/placer.py +++ b/src/qibo/transpiler/placer.py @@ -8,6 +8,7 @@ from qibo.models import Circuit from qibo.transpiler._exceptions import PlacementError from qibo.transpiler.abstract import Placer, Router +from qibo.transpiler.router import _find_connected_qubit def assert_placement( @@ -125,8 +126,11 @@ def __call__(self, circuit: Circuit): ) if len(gate.qubits) == 2: if self.middle_qubit not in gate.qubits: - new_middle = self._find_connected_qubit( - gate.qubits, circuit.queue[i + 1 :], hardware_qubits + new_middle = _find_connected_qubit( + gate.qubits, + circuit.queue[i + 1 :], + hardware_qubits, + error=PlacementError, ) hardware_qubits[self.middle_qubit], hardware_qubits[new_middle] = ( new_middle, @@ -136,28 +140,6 @@ def __call__(self, circuit: Circuit): return dict(zip(["q" + str(i) for i in range(nqubits)], hardware_qubits)) - def _find_connected_qubit(self, qubits, queue, hardware_qubits): - """ - Finds which qubit should be mapped to hardware middle qubit - by looking at the two-qubit gates that follow. - """ - possible_qubits = set(qubits) - for next_gate in queue: - if len(next_gate.qubits) > 2: - raise_error( - PlacementError, - "Gates targeting more than 2 qubits are not supported", - ) - if len(next_gate.qubits) == 2: - possible_qubits &= {hardware_qubits.index(q) for q in next_gate.qubits} - if not possible_qubits: - # freedom of choice - return qubits[0] - elif len(possible_qubits) == 1: - return possible_qubits.pop() - # freedom of choice - return qubits[0] - class Trivial(Placer): """Place qubits according to the following notation: diff --git a/src/qibo/transpiler/router.py b/src/qibo/transpiler/router.py index 558fc7f6ba..82f6ac1b7e 100644 --- a/src/qibo/transpiler/router.py +++ b/src/qibo/transpiler/router.py @@ -101,7 +101,10 @@ def __call__(self, circuit: Circuit, initial_layout: dict): elif len(qubits) == 2 and middle_qubit not in qubits: # find which qubit should be moved new_middle = _find_connected_qubit( - qubits, circuit.queue[i + 1 :], hardware_qubits + qubits, + circuit.queue[i + 1 :], + hardware_qubits, + error=ConnectivityError, ) # update hardware qubits according to the swap hardware_qubits[middle_qubit], hardware_qubits[new_middle] = ( @@ -123,22 +126,26 @@ def __call__(self, circuit: Circuit, initial_layout: dict): return new, dict(zip(hardware_qubits_keys, hardware_qubits)) -def _find_connected_qubit(qubits, queue, hardware_qubits): - """Helper method for :meth:`qibo.transpiler.StarConnectivity`. +def _find_connected_qubit(qubits, queue, hardware_qubits, error): + """Helper method for :meth:`qibo.transpiler.router.StarConnectivityRouter` + and :meth:`qibo.transpiler.router.StarConnectivityPlacer`. Finds which qubit should be mapped to hardware middle qubit by looking at the two-qubit gates that follow. """ possible_qubits = set(qubits) for next_gate in queue: + if len(next_gate.qubits) > 2: + raise_error( + error, + "Gates targeting more than 2 qubits are not supported", + ) if len(next_gate.qubits) == 2: possible_qubits &= {hardware_qubits.index(q) for q in next_gate.qubits} if not possible_qubits: - # freedom of choice return qubits[0] elif len(possible_qubits) == 1: return possible_qubits.pop() - # freedom of choice return qubits[0] From f31d5c508d3e1ff7866ad8aa30e90605de9ed6e1 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 27 Jan 2024 09:46:41 +0400 Subject: [PATCH 047/200] test new random generation --- src/qibo/quantum_info/random_ensembles.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 495081c1c9..3309bdc5b0 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -454,7 +454,9 @@ def random_statevector(dims: int, seed=None, backend=None): backend = GlobalBackend() local_state = ( - np.random.default_rng(seed) if seed is None or isinstance(seed, int) else seed + backend.np.random.default_rng(seed) + if seed is None or isinstance(seed, int) + else seed ) state = local_state.standard_normal(dims).astype(complex) From 380a80b30f4e311f8953d613f088f51298bc1ab7 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 27 Jan 2024 09:51:43 +0400 Subject: [PATCH 048/200] revamp seed --- src/qibo/quantum_info/random_ensembles.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 3309bdc5b0..c2fac74687 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -453,11 +453,13 @@ def random_statevector(dims: int, seed=None, backend=None): if backend is None: # pragma: no cover backend = GlobalBackend() - local_state = ( - backend.np.random.default_rng(seed) - if seed is None or isinstance(seed, int) - else seed - ) + if seed is None or isinstance(seed, int): + if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + local_state = backend.np.random.default_rng(seed) + else: + local_state = np.random.default_rng(seed) + else: + local_state = seed state = local_state.standard_normal(dims).astype(complex) state += 1.0j * local_state.standard_normal(dims) From 514e4143fe30352632353c2ea296ac97184f6b89 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 08:39:13 +0400 Subject: [PATCH 049/200] fix coverage --- src/qibo/quantum_info/random_ensembles.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index c2fac74687..abe58141b4 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -454,7 +454,10 @@ def random_statevector(dims: int, seed=None, backend=None): backend = GlobalBackend() if seed is None or isinstance(seed, int): - if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + if backend.__class__.__name__ in [ + "CupyBackend", + "CuQuantumBackend", + ]: # pragma: no cover local_state = backend.np.random.default_rng(seed) else: local_state = np.random.default_rng(seed) From fef4cb5bf232c161184123bf6a6e8332d8e51661 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 08:52:03 +0400 Subject: [PATCH 050/200] create `entanglement.py` --- src/qibo/quantum_info/entanglement.py | 298 ++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 src/qibo/quantum_info/entanglement.py diff --git a/src/qibo/quantum_info/entanglement.py b/src/qibo/quantum_info/entanglement.py new file mode 100644 index 0000000000..7f006655d6 --- /dev/null +++ b/src/qibo/quantum_info/entanglement.py @@ -0,0 +1,298 @@ +"""Submodules with entanglement measures.""" + +import numpy as np + +from qibo.backends import GlobalBackend +from qibo.config import PRECISION_TOL, raise_error +from qibo.quantum_info.metrics import fidelity, purity + + +def concurrence(state, bipartition, check_purity: bool = True, backend=None): + """Calculates concurrence of a pure bipartite quantum state + :math:`\\rho \\in \\mathcal{H}_{A} \\otimes \\mathcal{H}_{B}` as + + .. math:: + C(\\rho) = \\sqrt{2 \\, (\\text{tr}^{2}(\\rho) - \\text{tr}(\\rho_{A}^{2}))} \\, , + + where :math:`\\rho_{A} = \\text{tr}_{B}(\\rho)` is the reduced density operator + obtained by tracing out the qubits in the ``bipartition`` :math:`B`. + + Args: + state (ndarray): statevector or density matrix. + bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. + check_purity (bool, optional): if ``True``, checks if ``state`` is pure. If ``False``, + it assumes ``state`` is pure . Defaults to ``True``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + Defaults to ``None``. + + Returns: + float: Concurrence of :math:`\\rho`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if ( + (len(state.shape) not in [1, 2]) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + if isinstance(check_purity, bool) is False: + raise_error( + TypeError, + f"check_purity must be type bool, but it is type {type(check_purity)}.", + ) + + nqubits = int(np.log2(state.shape[0])) + + if check_purity is True: + purity_total_system = purity(state) + + mixed = bool(abs(purity_total_system - 1.0) > PRECISION_TOL) + if mixed is True: + raise_error( + NotImplementedError, + "concurrence only implemented for pure quantum states.", + ) + + reduced_density_matrix = ( + backend.partial_trace(state, bipartition, nqubits) + if len(state.shape) == 1 + else backend.partial_trace_density_matrix(state, bipartition, nqubits) + ) + + purity_reduced = purity(reduced_density_matrix) + if purity_reduced - 1.0 > 0.0: + purity_reduced = round(purity_reduced, 7) + + concur = np.sqrt(2 * (1 - purity_reduced)) + + return concur + + +def entanglement_of_formation( + state, bipartition, base: float = 2, check_purity: bool = True, backend=None +): + """Calculates the entanglement of formation :math:`E_{f}` of a pure bipartite + quantum state :math:`\\rho`, which is given by + + .. math:: + E_{f} = H([1 - x, x]) \\, , + + where + + .. math:: + x = \\frac{1 + \\sqrt{1 - C^{2}(\\rho)}}{2} \\, , + + :math:`C(\\rho)` is the :func:`qibo.quantum_info.concurrence` of :math:`\\rho`, + and :math:`H` is the :func:`qibo.quantum_info.shannon_entropy`. + + Args: + state (ndarray): statevector or density matrix. + bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. + base (float): the base of the log in :func:`qibo.quantum_info.shannon_entropy`. + Defaults to :math:`2`. + check_purity (bool, optional): if ``True``, checks if ``state`` is pure. If ``False``, + it assumes ``state`` is pure . Default: ``True``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + Defaults to ``None``. + + + Returns: + float: entanglement of formation of state :math:`\\rho`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + from qibo.quantum_info.utils import shannon_entropy # pylint: disable=C0415 + + concur = concurrence( + state, bipartition=bipartition, check_purity=check_purity, backend=backend + ) + concur = (1 + np.sqrt(1 - concur**2)) / 2 + probabilities = [1 - concur, concur] + + ent_of_form = shannon_entropy(probabilities, base=base, backend=backend) + + return ent_of_form + + +def entanglement_fidelity( + channel, nqubits: int, state=None, check_hermitian: bool = False, backend=None +): + """Entanglement fidelity :math:`F_{\\mathcal{E}}` of a ``channel`` :math:`\\mathcal{E}` + on ``state`` :math:`\\rho` is given by + + .. math:: + F_{\\mathcal{E}}(\\rho) = F(\\rho_{f}, \\rho) + + where :math:`F` is the :func:`qibo.quantum_info.fidelity` function for states, + and :math:`\\rho_{f} = \\mathcal{E}_{A} \\otimes I_{B}(\\rho)` + is the state after the channel :math:`\\mathcal{E}` was applied to + partition :math:`A`. + + Args: + channel (:class:`qibo.gates.channels.Channel`): quantum channel + acting on partition :math:`A`. + nqubits (int): total number of qubits in ``state``. + state (ndarray, optional): statevector or density matrix to be evolved + by ``channel``. If ``None``, defaults to the maximally entangled state + :math:`\\frac{1}{2^{n}} \\, \\sum_{k} \\, \\ket{k}\\ket{k}`, where + :math:`n` is ``nqubits``. Defaults to ``None``. + check_hermitian (bool, optional): if ``True``, checks if the final state + :math:`\\rho_{f}` is Hermitian. If ``False``, it assumes it is Hermitian. + Defaults to ``False``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + Defaults to ``None``. + + Returns: + float: Entanglement fidelity :math:`F_{\\mathcal{E}}`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if isinstance(nqubits, int) is False: + raise_error( + TypeError, f"nqubits must be type int, but it is type {type(nqubits)}." + ) + + if nqubits <= 0: + raise_error( + ValueError, f"nqubits must be a positive integer, but it is {nqubits}." + ) + + if state is not None and ( + (len(state.shape) not in [1, 2]) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + if isinstance(check_hermitian, bool) is False: + raise_error( + TypeError, + f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", + ) + + if state is None: + state = backend.plus_density_matrix(nqubits) + + # necessary because this function do support repeated execution, + # so it has to default to density matrices + if len(state.shape) == 1: + state = np.outer(state, np.conj(state)) + + state_final = backend.apply_channel_density_matrix(channel, state, nqubits) + + entang_fidelity = fidelity( + state_final, state, check_hermitian=check_hermitian, backend=backend + ) + + return entang_fidelity + + +def meyer_wallach_entanglement(circuit, backend=None): + """Computes the Meyer-Wallach entanglement Q of the `circuit`, + + .. math:: + Q(\\theta) = 1 - \\frac{1}{N} \\, \\sum_{k} \\, + \\text{tr}\\left(\\rho_{k^{2}}(\\theta)\\right) \\, . + + Args: + circuit (:class:`qibo.models.Circuit`): Parametrized circuit. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + Defaults to ``None``. + + Returns: + float: Meyer-Wallach entanglement. + """ + + if backend is None: # pragma: no cover + backend = GlobalBackend() + + circuit.density_matrix = True + nqubits = circuit.nqubits + + rho = backend.execute_circuit(circuit).state() + + ent = 0 + for j in range(nqubits): + trace_q = list(range(nqubits)) + trace_q.pop(j) + + rho_r = backend.partial_trace_density_matrix(rho, trace_q, nqubits) + + trace = purity(rho_r) + + ent += trace + + entanglement = 1 - ent / nqubits + + return entanglement + + +def entangling_capability(circuit, samples: int, seed=None, backend=None): + """Returns the entangling capability :math:`\\text{Ent}` of a parametrized + circuit, which is average Meyer-Wallach entanglement Q of the circuit, i.e. + + .. math:: + \\text{Ent} = \\frac{2}{S}\\sum_{k}Q_k \\, , + + where :math:`S` is the number of samples. + + Args: + circuit (:class:`qibo.models.Circuit`): Parametrized circuit. + samples (int): number of samples to estimate the integral. + seed (int or :class:`numpy.random.Generator`, optional): Either a generator of random + numbers or a fixed seed to initialize a generator. If ``None``, initializes + a generator with a random seed. Default: ``None``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + Defaults to ``None``. + + Returns: + float: Entangling capability. + """ + + if isinstance(samples, int) is False: + raise_error( + TypeError, f"samples must be type int, but it is type {type(samples)}." + ) + + if ( + seed is not None + and not isinstance(seed, int) + and not isinstance(seed, np.random.Generator) + ): + raise_error( + TypeError, "seed must be either type int or numpy.random.Generator." + ) + + if backend is None: # pragma: no cover + backend = GlobalBackend() + + local_state = ( + np.random.default_rng(seed) if seed is None or isinstance(seed, int) else seed + ) + + res = [] + for _ in range(samples): + params = local_state.uniform(-np.pi, np.pi, circuit.trainable_gates.nparams) + circuit.set_parameters(params) + entanglement = meyer_wallach_entanglement(circuit, backend=backend) + res.append(entanglement) + + capability = 2 * np.real(np.sum(res)) / samples + + return capability From e9bef500baae1a2dd84341fe15d0020d2f99e623 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 08:52:14 +0400 Subject: [PATCH 051/200] create `entropies.py` --- src/qibo/quantum_info/entropies.py | 158 +++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/qibo/quantum_info/entropies.py diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py new file mode 100644 index 0000000000..82e557772c --- /dev/null +++ b/src/qibo/quantum_info/entropies.py @@ -0,0 +1,158 @@ +"""Submodule with entropy measures.""" + +import numpy as np + +from qibo.backends import GlobalBackend +from qibo.config import raise_error +from qibo.quantum_info.metrics import _check_hermitian_or_not_gpu, purity + + +def entropy( + state, + base: float = 2, + check_hermitian: bool = False, + return_spectrum: bool = False, + backend=None, +): + """The von-Neumann entropy :math:`S(\\rho)` of a quantum ``state`` :math:`\\rho`, which + is given by + + .. math:: + S(\\rho) = - \\text{tr}\\left[\\rho \\, \\log(\\rho)\\right] + + Args: + state (ndarray): statevector or density matrix. + base (float, optional): the base of the log. Defaults to :math:`2`. + check_hermitian (bool, optional): if ``True``, checks if ``state`` is Hermitian. + If ``False``, it assumes ``state`` is Hermitian . + Defaults to ``False``. + return_spectrum: if ``True``, returns ``entropy`` and + :math:`-\\log_{\\textup{b}}(\\textup{eigenvalues})`, where :math:`b` is ``base``. + If ``False``, returns only ``entropy``. Default is ``False``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: The von-Neumann entropy :math:`S` of ``state`` :math:`\\rho`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if ( + (len(state.shape) >= 3) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + if base <= 0.0: + raise_error(ValueError, "log base must be non-negative.") + + if isinstance(check_hermitian, bool) is False: + raise_error( + TypeError, + f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", + ) + + if purity(state) == 1.0: + if return_spectrum: + return 0.0, backend.cast([1.0], dtype=float) + + return 0.0 + + if check_hermitian is False or _check_hermitian_or_not_gpu(state, backend=backend): + eigenvalues = np.linalg.eigvalsh(state) + else: + eigenvalues = np.linalg.eigvals(state) + + if base == 2: + log_prob = np.where(eigenvalues > 0, np.log2(eigenvalues), 0.0) + elif base == 10: + log_prob = np.where(eigenvalues > 0, np.log10(eigenvalues), 0.0) + elif base == np.e: + log_prob = np.where(eigenvalues > 0, np.log(eigenvalues), 0.0) + else: + log_prob = np.where(eigenvalues > 0, np.log(eigenvalues) / np.log(base), 0.0) + + ent = -np.sum(eigenvalues * log_prob) + # absolute value if entropy == 0.0 to avoid returning -0.0 + ent = np.abs(ent) if ent == 0.0 else ent + + ent = float(ent) + + if return_spectrum: + log_prob = backend.cast(log_prob, dtype=log_prob.dtype) + return ent, -log_prob + + return ent + + +def entanglement_entropy( + state, + bipartition, + base: float = 2, + check_hermitian: bool = False, + return_spectrum: bool = False, + backend=None, +): + """Calculates the entanglement entropy :math:`S` of bipartition :math:`A` + of ``state`` :math:`\\rho`. This is given by + + .. math:: + S(\\rho_{A}) = -\\text{tr}(\\rho_{A} \\, \\log(\\rho_{A})) \\, , + + where :math:`\\rho_{A} = \\text{tr}_{B}(\\rho)` is the reduced density matrix calculated + by tracing out the ``bipartition`` :math:`B`. + + Args: + state (ndarray): statevector or density matrix. + bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. + base (float, optional): the base of the log. Defaults to :math: `2`. + check_hermitian (bool, optional): if ``True``, checks if :math:`\\rho_{A}` is Hermitian. + If ``False``, it assumes ``state`` is Hermitian . Default: ``False``. + return_spectrum: if ``True``, returns ``entropy`` and eigenvalues of ``state``. + If ``False``, returns only ``entropy``. Default is ``False``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Entanglement entropy :math:`S` of ``state`` :math:`\\rho`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if base <= 0.0: + raise_error(ValueError, "log base must be non-negative.") + + if ( + (len(state.shape) not in [1, 2]) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + nqubits = int(np.log2(state.shape[0])) + + reduced_density_matrix = ( + backend.partial_trace(state, bipartition, nqubits) + if len(state.shape) == 1 + else backend.partial_trace_density_matrix(state, bipartition, nqubits) + ) + + entropy_entanglement = entropy( + reduced_density_matrix, + base=base, + check_hermitian=check_hermitian, + return_spectrum=return_spectrum, + backend=backend, + ) + + return entropy_entanglement From f989054996c2f09f797c2e12ce85b418dcf1b126 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 08:52:32 +0400 Subject: [PATCH 052/200] move functions to `entanglement.py` and `entropies.py` --- src/qibo/quantum_info/metrics.py | 442 ------------------------------- 1 file changed, 442 deletions(-) diff --git a/src/qibo/quantum_info/metrics.py b/src/qibo/quantum_info/metrics.py index eb29f1b486..f11225f9d9 100644 --- a/src/qibo/quantum_info/metrics.py +++ b/src/qibo/quantum_info/metrics.py @@ -57,273 +57,6 @@ def impurity(state): return 1 - purity(state) -def concurrence(state, bipartition, check_purity: bool = True, backend=None): - """Calculates concurrence of a pure bipartite quantum state - :math:`\\rho \\in \\mathcal{H}_{A} \\otimes \\mathcal{H}_{B}` as - - .. math:: - C(\\rho) = \\sqrt{2 \\, (\\text{tr}^{2}(\\rho) - \\text{tr}(\\rho_{A}^{2}))} \\, , - - where :math:`\\rho_{A} = \\text{tr}_{B}(\\rho)` is the reduced density operator - obtained by tracing out the qubits in the ``bipartition`` :math:`B`. - - Args: - state (ndarray): statevector or density matrix. - bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. - check_purity (bool, optional): if ``True``, checks if ``state`` is pure. If ``False``, - it assumes ``state`` is pure . Defaults to ``True``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. - Defaults to ``None``. - - Returns: - float: Concurrence of :math:`\\rho`. - """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - - if ( - (len(state.shape) not in [1, 2]) - or (len(state) == 0) - or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) - ): - raise_error( - TypeError, - f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", - ) - - if isinstance(check_purity, bool) is False: - raise_error( - TypeError, - f"check_purity must be type bool, but it is type {type(check_purity)}.", - ) - - nqubits = int(np.log2(state.shape[0])) - - if check_purity is True: - purity_total_system = purity(state) - - mixed = bool(abs(purity_total_system - 1.0) > PRECISION_TOL) - if mixed is True: - raise_error( - NotImplementedError, - "concurrence only implemented for pure quantum states.", - ) - - reduced_density_matrix = ( - backend.partial_trace(state, bipartition, nqubits) - if len(state.shape) == 1 - else backend.partial_trace_density_matrix(state, bipartition, nqubits) - ) - - purity_reduced = purity(reduced_density_matrix) - if purity_reduced - 1.0 > 0.0: - purity_reduced = round(purity_reduced, 7) - - concur = np.sqrt(2 * (1 - purity_reduced)) - - return concur - - -def entanglement_of_formation( - state, bipartition, base: float = 2, check_purity: bool = True, backend=None -): - """Calculates the entanglement of formation :math:`E_{f}` of a pure bipartite - quantum state :math:`\\rho`, which is given by - - .. math:: - E_{f} = H([1 - x, x]) \\, , - - where - - .. math:: - x = \\frac{1 + \\sqrt{1 - C^{2}(\\rho)}}{2} \\, , - - :math:`C(\\rho)` is the :func:`qibo.quantum_info.concurrence` of :math:`\\rho`, - and :math:`H` is the :func:`qibo.quantum_info.shannon_entropy`. - - Args: - state (ndarray): statevector or density matrix. - bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. - base (float): the base of the log in :func:`qibo.quantum_info.shannon_entropy`. - Defaults to :math:`2`. - check_purity (bool, optional): if ``True``, checks if ``state`` is pure. If ``False``, - it assumes ``state`` is pure . Default: ``True``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. - Defaults to ``None``. - - - Returns: - float: entanglement of formation of state :math:`\\rho`. - """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - - from qibo.quantum_info.utils import shannon_entropy # pylint: disable=C0415 - - concur = concurrence( - state, bipartition=bipartition, check_purity=check_purity, backend=backend - ) - concur = (1 + np.sqrt(1 - concur**2)) / 2 - probabilities = [1 - concur, concur] - - ent_of_form = shannon_entropy(probabilities, base=base, backend=backend) - - return ent_of_form - - -def entropy( - state, - base: float = 2, - check_hermitian: bool = False, - return_spectrum: bool = False, - backend=None, -): - """The von-Neumann entropy :math:`S(\\rho)` of a quantum ``state`` :math:`\\rho`, which - is given by - - .. math:: - S(\\rho) = - \\text{tr}\\left[\\rho \\, \\log(\\rho)\\right] - - Args: - state (ndarray): statevector or density matrix. - base (float, optional): the base of the log. Defaults to :math:`2`. - check_hermitian (bool, optional): if ``True``, checks if ``state`` is Hermitian. - If ``False``, it assumes ``state`` is Hermitian . - Defaults to ``False``. - return_spectrum: if ``True``, returns ``entropy`` and - :math:`-\\log_{\\textup{b}}(\\textup{eigenvalues})`, where :math:`b` is ``base``. - If ``False``, returns only ``entropy``. Default is ``False``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. - - Returns: - float: The von-Neumann entropy :math:`S` of ``state`` :math:`\\rho`. - """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - - if ( - (len(state.shape) >= 3) - or (len(state) == 0) - or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) - ): - raise_error( - TypeError, - f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", - ) - - if base <= 0.0: - raise_error(ValueError, "log base must be non-negative.") - - if isinstance(check_hermitian, bool) is False: - raise_error( - TypeError, - f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", - ) - - if purity(state) == 1.0: - if return_spectrum: - return 0.0, backend.cast([1.0], dtype=float) - - return 0.0 - - if check_hermitian is False or _check_hermitian_or_not_gpu(state, backend=backend): - eigenvalues = np.linalg.eigvalsh(state) - else: - eigenvalues = np.linalg.eigvals(state) - - if base == 2: - log_prob = np.where(eigenvalues > 0, np.log2(eigenvalues), 0.0) - elif base == 10: - log_prob = np.where(eigenvalues > 0, np.log10(eigenvalues), 0.0) - elif base == np.e: - log_prob = np.where(eigenvalues > 0, np.log(eigenvalues), 0.0) - else: - log_prob = np.where(eigenvalues > 0, np.log(eigenvalues) / np.log(base), 0.0) - - ent = -np.sum(eigenvalues * log_prob) - # absolute value if entropy == 0.0 to avoid returning -0.0 - ent = np.abs(ent) if ent == 0.0 else ent - - ent = float(ent) - - if return_spectrum: - log_prob = backend.cast(log_prob, dtype=log_prob.dtype) - return ent, -log_prob - - return ent - - -def entanglement_entropy( - state, - bipartition, - base: float = 2, - check_hermitian: bool = False, - return_spectrum: bool = False, - backend=None, -): - """Calculates the entanglement entropy :math:`S` of bipartition :math:`A` - of ``state`` :math:`\\rho`. This is given by - - .. math:: - S(\\rho_{A}) = -\\text{tr}(\\rho_{A} \\, \\log(\\rho_{A})) \\, , - - where :math:`\\rho_{A} = \\text{tr}_{B}(\\rho)` is the reduced density matrix calculated - by tracing out the ``bipartition`` :math:`B`. - - Args: - state (ndarray): statevector or density matrix. - bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. - base (float, optional): the base of the log. Defaults to :math: `2`. - check_hermitian (bool, optional): if ``True``, checks if :math:`\\rho_{A}` is Hermitian. - If ``False``, it assumes ``state`` is Hermitian . Default: ``False``. - return_spectrum: if ``True``, returns ``entropy`` and eigenvalues of ``state``. - If ``False``, returns only ``entropy``. Default is ``False``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. - - Returns: - float: Entanglement entropy :math:`S` of ``state`` :math:`\\rho`. - """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - - if base <= 0.0: - raise_error(ValueError, "log base must be non-negative.") - - if ( - (len(state.shape) not in [1, 2]) - or (len(state) == 0) - or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) - ): - raise_error( - TypeError, - f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", - ) - - nqubits = int(np.log2(state.shape[0])) - - reduced_density_matrix = ( - backend.partial_trace(state, bipartition, nqubits) - if len(state.shape) == 1 - else backend.partial_trace_density_matrix(state, bipartition, nqubits) - ) - - entropy_entanglement = entropy( - reduced_density_matrix, - base=base, - check_hermitian=check_hermitian, - return_spectrum=return_spectrum, - backend=backend, - ) - - return entropy_entanglement - - def trace_distance(state, target, check_hermitian: bool = False, backend=None): """Trace distance between two quantum states, :math:`\\rho` and :math:`\\sigma`: @@ -634,84 +367,6 @@ def bures_distance(state, target, check_hermitian: bool = False, backend=None): return distance -def entanglement_fidelity( - channel, nqubits: int, state=None, check_hermitian: bool = False, backend=None -): - """Entanglement fidelity :math:`F_{\\mathcal{E}}` of a ``channel`` :math:`\\mathcal{E}` - on ``state`` :math:`\\rho` is given by - - .. math:: - F_{\\mathcal{E}}(\\rho) = F(\\rho_{f}, \\rho) - - where :math:`F` is the :func:`qibo.quantum_info.fidelity` function for states, - and :math:`\\rho_{f} = \\mathcal{E}_{A} \\otimes I_{B}(\\rho)` - is the state after the channel :math:`\\mathcal{E}` was applied to - partition :math:`A`. - - Args: - channel (:class:`qibo.gates.channels.Channel`): quantum channel - acting on partition :math:`A`. - nqubits (int): total number of qubits in ``state``. - state (ndarray, optional): statevector or density matrix to be evolved - by ``channel``. If ``None``, defaults to the maximally entangled state - :math:`\\frac{1}{2^{n}} \\, \\sum_{k} \\, \\ket{k}\\ket{k}`, where - :math:`n` is ``nqubits``. Defaults to ``None``. - check_hermitian (bool, optional): if ``True``, checks if the final state - :math:`\\rho_{f}` is Hermitian. If ``False``, it assumes it is Hermitian. - Defaults to ``False``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. - Defaults to ``None``. - - Returns: - float: Entanglement fidelity :math:`F_{\\mathcal{E}}`. - """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - - if isinstance(nqubits, int) is False: - raise_error( - TypeError, f"nqubits must be type int, but it is type {type(nqubits)}." - ) - - if nqubits <= 0: - raise_error( - ValueError, f"nqubits must be a positive integer, but it is {nqubits}." - ) - - if state is not None and ( - (len(state.shape) not in [1, 2]) - or (len(state) == 0) - or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) - ): - raise_error( - TypeError, - f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", - ) - - if isinstance(check_hermitian, bool) is False: - raise_error( - TypeError, - f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", - ) - - if state is None: - state = backend.plus_density_matrix(nqubits) - - # necessary because this function do support repeated execution, - # so it has to default to density matrices - if len(state.shape) == 1: - state = np.outer(state, np.conj(state)) - - state_final = backend.apply_channel_density_matrix(channel, state, nqubits) - - entang_fidelity = fidelity( - state_final, state, check_hermitian=check_hermitian, backend=backend - ) - - return entang_fidelity - - def process_fidelity(channel, target=None, check_unitary: bool = False, backend=None): """Process fidelity between a quantum ``channel`` :math:`\\mathcal{E}` and a ``target`` unitary channel :math:`U`. The process fidelity is defined as @@ -1008,103 +663,6 @@ def diamond_norm(channel, target=None, backend=None, **kwargs): return solution -def meyer_wallach_entanglement(circuit, backend=None): - """Computes the Meyer-Wallach entanglement Q of the `circuit`, - - .. math:: - Q(\\theta) = 1 - \\frac{1}{N} \\, \\sum_{k} \\, - \\text{tr}\\left(\\rho_{k^{2}}(\\theta)\\right) \\, . - - Args: - circuit (:class:`qibo.models.Circuit`): Parametrized circuit. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. - Defaults to ``None``. - - Returns: - float: Meyer-Wallach entanglement. - """ - - if backend is None: # pragma: no cover - backend = GlobalBackend() - - circuit.density_matrix = True - nqubits = circuit.nqubits - - rho = backend.execute_circuit(circuit).state() - - ent = 0 - for j in range(nqubits): - trace_q = list(range(nqubits)) - trace_q.pop(j) - - rho_r = backend.partial_trace_density_matrix(rho, trace_q, nqubits) - - trace = purity(rho_r) - - ent += trace - - entanglement = 1 - ent / nqubits - - return entanglement - - -def entangling_capability(circuit, samples: int, seed=None, backend=None): - """Returns the entangling capability :math:`\\text{Ent}` of a parametrized - circuit, which is average Meyer-Wallach entanglement Q of the circuit, i.e. - - .. math:: - \\text{Ent} = \\frac{2}{S}\\sum_{k}Q_k \\, , - - where :math:`S` is the number of samples. - - Args: - circuit (:class:`qibo.models.Circuit`): Parametrized circuit. - samples (int): number of samples to estimate the integral. - seed (int or :class:`numpy.random.Generator`, optional): Either a generator of random - numbers or a fixed seed to initialize a generator. If ``None``, initializes - a generator with a random seed. Default: ``None``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. - Defaults to ``None``. - - Returns: - float: Entangling capability. - """ - - if isinstance(samples, int) is False: - raise_error( - TypeError, f"samples must be type int, but it is type {type(samples)}." - ) - - if ( - seed is not None - and not isinstance(seed, int) - and not isinstance(seed, np.random.Generator) - ): - raise_error( - TypeError, "seed must be either type int or numpy.random.Generator." - ) - - if backend is None: # pragma: no cover - backend = GlobalBackend() - - local_state = ( - np.random.default_rng(seed) if seed is None or isinstance(seed, int) else seed - ) - - res = [] - for _ in range(samples): - params = local_state.uniform(-np.pi, np.pi, circuit.trainable_gates.nparams) - circuit.set_parameters(params) - entanglement = meyer_wallach_entanglement(circuit, backend=backend) - res.append(entanglement) - - capability = 2 * np.real(np.sum(res)) / samples - - return capability - - def expressibility( circuit, power_t: int, From a34e4cca4c7a73d914d09e34e2668531697ab1ca Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 08:59:29 +0400 Subject: [PATCH 053/200] split tests --- tests/test_quantum_info_entanglement.py | 175 ++++++++++++++ tests/test_quantum_info_entropies.py | 130 +++++++++++ tests/test_quantum_info_metrics.py | 294 ------------------------ 3 files changed, 305 insertions(+), 294 deletions(-) create mode 100644 tests/test_quantum_info_entanglement.py create mode 100644 tests/test_quantum_info_entropies.py diff --git a/tests/test_quantum_info_entanglement.py b/tests/test_quantum_info_entanglement.py new file mode 100644 index 0000000000..a98cf1909b --- /dev/null +++ b/tests/test_quantum_info_entanglement.py @@ -0,0 +1,175 @@ +import numpy as np +import pytest + +from qibo import Circuit, gates +from qibo.config import PRECISION_TOL +from qibo.quantum_info.entanglement import ( + concurrence, + entanglement_fidelity, + entanglement_of_formation, + entangling_capability, + meyer_wallach_entanglement, +) +from qibo.quantum_info.random_ensembles import random_density_matrix, random_statevector + + +@pytest.mark.parametrize("check_purity", [True, False]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("bipartition", [[0], [1]]) +def test_concurrence_and_formation(backend, bipartition, base, check_purity): + with pytest.raises(TypeError): + state = np.random.rand(2, 3) + state = backend.cast(state, dtype=state.dtype) + test = concurrence( + state, bipartition=bipartition, check_purity=check_purity, backend=backend + ) + with pytest.raises(TypeError): + state = random_statevector(4, backend=backend) + test = concurrence( + state, bipartition=bipartition, check_purity="True", backend=backend + ) + + if check_purity is True: + with pytest.raises(NotImplementedError): + state = backend.identity_density_matrix(2, normalize=False) + test = concurrence(state, bipartition=bipartition, backend=backend) + + nqubits = 2 + dim = 2**nqubits + state = random_statevector(dim, backend=backend) + concur = concurrence( + state, bipartition=bipartition, check_purity=check_purity, backend=backend + ) + ent_form = entanglement_of_formation( + state, + bipartition=bipartition, + base=base, + check_purity=check_purity, + backend=backend, + ) + backend.assert_allclose(0.0 <= concur <= np.sqrt(2), True) + backend.assert_allclose(0.0 <= ent_form <= 1.0, True) + + state = np.kron( + random_density_matrix(2, pure=True, backend=backend), + random_density_matrix(2, pure=True, backend=backend), + ) + concur = concurrence(state, bipartition, check_purity=check_purity, backend=backend) + ent_form = entanglement_of_formation( + state, + bipartition=bipartition, + base=base, + check_purity=check_purity, + backend=backend, + ) + backend.assert_allclose(concur, 0.0, atol=10 * PRECISION_TOL) + backend.assert_allclose(ent_form, 0.0, atol=PRECISION_TOL) + + +@pytest.mark.parametrize("check_hermitian", [False, True]) +@pytest.mark.parametrize("nqubits", [4, 6]) +@pytest.mark.parametrize("channel", [gates.DepolarizingChannel]) +def test_entanglement_fidelity(backend, channel, nqubits, check_hermitian): + with pytest.raises(TypeError): + test = entanglement_fidelity( + channel, nqubits=[0], check_hermitian=check_hermitian, backend=backend + ) + with pytest.raises(ValueError): + test = entanglement_fidelity( + channel, nqubits=0, check_hermitian=check_hermitian, backend=backend + ) + with pytest.raises(TypeError): + state = np.random.rand(2, 3, 2) + state = backend.cast(state, dtype=state.dtype) + test = entanglement_fidelity( + channel, + nqubits, + state=state, + check_hermitian=check_hermitian, + backend=backend, + ) + with pytest.raises(TypeError): + state = random_statevector(2, backend=backend) + test = entanglement_fidelity( + channel, nqubits, state=state, check_hermitian="False", backend=backend + ) + + channel = channel([0, 1], 0.5) + + # test on maximally entangled state + ent_fid = entanglement_fidelity( + channel, nqubits=nqubits, check_hermitian=check_hermitian, backend=backend + ) + backend.assert_allclose(ent_fid, 0.625, atol=PRECISION_TOL) + + # test with a state vector + state = backend.plus_state(nqubits) + ent_fid = entanglement_fidelity( + channel, + nqubits=nqubits, + state=state, + check_hermitian=check_hermitian, + backend=backend, + ) + backend.assert_allclose(ent_fid, 0.625, atol=PRECISION_TOL) + + # test on maximally mixed state + state = backend.identity_density_matrix(nqubits) + ent_fid = entanglement_fidelity( + channel, + nqubits=nqubits, + state=state, + check_hermitian=check_hermitian, + backend=backend, + ) + backend.assert_allclose(ent_fid, 1.0, atol=PRECISION_TOL) + + +def test_meyer_wallach_entanglement(backend): + nqubits = 2 + + circuit1 = Circuit(nqubits) + circuit1.add([gates.RX(0, np.pi / 4)] for _ in range(nqubits)) + + circuit2 = Circuit(nqubits) + circuit2.add([gates.RX(0, np.pi / 4)] for _ in range(nqubits)) + circuit2.add(gates.CNOT(0, 1)) + + backend.assert_allclose( + meyer_wallach_entanglement(circuit1, backend=backend), 0.0, atol=PRECISION_TOL + ) + + backend.assert_allclose( + meyer_wallach_entanglement(circuit2, backend=backend), 0.5, atol=PRECISION_TOL + ) + + +@pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)]) +def test_entangling_capability(backend, seed): + with pytest.raises(TypeError): + circuit = Circuit(1) + samples = 0.5 + entangling_capability(circuit, samples, seed=seed, backend=backend) + with pytest.raises(TypeError): + circuit = Circuit(1) + entangling_capability(circuit, samples=10, seed="10", backend=backend) + + nqubits = 2 + samples = 100 + + c1 = Circuit(nqubits) + c1.add([gates.RX(q, 0, trainable=True) for q in range(nqubits)]) + c1.add(gates.CNOT(0, 1)) + c1.add([gates.RX(q, 0, trainable=True) for q in range(nqubits)]) + ent_mw1 = entangling_capability(c1, samples, seed=seed, backend=backend) + + c2 = Circuit(nqubits) + c2.add(gates.H(0)) + c2.add(gates.CNOT(0, 1)) + c2.add(gates.RX(0, 0, trainable=True)) + ent_mw2 = entangling_capability(c2, samples, seed=seed, backend=backend) + + c3 = Circuit(nqubits) + ent_mw3 = entangling_capability(c3, samples, seed=seed, backend=backend) + + backend.assert_allclose(ent_mw3 < ent_mw1 < ent_mw2, True) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py new file mode 100644 index 0000000000..774ec11fcd --- /dev/null +++ b/tests/test_quantum_info_entropies.py @@ -0,0 +1,130 @@ +import numpy as np +import pytest + +from qibo.config import PRECISION_TOL +from qibo.quantum_info.entropies import entanglement_entropy, entropy +from qibo.quantum_info.random_ensembles import random_statevector, random_unitary + + +@pytest.mark.parametrize("check_hermitian", [False, True]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +def test_entropy(backend, base, check_hermitian): + with pytest.raises(TypeError): + state = np.random.rand(2, 3) + state = backend.cast(state, dtype=state.dtype) + test = entropy( + state, base=base, check_hermitian=check_hermitian, backend=backend + ) + with pytest.raises(ValueError): + state = np.array([1.0, 0.0]) + state = backend.cast(state, dtype=state.dtype) + test = entropy(state, base=0, check_hermitian=check_hermitian, backend=backend) + with pytest.raises(TypeError): + state = np.array([1.0, 0.0]) + state = backend.cast(state, dtype=state.dtype) + test = entropy(state, base=base, check_hermitian="False", backend=backend) + + if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + with pytest.raises(NotImplementedError): + state = random_unitary(4, backend=backend) + test = entropy(state, base=base, check_hermitian=True, backend=backend) + else: + state = random_unitary(4, backend=backend) + test = entropy(state, base=base, check_hermitian=True, backend=backend) + + state = np.array([1.0, 0.0]) + state = backend.cast(state, dtype=state.dtype) + backend.assert_allclose(entropy(state, backend=backend), 0.0, atol=PRECISION_TOL) + + state = np.array([1.0, 0.0, 0.0, 0.0]) + state = np.outer(state, state) + state = backend.cast(state, dtype=state.dtype) + + nqubits = 2 + state = backend.identity_density_matrix(nqubits) + if base == 2: + test = 2.0 + elif base == 10: + test = 0.6020599913279624 + elif base == np.e: + test = 1.3862943611198906 + else: + test = 0.8613531161467861 + + backend.assert_allclose( + entropy(state, base, check_hermitian=check_hermitian, backend=backend), test + ) + + +@pytest.mark.parametrize("check_hermitian", [False, True]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("bipartition", [[0], [1]]) +def test_entanglement_entropy(backend, bipartition, base, check_hermitian): + with pytest.raises(TypeError): + state = np.random.rand(2, 3) + state = backend.cast(state, dtype=state.dtype) + test = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=check_hermitian, + backend=backend, + ) + with pytest.raises(ValueError): + state = np.array([1.0, 0.0]) + state = backend.cast(state, dtype=state.dtype) + test = entanglement_entropy( + state, + bipartition=bipartition, + base=0, + check_hermitian=check_hermitian, + backend=backend, + ) + if backend.__class__.__name__ == "CupyBackend": + with pytest.raises(NotImplementedError): + state = random_unitary(4, backend=backend) + test = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=True, + backend=backend, + ) + + # Bell state + state = np.array([1.0, 0.0, 0.0, 1.0]) / np.sqrt(2) + state = backend.cast(state, dtype=state.dtype) + + entang_entrop = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=check_hermitian, + backend=backend, + ) + + if base == 2: + test = 1.0 + elif base == 10: + test = 0.30102999566398125 + elif base == np.e: + test = 0.6931471805599454 + else: + test = 0.4306765580733931 + + backend.assert_allclose(entang_entrop, test, atol=PRECISION_TOL) + + # Product state + state = np.kron( + random_statevector(2, backend=backend), random_statevector(2, backend=backend) + ) + + entang_entrop = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=check_hermitian, + backend=backend, + ) + + backend.assert_allclose(entang_entrop, 0.0, atol=PRECISION_TOL) diff --git a/tests/test_quantum_info_metrics.py b/tests/test_quantum_info_metrics.py index 0e7b86f21b..793bb510a5 100644 --- a/tests/test_quantum_info_metrics.py +++ b/tests/test_quantum_info_metrics.py @@ -7,13 +7,7 @@ average_gate_fidelity, bures_angle, bures_distance, - concurrence, diamond_norm, - entanglement_entropy, - entanglement_fidelity, - entanglement_of_formation, - entangling_capability, - entropy, expressibility, fidelity, frame_potential, @@ -21,7 +15,6 @@ hilbert_schmidt_distance, impurity, infidelity, - meyer_wallach_entanglement, process_fidelity, process_infidelity, purity, @@ -30,7 +23,6 @@ from qibo.quantum_info.random_ensembles import ( random_density_matrix, random_hermitian, - random_statevector, random_unitary, ) from qibo.quantum_info.superoperator_transformations import to_choi @@ -59,183 +51,6 @@ def test_purity_and_impurity(backend): backend.assert_allclose(impurity(state), 1.0 - 1.0 / dim, atol=PRECISION_TOL) -@pytest.mark.parametrize("check_purity", [True, False]) -@pytest.mark.parametrize("base", [2, 10, np.e, 5]) -@pytest.mark.parametrize("bipartition", [[0], [1]]) -def test_concurrence_and_formation(backend, bipartition, base, check_purity): - with pytest.raises(TypeError): - state = np.random.rand(2, 3) - state = backend.cast(state, dtype=state.dtype) - test = concurrence( - state, bipartition=bipartition, check_purity=check_purity, backend=backend - ) - with pytest.raises(TypeError): - state = random_statevector(4, backend=backend) - test = concurrence( - state, bipartition=bipartition, check_purity="True", backend=backend - ) - - if check_purity is True: - with pytest.raises(NotImplementedError): - state = backend.identity_density_matrix(2, normalize=False) - test = concurrence(state, bipartition=bipartition, backend=backend) - - nqubits = 2 - dim = 2**nqubits - state = random_statevector(dim, backend=backend) - concur = concurrence( - state, bipartition=bipartition, check_purity=check_purity, backend=backend - ) - ent_form = entanglement_of_formation( - state, - bipartition=bipartition, - base=base, - check_purity=check_purity, - backend=backend, - ) - backend.assert_allclose(0.0 <= concur <= np.sqrt(2), True) - backend.assert_allclose(0.0 <= ent_form <= 1.0, True) - - state = np.kron( - random_density_matrix(2, pure=True, backend=backend), - random_density_matrix(2, pure=True, backend=backend), - ) - concur = concurrence(state, bipartition, check_purity=check_purity, backend=backend) - ent_form = entanglement_of_formation( - state, - bipartition=bipartition, - base=base, - check_purity=check_purity, - backend=backend, - ) - backend.assert_allclose(concur, 0.0, atol=10 * PRECISION_TOL) - backend.assert_allclose(ent_form, 0.0, atol=PRECISION_TOL) - - -@pytest.mark.parametrize("check_hermitian", [False, True]) -@pytest.mark.parametrize("base", [2, 10, np.e, 5]) -def test_entropy(backend, base, check_hermitian): - with pytest.raises(TypeError): - state = np.random.rand(2, 3) - state = backend.cast(state, dtype=state.dtype) - test = entropy( - state, base=base, check_hermitian=check_hermitian, backend=backend - ) - with pytest.raises(ValueError): - state = np.array([1.0, 0.0]) - state = backend.cast(state, dtype=state.dtype) - test = entropy(state, base=0, check_hermitian=check_hermitian, backend=backend) - with pytest.raises(TypeError): - state = np.array([1.0, 0.0]) - state = backend.cast(state, dtype=state.dtype) - test = entropy(state, base=base, check_hermitian="False", backend=backend) - - if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: - with pytest.raises(NotImplementedError): - state = random_unitary(4, backend=backend) - test = entropy(state, base=base, check_hermitian=True, backend=backend) - else: - state = random_unitary(4, backend=backend) - test = entropy(state, base=base, check_hermitian=True, backend=backend) - - state = np.array([1.0, 0.0]) - state = backend.cast(state, dtype=state.dtype) - backend.assert_allclose(entropy(state, backend=backend), 0.0, atol=PRECISION_TOL) - - state = np.array([1.0, 0.0, 0.0, 0.0]) - state = np.outer(state, state) - state = backend.cast(state, dtype=state.dtype) - - nqubits = 2 - state = backend.identity_density_matrix(nqubits) - if base == 2: - test = 2.0 - elif base == 10: - test = 0.6020599913279624 - elif base == np.e: - test = 1.3862943611198906 - else: - test = 0.8613531161467861 - - backend.assert_allclose( - entropy(state, base, check_hermitian=check_hermitian, backend=backend), test - ) - - -@pytest.mark.parametrize("check_hermitian", [False, True]) -@pytest.mark.parametrize("base", [2, 10, np.e, 5]) -@pytest.mark.parametrize("bipartition", [[0], [1]]) -def test_entanglement_entropy(backend, bipartition, base, check_hermitian): - with pytest.raises(TypeError): - state = np.random.rand(2, 3) - state = backend.cast(state, dtype=state.dtype) - test = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=check_hermitian, - backend=backend, - ) - with pytest.raises(ValueError): - state = np.array([1.0, 0.0]) - state = backend.cast(state, dtype=state.dtype) - test = entanglement_entropy( - state, - bipartition=bipartition, - base=0, - check_hermitian=check_hermitian, - backend=backend, - ) - if backend.__class__.__name__ == "CupyBackend": - with pytest.raises(NotImplementedError): - state = random_unitary(4, backend=backend) - test = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=True, - backend=backend, - ) - - # Bell state - state = np.array([1.0, 0.0, 0.0, 1.0]) / np.sqrt(2) - state = backend.cast(state, dtype=state.dtype) - - entang_entrop = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=check_hermitian, - backend=backend, - ) - - if base == 2: - test = 1.0 - elif base == 10: - test = 0.30102999566398125 - elif base == np.e: - test = 0.6931471805599454 - else: - test = 0.4306765580733931 - - backend.assert_allclose(entang_entrop, test, atol=PRECISION_TOL) - - # Product state - state = np.kron( - random_statevector(2, backend=backend), random_statevector(2, backend=backend) - ) - - entang_entrop = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=check_hermitian, - backend=backend, - ) - - backend.assert_allclose(entang_entrop, 0.0, atol=PRECISION_TOL) - - @pytest.mark.parametrize("check_hermitian", [False, True]) def test_trace_distance(backend, check_hermitian): with pytest.raises(TypeError): @@ -445,65 +260,6 @@ def test_fidelity_and_infidelity_and_bures(backend, check_hermitian): test = fidelity(state, target, check_hermitian=True, backend=backend) -@pytest.mark.parametrize("check_hermitian", [False, True]) -@pytest.mark.parametrize("nqubits", [4, 6]) -@pytest.mark.parametrize("channel", [gates.DepolarizingChannel]) -def test_entanglement_fidelity(backend, channel, nqubits, check_hermitian): - with pytest.raises(TypeError): - test = entanglement_fidelity( - channel, nqubits=[0], check_hermitian=check_hermitian, backend=backend - ) - with pytest.raises(ValueError): - test = entanglement_fidelity( - channel, nqubits=0, check_hermitian=check_hermitian, backend=backend - ) - with pytest.raises(TypeError): - state = np.random.rand(2, 3, 2) - state = backend.cast(state, dtype=state.dtype) - test = entanglement_fidelity( - channel, - nqubits, - state=state, - check_hermitian=check_hermitian, - backend=backend, - ) - with pytest.raises(TypeError): - state = random_statevector(2, backend=backend) - test = entanglement_fidelity( - channel, nqubits, state=state, check_hermitian="False", backend=backend - ) - - channel = channel([0, 1], 0.5) - - # test on maximally entangled state - ent_fid = entanglement_fidelity( - channel, nqubits=nqubits, check_hermitian=check_hermitian, backend=backend - ) - backend.assert_allclose(ent_fid, 0.625, atol=PRECISION_TOL) - - # test with a state vector - state = backend.plus_state(nqubits) - ent_fid = entanglement_fidelity( - channel, - nqubits=nqubits, - state=state, - check_hermitian=check_hermitian, - backend=backend, - ) - backend.assert_allclose(ent_fid, 0.625, atol=PRECISION_TOL) - - # test on maximally mixed state - state = backend.identity_density_matrix(nqubits) - ent_fid = entanglement_fidelity( - channel, - nqubits=nqubits, - state=state, - check_hermitian=check_hermitian, - backend=backend, - ) - backend.assert_allclose(ent_fid, 1.0, atol=PRECISION_TOL) - - def test_process_fidelity_and_infidelity(backend): d = 2 with pytest.raises(TypeError): @@ -572,56 +328,6 @@ def test_diamond_norm(backend, nqubits): backend.assert_allclose(dnorm, 0.0, atol=PRECISION_TOL) -def test_meyer_wallach_entanglement(backend): - nqubits = 2 - - circuit1 = Circuit(nqubits) - circuit1.add([gates.RX(0, np.pi / 4)] for _ in range(nqubits)) - - circuit2 = Circuit(nqubits) - circuit2.add([gates.RX(0, np.pi / 4)] for _ in range(nqubits)) - circuit2.add(gates.CNOT(0, 1)) - - backend.assert_allclose( - meyer_wallach_entanglement(circuit1, backend=backend), 0.0, atol=PRECISION_TOL - ) - - backend.assert_allclose( - meyer_wallach_entanglement(circuit2, backend=backend), 0.5, atol=PRECISION_TOL - ) - - -@pytest.mark.parametrize("seed", [None, 10, np.random.default_rng(10)]) -def test_entangling_capability(backend, seed): - with pytest.raises(TypeError): - circuit = Circuit(1) - samples = 0.5 - entangling_capability(circuit, samples, seed=seed, backend=backend) - with pytest.raises(TypeError): - circuit = Circuit(1) - entangling_capability(circuit, samples=10, seed="10", backend=backend) - - nqubits = 2 - samples = 100 - - c1 = Circuit(nqubits) - c1.add([gates.RX(q, 0, trainable=True) for q in range(nqubits)]) - c1.add(gates.CNOT(0, 1)) - c1.add([gates.RX(q, 0, trainable=True) for q in range(nqubits)]) - ent_mw1 = entangling_capability(c1, samples, seed=seed, backend=backend) - - c2 = Circuit(nqubits) - c2.add(gates.H(0)) - c2.add(gates.CNOT(0, 1)) - c2.add(gates.RX(0, 0, trainable=True)) - ent_mw2 = entangling_capability(c2, samples, seed=seed, backend=backend) - - c3 = Circuit(nqubits) - ent_mw3 = entangling_capability(c3, samples, seed=seed, backend=backend) - - backend.assert_allclose(ent_mw3 < ent_mw1 < ent_mw2, True) - - def test_expressibility(backend): with pytest.raises(TypeError): circuit = Circuit(1) From ed89806d818edfd2c961cfb2193b71c05d34206c Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 09:06:59 +0400 Subject: [PATCH 054/200] split api reference --- doc/source/api-reference/qibo.rst | 102 +++++++++++++++++------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 2f8e7d9d92..deb571878e 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1489,35 +1489,11 @@ The destabilizers can be extracted analogously with :meth:`qibo.quantum_info.cli :member-order: bysource -Metrics -^^^^^^^ -Set of functions that are used to calculate metrics of states, (pseudo-)distance measures -between states, and distance measures between quantum channels. - -Purity -"""""" - -.. autofunction:: qibo.quantum_info.purity - - -Impurity -"""""""" - -.. autofunction:: qibo.quantum_info.impurity - - -Concurrence -""""""""""" - -.. autofunction:: qibo.quantum_info.concurrence - - -Entanglement of formation -""""""""""""""""""""""""" - -.. autofunction:: qibo.quantum_info.entanglement_of_formation +Entropy measures +^^^^^^^^^^^^^^^^ +Set of functions to calculate entropy measures. Entropy """"""" @@ -1547,6 +1523,60 @@ Entanglement entropy when using `cupy` backend. +Entanglement measures +^^^^^^^^^^^^^^^^^^^^^ + +Set of functions to calculate entanglement measures. + + +Concurrence +""""""""""" + +.. autofunction:: qibo.quantum_info.concurrence + + +Entanglement of formation +""""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.entanglement_of_formation + + +Entanglement fidelity +""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.entanglement_fidelity + + +Meyer-Wallach entanglement +"""""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.meyer_wallach_entanglement + + +Entanglement capability +""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.entangling_capability + + +Metrics +^^^^^^^ + +Set of functions that are used to calculate metrics of states, (pseudo-)distance measures +between states, and distance measures between quantum channels. + +Purity +"""""" + +.. autofunction:: qibo.quantum_info.purity + + +Impurity +"""""""" + +.. autofunction:: qibo.quantum_info.impurity + + Trace distance """""""""""""" @@ -1591,12 +1621,6 @@ Bures distance .. autofunction:: qibo.quantum_info.bures_distance -Entanglement fidelity -""""""""""""""""""""" - -.. autofunction:: qibo.quantum_info.entanglement_fidelity - - Process fidelity """""""""""""""" @@ -1627,18 +1651,6 @@ Diamond Norm .. autofunction:: qibo.quantum_info.diamond_norm -Meyer-Wallach entanglement -"""""""""""""""""""""""""" - -.. autofunction:: qibo.quantum_info.meyer_wallach_entanglement - - -Entanglement capability -""""""""""""""""""""""" - -.. autofunction:: qibo.quantum_info.entangling_capability - - Expressibility of parameterized quantum circuits """""""""""""""""""""""""""""""""""""""""""""""" From 5991f6216edb4fce228fcb4433647f5be56f1b10 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 09:15:33 +0400 Subject: [PATCH 055/200] fix import --- src/qibo/callbacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/callbacks.py b/src/qibo/callbacks.py index 16d88d712a..34026bc930 100644 --- a/src/qibo/callbacks.py +++ b/src/qibo/callbacks.py @@ -125,7 +125,7 @@ def nqubits(self, n: int): ] def apply(self, backend, state): - from qibo.quantum_info.metrics import entanglement_entropy + from qibo.quantum_info.entanglement import entanglement_entropy entropy, spectrum = entanglement_entropy( state, From 8994079ddf28f6d40e52c7f84f90044f22e1e4ce Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 09:15:44 +0400 Subject: [PATCH 056/200] update `__init__.py` --- src/qibo/quantum_info/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qibo/quantum_info/__init__.py b/src/qibo/quantum_info/__init__.py index 640fdb3e13..73124d82a1 100644 --- a/src/qibo/quantum_info/__init__.py +++ b/src/qibo/quantum_info/__init__.py @@ -1,5 +1,7 @@ from qibo.quantum_info.basis import * from qibo.quantum_info.clifford import * +from qibo.quantum_info.entanglement import * +from qibo.quantum_info.entropies import * from qibo.quantum_info.metrics import * from qibo.quantum_info.random_ensembles import * from qibo.quantum_info.superoperator_transformations import * From 68967d9f3a255d281c71d5277b4dd7c8dc076f08 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 28 Jan 2024 09:19:21 +0400 Subject: [PATCH 057/200] fix import --- src/qibo/callbacks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/callbacks.py b/src/qibo/callbacks.py index 34026bc930..77114ed42a 100644 --- a/src/qibo/callbacks.py +++ b/src/qibo/callbacks.py @@ -125,7 +125,7 @@ def nqubits(self, n: int): ] def apply(self, backend, state): - from qibo.quantum_info.entanglement import entanglement_entropy + from qibo.quantum_info.entropies import entanglement_entropy entropy, spectrum = entanglement_entropy( state, From cbeb4e6eb5cf6de55941639025523b02390fa53c Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 09:34:47 +0400 Subject: [PATCH 058/200] `shannon_entropy` from `utils` to `entropies` --- doc/source/api-reference/qibo.rst | 80 +++++++++++++-------------- src/qibo/quantum_info/entanglement.py | 6 +- src/qibo/quantum_info/entropies.py | 68 ++++++++++++++++++++++- src/qibo/quantum_info/utils.py | 66 ---------------------- tests/test_quantum_info_entropies.py | 42 +++++++++++++- tests/test_quantum_info_utils.py | 41 -------------- 6 files changed, 151 insertions(+), 152 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index deb571878e..efe2a4ef08 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1489,40 +1489,6 @@ The destabilizers can be extracted analogously with :meth:`qibo.quantum_info.cli :member-order: bysource - -Entropy measures -^^^^^^^^^^^^^^^^ - -Set of functions to calculate entropy measures. - -Entropy -""""""" - -.. autofunction:: qibo.quantum_info.entropy - -.. note:: - ``validate`` flag allows the user to choose if the function will check if input - ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the - assumption of Hermiticity, because it is faster and, more importantly, - the functions are intended to be used on Hermitian inputs. When ``validate=True`` - and ``state`` is non-Hermitian, an error will be raised when using `cupy` backend. - - -Entanglement entropy -"""""""""""""""""""" - -.. autofunction:: qibo.quantum_info.entanglement_entropy - -.. note:: - ``validate`` flag allows the user to choose if the function will check if - the reduced density matrix resulting from tracing out ``bipartition`` from input - ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the - assumption of Hermiticity, because it is faster and, more importantly, - the functions are intended to be used on Hermitian inputs. When ``validate=True`` - and the reduced density matrix is non-Hermitian, an error will be raised - when using `cupy` backend. - - Entanglement measures ^^^^^^^^^^^^^^^^^^^^^ @@ -1559,6 +1525,46 @@ Entanglement capability .. autofunction:: qibo.quantum_info.entangling_capability +Entropy measures +^^^^^^^^^^^^^^^^ + +Set of functions to calculate entropy measures. + + +Shannon entropy +""""""""""""""" + +.. autofunction:: qibo.quantum_info.shannon_entropy + + +Entropy +""""""" + +.. autofunction:: qibo.quantum_info.entropy + +.. note:: + ``validate`` flag allows the user to choose if the function will check if input + ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the + assumption of Hermiticity, because it is faster and, more importantly, + the functions are intended to be used on Hermitian inputs. When ``validate=True`` + and ``state`` is non-Hermitian, an error will be raised when using `cupy` backend. + + +Entanglement Entropy +"""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.entanglement_entropy + +.. note:: + ``validate`` flag allows the user to choose if the function will check if + the reduced density matrix resulting from tracing out ``bipartition`` from input + ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the + assumption of Hermiticity, because it is faster and, more importantly, + the functions are intended to be used on Hermitian inputs. When ``validate=True`` + and the reduced density matrix is non-Hermitian, an error will be raised + when using `cupy` backend. + + Metrics ^^^^^^^ @@ -2047,12 +2053,6 @@ Hadamard Transform .. autofunction:: qibo.quantum_info.hadamard_transform -Shannon entropy -""""""""""""""" - -.. autofunction:: qibo.quantum_info.shannon_entropy - - Hellinger distance """""""""""""""""" diff --git a/src/qibo/quantum_info/entanglement.py b/src/qibo/quantum_info/entanglement.py index 7f006655d6..c2f6eda3f0 100644 --- a/src/qibo/quantum_info/entanglement.py +++ b/src/qibo/quantum_info/entanglement.py @@ -90,12 +90,12 @@ def entanglement_of_formation( x = \\frac{1 + \\sqrt{1 - C^{2}(\\rho)}}{2} \\, , :math:`C(\\rho)` is the :func:`qibo.quantum_info.concurrence` of :math:`\\rho`, - and :math:`H` is the :func:`qibo.quantum_info.shannon_entropy`. + and :math:`H` is the :func:`qibo.quantum_info.entropies.shannon_entropy`. Args: state (ndarray): statevector or density matrix. bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. - base (float): the base of the log in :func:`qibo.quantum_info.shannon_entropy`. + base (float): the base of the log in :func:`qibo.quantum_info.entropies.shannon_entropy`. Defaults to :math:`2`. check_purity (bool, optional): if ``True``, checks if ``state`` is pure. If ``False``, it assumes ``state`` is pure . Default: ``True``. @@ -110,7 +110,7 @@ def entanglement_of_formation( if backend is None: # pragma: no cover backend = GlobalBackend() - from qibo.quantum_info.utils import shannon_entropy # pylint: disable=C0415 + from qibo.quantum_info.entropies import shannon_entropy # pylint: disable=C0415 concur = concurrence( state, bipartition=bipartition, check_purity=check_purity, backend=backend diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 82e557772c..6a09d920fe 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -3,10 +3,76 @@ import numpy as np from qibo.backends import GlobalBackend -from qibo.config import raise_error +from qibo.config import PRECISION_TOL, raise_error from qibo.quantum_info.metrics import _check_hermitian_or_not_gpu, purity +def shannon_entropy(probability_array, base: float = 2, backend=None): + """Calculate the Shannon entropy of a probability array :math:`\\mathbf{p}`, which is given by + + .. math:: + H(\\mathbf{p}) = - \\sum_{k = 0}^{d^{2} - 1} \\, p_{k} \\, \\log_{b}(p_{k}) \\, , + + where :math:`d = \\text{dim}(\\mathcal{H})` is the dimension of the + Hilbert space :math:`\\mathcal{H}`, :math:`b` is the log base (default 2), + and :math:`0 \\log_{b}(0) \\equiv 0`. + + Args: + probability_array (ndarray or list): a probability array :math:`\\mathbf{p}`. + base (float): the base of the log. Defaults to :math:`2`. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + Defaults to ``None``. + + Returns: + (float): Shannon entropy :math:`H(\\mathcal{p})`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if isinstance(probability_array, list): + probability_array = backend.cast(probability_array, dtype=float) + + if base <= 0: + raise_error(ValueError, "log base must be non-negative.") + + if len(probability_array.shape) != 1: + raise_error( + TypeError, + f"Probability array must have dims (k,) but it has {probability_array.shape}.", + ) + + if len(probability_array) == 0: + raise_error(TypeError, "Empty array.") + + if any(probability_array < 0) or any(probability_array > 1.0): + raise_error( + ValueError, + "All elements of the probability array must be between 0. and 1..", + ) + + if np.abs(np.sum(probability_array) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "Probability array must sum to 1.") + + if base == 2: + log_prob = np.where(probability_array != 0.0, np.log2(probability_array), 0.0) + elif base == 10: + log_prob = np.where(probability_array != 0, np.log10(probability_array), 0.0) + elif base == np.e: + log_prob = np.where(probability_array != 0, np.log(probability_array), 0.0) + else: + log_prob = np.where( + probability_array != 0, np.log(probability_array) / np.log(base), 0.0 + ) + + entropy = -np.sum(probability_array * log_prob) + + # absolute value if entropy == 0.0 to avoid returning -0.0 + entropy = np.abs(entropy) if entropy == 0.0 else entropy + + return complex(entropy).real + + def entropy( state, base: float = 2, diff --git a/src/qibo/quantum_info/utils.py b/src/qibo/quantum_info/utils.py index eb5a447d8d..e13ed68f95 100644 --- a/src/qibo/quantum_info/utils.py +++ b/src/qibo/quantum_info/utils.py @@ -127,72 +127,6 @@ def hadamard_transform(array, implementation: str = "fast", backend=None): return array -def shannon_entropy(probability_array, base: float = 2, backend=None): - """Calculate the Shannon entropy of a probability array :math:`\\mathbf{p}`, which is given by - - .. math:: - H(\\mathbf{p}) = - \\sum_{k = 0}^{d^{2} - 1} \\, p_{k} \\, \\log_{b}(p_{k}) \\, , - - where :math:`d = \\text{dim}(\\mathcal{H})` is the dimension of the - Hilbert space :math:`\\mathcal{H}`, :math:`b` is the log base (default 2), - and :math:`0 \\log_{b}(0) \\equiv 0`. - - Args: - probability_array (ndarray or list): a probability array :math:`\\mathbf{p}`. - base (float): the base of the log. Defaults to :math:`2`. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. - Defaults to ``None``. - - Returns: - (float): The Shannon entropy :math:`H(\\mathcal{p})`. - """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - - if isinstance(probability_array, list): - probability_array = backend.cast(probability_array, dtype=float) - - if base <= 0: - raise_error(ValueError, "log base must be non-negative.") - - if len(probability_array.shape) != 1: - raise_error( - TypeError, - f"Probability array must have dims (k,) but it has {probability_array.shape}.", - ) - - if len(probability_array) == 0: - raise_error(TypeError, "Empty array.") - - if any(probability_array < 0) or any(probability_array > 1.0): - raise_error( - ValueError, - "All elements of the probability array must be between 0. and 1..", - ) - - if np.abs(np.sum(probability_array) - 1.0) > PRECISION_TOL: - raise_error(ValueError, "Probability array must sum to 1.") - - if base == 2: - log_prob = np.where(probability_array != 0.0, np.log2(probability_array), 0.0) - elif base == 10: - log_prob = np.where(probability_array != 0, np.log10(probability_array), 0.0) - elif base == np.e: - log_prob = np.where(probability_array != 0, np.log(probability_array), 0.0) - else: - log_prob = np.where( - probability_array != 0, np.log(probability_array) / np.log(base), 0.0 - ) - - entropy = -np.sum(probability_array * log_prob) - - # absolute value if entropy == 0.0 to avoid returning -0.0 - entropy = np.abs(entropy) if entropy == 0.0 else entropy - - return complex(entropy).real - - def hellinger_distance(prob_dist_p, prob_dist_q, validate: bool = False, backend=None): """Calculate the Hellinger distance :math:`H(p, q)` between two discrete probability distributions, :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 774ec11fcd..3cc2c43f2f 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -2,10 +2,50 @@ import pytest from qibo.config import PRECISION_TOL -from qibo.quantum_info.entropies import entanglement_entropy, entropy +from qibo.quantum_info.entropies import entanglement_entropy, entropy, shannon_entropy from qibo.quantum_info.random_ensembles import random_statevector, random_unitary +def test_shannon_entropy_errors(backend): + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = shannon_entropy(prob, -2, backend=backend) + with pytest.raises(TypeError): + prob = np.array([[1.0], [0.0]]) + prob = backend.cast(prob, dtype=prob.dtype) + test = shannon_entropy(prob, backend=backend) + with pytest.raises(TypeError): + prob = np.array([]) + prob = backend.cast(prob, dtype=prob.dtype) + test = shannon_entropy(prob, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, -1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = shannon_entropy(prob, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.1, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = shannon_entropy(prob, backend=backend) + with pytest.raises(ValueError): + prob = np.array([0.5, 0.4999999]) + prob = backend.cast(prob, dtype=prob.dtype) + test = shannon_entropy(prob, backend=backend) + + +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +def test_shannon_entropy(backend, base): + prob_array = [1.0, 0.0] + result = shannon_entropy(prob_array, base, backend=backend) + backend.assert_allclose(result, 0.0) + + if base == 2: + prob_array = np.array([0.5, 0.5]) + prob_array = backend.cast(prob_array, dtype=prob_array.dtype) + result = shannon_entropy(prob_array, base, backend=backend) + backend.assert_allclose(result, 1.0) + + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) def test_entropy(backend, base, check_hermitian): diff --git a/tests/test_quantum_info_utils.py b/tests/test_quantum_info_utils.py index f873078bb4..d96d3dfd2b 100644 --- a/tests/test_quantum_info_utils.py +++ b/tests/test_quantum_info_utils.py @@ -14,7 +14,6 @@ hellinger_distance, hellinger_fidelity, pqc_integral, - shannon_entropy, ) @@ -90,46 +89,6 @@ def test_hadamard_transform(backend, nqubits, implementation, is_matrix): backend.assert_allclose(transformed, test_transformed, atol=PRECISION_TOL) -def test_shannon_entropy_errors(backend): - with pytest.raises(ValueError): - prob = np.array([1.0, 0.0]) - prob = backend.cast(prob, dtype=prob.dtype) - test = shannon_entropy(prob, -2, backend=backend) - with pytest.raises(TypeError): - prob = np.array([[1.0], [0.0]]) - prob = backend.cast(prob, dtype=prob.dtype) - test = shannon_entropy(prob, backend=backend) - with pytest.raises(TypeError): - prob = np.array([]) - prob = backend.cast(prob, dtype=prob.dtype) - test = shannon_entropy(prob, backend=backend) - with pytest.raises(ValueError): - prob = np.array([1.0, -1.0]) - prob = backend.cast(prob, dtype=prob.dtype) - test = shannon_entropy(prob, backend=backend) - with pytest.raises(ValueError): - prob = np.array([1.1, 0.0]) - prob = backend.cast(prob, dtype=prob.dtype) - test = shannon_entropy(prob, backend=backend) - with pytest.raises(ValueError): - prob = np.array([0.5, 0.4999999]) - prob = backend.cast(prob, dtype=prob.dtype) - test = shannon_entropy(prob, backend=backend) - - -@pytest.mark.parametrize("base", [2, 10, np.e, 5]) -def test_shannon_entropy(backend, base): - prob_array = [1.0, 0.0] - result = shannon_entropy(prob_array, base, backend=backend) - backend.assert_allclose(result, 0.0) - - if base == 2: - prob_array = np.array([0.5, 0.5]) - prob_array = backend.cast(prob_array, dtype=prob_array.dtype) - result = shannon_entropy(prob_array, base, backend=backend) - backend.assert_allclose(result, 1.0) - - def test_hellinger(backend): with pytest.raises(TypeError): prob = np.random.rand(1, 2) From 44f9719bfc44eede7a621d7e9db72d658fc158bb Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 10:42:12 +0400 Subject: [PATCH 059/200] function --- src/qibo/quantum_info/entropies.py | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 6a09d920fe..759cc411fa 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -222,3 +222,63 @@ def entanglement_entropy( ) return entropy_entanglement + + +def classical_relative_entropy( + prob_dist_p, prob_dist_q, base: float = 2, validate: bool = False, backend=None +): + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if isinstance(prob_dist_p, list): + prob_dist_p = backend.cast(prob_dist_p, dtype=float) + if isinstance(prob_dist_q, list): + prob_dist_q = backend.cast(prob_dist_q, dtype=float) + + if (len(prob_dist_p.shape) != 1) or (len(prob_dist_q.shape) != 1): + raise_error( + TypeError, + "Probability arrays must have dims (k,) but have " + + f"dims {prob_dist_p.shape} and {prob_dist_q.shape}.", + ) + + if (len(prob_dist_p) == 0) or (len(prob_dist_q) == 0): + raise_error(TypeError, "At least one of the arrays is empty.") + + if base <= 0: + raise_error(ValueError, "log base must be non-negative.") + + if validate: + if (any(prob_dist_p < 0) or any(prob_dist_p > 1.0)) or ( + any(prob_dist_q < 0) or any(prob_dist_q > 1.0) + ): + raise_error( + ValueError, + "All elements of the probability array must be between 0. and 1..", + ) + if np.abs(np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "First probability array must sum to 1.") + + if np.abs(np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "Second probability array must sum to 1.") + + entropy_p = -shannon_entropy(prob_dist_p, base=base, backend=backend) + + if base == 2: + log_prob_q = np.where(prob_dist_q != 0.0, np.log2(prob_dist_q), -np.inf) + log_prob = np.where(prob_dist_p != 0.0, log_prob_q, 0.0) + elif base == 10: + log_prob_q = np.where(prob_dist_q != 0.0, np.log10(prob_dist_q), -np.inf) + log_prob = np.where(prob_dist_p != 0, log_prob_q, 0.0) + elif base == np.e: + log_prob_q = np.where(prob_dist_q != 0.0, np.log(prob_dist_q), -np.inf) + log_prob = np.where(prob_dist_p != 0, log_prob_q, 0.0) + else: + log_prob_q = np.where( + prob_dist_q != 0.0, np.log(prob_dist_q) / np.log(base), -np.inf + ) + log_prob = np.where(prob_dist_p != 0, log_prob_q / np.log(base), 0.0) + + relative = np.sum(prob_dist_p * log_prob) + + return entropy_p - relative From d004521f48d0aa8d26cfdc31741042e09a5922b5 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 12:16:10 +0400 Subject: [PATCH 060/200] docstring --- src/qibo/quantum_info/entropies.py | 38 ++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 759cc411fa..8c014c0af6 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -31,7 +31,8 @@ def shannon_entropy(probability_array, base: float = 2, backend=None): backend = GlobalBackend() if isinstance(probability_array, list): - probability_array = backend.cast(probability_array, dtype=float) + # np.float64 is necessary instead of native float because of tensorflow + probability_array = backend.cast(probability_array, dtype=np.float64) if base <= 0: raise_error(ValueError, "log base must be non-negative.") @@ -227,13 +228,38 @@ def entanglement_entropy( def classical_relative_entropy( prob_dist_p, prob_dist_q, base: float = 2, validate: bool = False, backend=None ): + """Calculates the relative entropy between two discrete probability distributions. + + For probabilities :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, it is defined as + + ..math:: + D(\\mathbf{p} \\, \\| \\, \\mathbf{q}) = \\sum_{x} \\, \\mathbf{p}(x) \\, + \\log\\left( \\frac{\\mathbf{p}(x)}{\\mathbf{q}(x)} \\right) \\, . + + The classical relative entropy is also known as the + `Kullback-Leibler (KL) divergence `_. + + Args: + prob_dist_p (ndarray or list): discrete probability distribution :math:`p`. + prob_dist_q (ndarray or list): discrete probability distribution :math:`q`. + base (float): the base of the log. Defaults to :math:`2`. + validate (bool, optional): If ``True``, checks if :math:`p` and :math:`q` are proper + probability distributions. Defaults to ``False``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be + used in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + Returns: + float: Classical relative entropy between :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. + """ if backend is None: # pragma: no cover backend = GlobalBackend() if isinstance(prob_dist_p, list): - prob_dist_p = backend.cast(prob_dist_p, dtype=float) + # np.float64 is necessary instead of native float because of tensorflow + prob_dist_p = backend.cast(prob_dist_p, dtype=np.float64) if isinstance(prob_dist_q, list): - prob_dist_q = backend.cast(prob_dist_q, dtype=float) + # np.float64 is necessary instead of native float because of tensorflow + prob_dist_q = backend.cast(prob_dist_q, dtype=np.float64) if (len(prob_dist_p.shape) != 1) or (len(prob_dist_q.shape) != 1): raise_error( @@ -266,18 +292,16 @@ def classical_relative_entropy( if base == 2: log_prob_q = np.where(prob_dist_q != 0.0, np.log2(prob_dist_q), -np.inf) - log_prob = np.where(prob_dist_p != 0.0, log_prob_q, 0.0) elif base == 10: log_prob_q = np.where(prob_dist_q != 0.0, np.log10(prob_dist_q), -np.inf) - log_prob = np.where(prob_dist_p != 0, log_prob_q, 0.0) elif base == np.e: log_prob_q = np.where(prob_dist_q != 0.0, np.log(prob_dist_q), -np.inf) - log_prob = np.where(prob_dist_p != 0, log_prob_q, 0.0) else: log_prob_q = np.where( prob_dist_q != 0.0, np.log(prob_dist_q) / np.log(base), -np.inf ) - log_prob = np.where(prob_dist_p != 0, log_prob_q / np.log(base), 0.0) + + log_prob = np.where(prob_dist_p != 0.0, log_prob_q, 0.0) relative = np.sum(prob_dist_p * log_prob) From eaa14050028616962526e8a6f7eb5522772c2e5c Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 12:16:26 +0400 Subject: [PATCH 061/200] tests --- tests/test_quantum_info_entropies.py | 67 +++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 3cc2c43f2f..d78ceca58a 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -2,7 +2,12 @@ import pytest from qibo.config import PRECISION_TOL -from qibo.quantum_info.entropies import entanglement_entropy, entropy, shannon_entropy +from qibo.quantum_info.entropies import ( + classical_relative_entropy, + entanglement_entropy, + entropy, + shannon_entropy, +) from qibo.quantum_info.random_ensembles import random_statevector, random_unitary @@ -168,3 +173,63 @@ def test_entanglement_entropy(backend, bipartition, base, check_hermitian): ) backend.assert_allclose(entang_entrop, 0.0, atol=PRECISION_TOL) + + +@pytest.mark.parametrize("kind", [None, list]) +@pytest.mark.parametrize("validate", [False, True]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +def test_classical_relative_entropy(backend, base, validate, kind): + with pytest.raises(TypeError): + prob = np.random.rand(1, 2) + prob_q = np.random.rand(1, 5) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, backend=backend) + with pytest.raises(TypeError): + prob = np.random.rand(1, 2)[0] + prob_q = np.array([]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, backend=backend) + with pytest.raises(ValueError): + prob = np.array([-1, 2.0]) + prob_q = np.random.rand(1, 5)[0] + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + with pytest.raises(ValueError): + prob = np.random.rand(1, 2)[0] + prob_q = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob_q = np.random.rand(1, 2)[0] + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob_q = np.array([0.0, 1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, base=-2, backend=backend) + + prob_p = np.random.rand(10) + prob_q = np.random.rand(10) + prob_p /= np.sum(prob_p) + prob_q /= np.sum(prob_q) + + target = np.sum(prob_p * np.log(prob_p) / np.log(base)) - np.sum( + prob_p * np.log(prob_q) / np.log(base) + ) + + if kind is not None: + prob_p, prob_q = kind(prob_p), kind(prob_q) + + divergence = classical_relative_entropy( + prob_p, prob_q, base=base, validate=validate, backend=backend + ) + + backend.assert_allclose(divergence, target, atol=1e-5) From 75ec076aee90cc3ca6339e573c888f7f68620516 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 12:27:06 +0400 Subject: [PATCH 062/200] fix lint issues --- src/qibo/quantum_info/entropies.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 8c014c0af6..abdcbcc04d 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -66,12 +66,12 @@ def shannon_entropy(probability_array, base: float = 2, backend=None): probability_array != 0, np.log(probability_array) / np.log(base), 0.0 ) - entropy = -np.sum(probability_array * log_prob) + shan_entropy = -np.sum(probability_array * log_prob) # absolute value if entropy == 0.0 to avoid returning -0.0 - entropy = np.abs(entropy) if entropy == 0.0 else entropy + shan_entropy = np.abs(shan_entropy) if shan_entropy == 0.0 else shan_entropy - return complex(entropy).real + return complex(shan_entropy).real def entropy( @@ -288,7 +288,7 @@ def classical_relative_entropy( if np.abs(np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Second probability array must sum to 1.") - entropy_p = -shannon_entropy(prob_dist_p, base=base, backend=backend) + entropy_p = -1 * shannon_entropy(prob_dist_p, base=base, backend=backend) if base == 2: log_prob_q = np.where(prob_dist_q != 0.0, np.log2(prob_dist_q), -np.inf) From bd8866062927f76244bdd30634b379710fe15ab7 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 14:01:23 +0400 Subject: [PATCH 063/200] api ref --- doc/source/api-reference/qibo.rst | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index efe2a4ef08..73b3fec67b 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1545,11 +1545,31 @@ Entropy .. note:: ``validate`` flag allows the user to choose if the function will check if input ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the - assumption of Hermiticity, because it is faster and, more importantly, - the functions are intended to be used on Hermitian inputs. When ``validate=True`` + assumption of Hermiticity. This is faster and, more importantly, + this function are intended to be used on Hermitian inputs. When ``validate=True`` and ``state`` is non-Hermitian, an error will be raised when using `cupy` backend. +Relative Entropy +"""""""""""""""" + +.. autofunction:: qibo.quantum_info.relative_entropy + +.. note:: + ``validate`` flag allows the user to choose if the function will check if input + ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the + assumption of Hermiticity. This is faster and, more importantly, + this function are intended to be used on Hermitian inputs. When ``validate=True`` + and either ``state`` or ``target`` is non-Hermitian, + an error will be raised when using `cupy` backend. + + +Classical Relative Entropy +"""""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.classical_relative_entropy + + Entanglement Entropy """""""""""""""""""" @@ -1559,8 +1579,8 @@ Entanglement Entropy ``validate`` flag allows the user to choose if the function will check if the reduced density matrix resulting from tracing out ``bipartition`` from input ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the - assumption of Hermiticity, because it is faster and, more importantly, - the functions are intended to be used on Hermitian inputs. When ``validate=True`` + assumption of Hermiticity. This is faster and, more importantly, + this function are intended to be used on Hermitian inputs. When ``validate=True`` and the reduced density matrix is non-Hermitian, an error will be raised when using `cupy` backend. From f951653cb431ec115ab5bab8fe18c1f48ca5fdd1 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 14:01:34 +0400 Subject: [PATCH 064/200] minor changes --- src/qibo/quantum_info/entanglement.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qibo/quantum_info/entanglement.py b/src/qibo/quantum_info/entanglement.py index c2f6eda3f0..7f009e367a 100644 --- a/src/qibo/quantum_info/entanglement.py +++ b/src/qibo/quantum_info/entanglement.py @@ -42,7 +42,7 @@ def concurrence(state, bipartition, check_purity: bool = True, backend=None): f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", ) - if isinstance(check_purity, bool) is False: + if not isinstance(check_purity, bool): raise_error( TypeError, f"check_purity must be type bool, but it is type {type(check_purity)}.", @@ -158,7 +158,7 @@ def entanglement_fidelity( if backend is None: # pragma: no cover backend = GlobalBackend() - if isinstance(nqubits, int) is False: + if not isinstance(nqubits, int): raise_error( TypeError, f"nqubits must be type int, but it is type {type(nqubits)}." ) @@ -178,7 +178,7 @@ def entanglement_fidelity( f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", ) - if isinstance(check_hermitian, bool) is False: + if not isinstance(check_hermitian, bool): raise_error( TypeError, f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", @@ -265,7 +265,7 @@ def entangling_capability(circuit, samples: int, seed=None, backend=None): float: Entangling capability. """ - if isinstance(samples, int) is False: + if not isinstance(samples, int): raise_error( TypeError, f"samples must be type int, but it is type {type(samples)}." ) From 3909820955c2b5882abbd90cfb88f1c3edd9be4f Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 14:01:50 +0400 Subject: [PATCH 065/200] function --- src/qibo/quantum_info/entropies.py | 182 +++++++++++++++++++++-------- 1 file changed, 131 insertions(+), 51 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index abdcbcc04d..7a02c4b6f6 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -119,7 +119,7 @@ def entropy( if base <= 0.0: raise_error(ValueError, "log base must be non-negative.") - if isinstance(check_hermitian, bool) is False: + if not isinstance(check_hermitian, bool): raise_error( TypeError, f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", @@ -131,7 +131,7 @@ def entropy( return 0.0 - if check_hermitian is False or _check_hermitian_or_not_gpu(state, backend=backend): + if not check_hermitian or _check_hermitian_or_not_gpu(state, backend=backend): eigenvalues = np.linalg.eigvalsh(state) else: eigenvalues = np.linalg.eigvals(state) @@ -158,46 +158,14 @@ def entropy( return ent -def entanglement_entropy( - state, - bipartition, - base: float = 2, - check_hermitian: bool = False, - return_spectrum: bool = False, - backend=None, +def relative_entropy( + state, target, base: float = 2, check_hermitian: bool = False, backend=None ): - """Calculates the entanglement entropy :math:`S` of bipartition :math:`A` - of ``state`` :math:`\\rho`. This is given by - - .. math:: - S(\\rho_{A}) = -\\text{tr}(\\rho_{A} \\, \\log(\\rho_{A})) \\, , - - where :math:`\\rho_{A} = \\text{tr}_{B}(\\rho)` is the reduced density matrix calculated - by tracing out the ``bipartition`` :math:`B`. - - Args: - state (ndarray): statevector or density matrix. - bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. - base (float, optional): the base of the log. Defaults to :math: `2`. - check_hermitian (bool, optional): if ``True``, checks if :math:`\\rho_{A}` is Hermitian. - If ``False``, it assumes ``state`` is Hermitian . Default: ``False``. - return_spectrum: if ``True``, returns ``entropy`` and eigenvalues of ``state``. - If ``False``, returns only ``entropy``. Default is ``False``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. - - Returns: - float: Entanglement entropy :math:`S` of ``state`` :math:`\\rho`. - """ if backend is None: # pragma: no cover backend = GlobalBackend() - if base <= 0.0: - raise_error(ValueError, "log base must be non-negative.") - if ( - (len(state.shape) not in [1, 2]) + (len(state.shape) >= 3) or (len(state) == 0) or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) ): @@ -206,23 +174,68 @@ def entanglement_entropy( f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", ) - nqubits = int(np.log2(state.shape[0])) + if ( + (len(target.shape) >= 3) + or (len(target) == 0) + or (len(target.shape) == 2 and target.shape[0] != target.shape[1]) + ): + raise_error( + TypeError, + f"target must have dims either (k,) or (k,k), but have dims {target.shape}.", + ) - reduced_density_matrix = ( - backend.partial_trace(state, bipartition, nqubits) - if len(state.shape) == 1 - else backend.partial_trace_density_matrix(state, bipartition, nqubits) - ) + if base <= 0.0: + raise_error(ValueError, "log base must be non-negative.") - entropy_entanglement = entropy( - reduced_density_matrix, - base=base, - check_hermitian=check_hermitian, - return_spectrum=return_spectrum, - backend=backend, - ) + if not isinstance(check_hermitian, bool): + raise_error( + TypeError, + f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", + ) - return entropy_entanglement + if purity(state) == 1.0 and purity(target) == 1.0: + return 0.0 + + if not check_hermitian or _check_hermitian_or_not_gpu(state, backend=backend): + eigenvalues_state = np.linalg.eigvalsh(state) + else: + eigenvalues_state = np.linalg.eigvals(state) + + if not check_hermitian or _check_hermitian_or_not_gpu(target, backend=backend): + eigenvalues_target = np.linalg.eigvalsh(target) + else: + eigenvalues_target = np.linalg.eigvals(target) + + if base == 2: + log_state = np.where(eigenvalues_state > 0, np.log2(eigenvalues_state), 0.0) + log_target = np.where( + eigenvalues_target > 0, np.log2(eigenvalues_target), -np.inf + ) + elif base == 10: + log_state = np.where(eigenvalues_state > 0, np.log10(eigenvalues_state), 0.0) + log_target = np.where( + eigenvalues_target > 0, np.log10(eigenvalues_target), -np.inf + ) + elif base == np.e: + log_state = np.where(eigenvalues_state > 0, np.log(eigenvalues_state), 0.0) + log_target = np.where( + eigenvalues_target > 0, np.log(eigenvalues_target), -np.inf + ) + else: + log_state = np.where( + eigenvalues_state > 0, np.log(eigenvalues_state) / np.log(base), 0.0 + ) + log_target = np.where( + eigenvalues_target > 0, np.log(eigenvalues_target) / np.log(base), -np.inf + ) + + log_target = np.where(eigenvalues_state != 0.0, log_target, 0.0) + + entropy_state = np.sum(eigenvalues_state * log_state) + + relative = np.sum(eigenvalues_state * log_target) + + return float(entropy_state - relative) def classical_relative_entropy( @@ -306,3 +319,70 @@ def classical_relative_entropy( relative = np.sum(prob_dist_p * log_prob) return entropy_p - relative + + +def entanglement_entropy( + state, + bipartition, + base: float = 2, + check_hermitian: bool = False, + return_spectrum: bool = False, + backend=None, +): + """Calculates the entanglement entropy :math:`S` of bipartition :math:`A` + of ``state`` :math:`\\rho`. This is given by + + .. math:: + S(\\rho_{A}) = -\\text{tr}(\\rho_{A} \\, \\log(\\rho_{A})) \\, , + + where :math:`\\rho_{A} = \\text{tr}_{B}(\\rho)` is the reduced density matrix calculated + by tracing out the ``bipartition`` :math:`B`. + + Args: + state (ndarray): statevector or density matrix. + bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. + base (float, optional): the base of the log. Defaults to :math: `2`. + check_hermitian (bool, optional): if ``True``, checks if :math:`\\rho_{A}` is Hermitian. + If ``False``, it assumes ``state`` is Hermitian . Default: ``False``. + return_spectrum: if ``True``, returns ``entropy`` and eigenvalues of ``state``. + If ``False``, returns only ``entropy``. Default is ``False``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Entanglement entropy :math:`S` of ``state`` :math:`\\rho`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if base <= 0.0: + raise_error(ValueError, "log base must be non-negative.") + + if ( + (len(state.shape) not in [1, 2]) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + nqubits = int(np.log2(state.shape[0])) + + reduced_density_matrix = ( + backend.partial_trace(state, bipartition, nqubits) + if len(state.shape) == 1 + else backend.partial_trace_density_matrix(state, bipartition, nqubits) + ) + + entropy_entanglement = entropy( + reduced_density_matrix, + base=base, + check_hermitian=check_hermitian, + return_spectrum=return_spectrum, + backend=backend, + ) + + return entropy_entanglement From 373f81c2d9fdf51c0475ff08c830aa04360a9b09 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 14:01:54 +0400 Subject: [PATCH 066/200] tests --- tests/test_quantum_info_entropies.py | 172 ++++++++++++++++++--------- 1 file changed, 114 insertions(+), 58 deletions(-) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index d78ceca58a..2ef5689ee4 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -6,9 +6,14 @@ classical_relative_entropy, entanglement_entropy, entropy, + relative_entropy, shannon_entropy, ) -from qibo.quantum_info.random_ensembles import random_statevector, random_unitary +from qibo.quantum_info.random_ensembles import ( + random_density_matrix, + random_statevector, + random_unitary, +) def test_shannon_entropy_errors(backend): @@ -103,77 +108,54 @@ def test_entropy(backend, base, check_hermitian): @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) -@pytest.mark.parametrize("bipartition", [[0], [1]]) -def test_entanglement_entropy(backend, bipartition, base, check_hermitian): +def test_relative_entropy(backend, base, check_hermitian): with pytest.raises(TypeError): state = np.random.rand(2, 3) state = backend.cast(state, dtype=state.dtype) - test = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=check_hermitian, - backend=backend, + target = random_density_matrix(2, pure=True, backend=backend) + test = relative_entropy( + state, target, base=base, check_hermitian=check_hermitian, backend=backend + ) + with pytest.raises(TypeError): + target = np.random.rand(2, 3) + target = backend.cast(target, dtype=target.dtype) + state = random_density_matrix(2, pure=True, backend=backend) + test = relative_entropy( + state, target, base=base, check_hermitian=check_hermitian, backend=backend ) with pytest.raises(ValueError): state = np.array([1.0, 0.0]) state = backend.cast(state, dtype=state.dtype) - test = entanglement_entropy( - state, - bipartition=bipartition, - base=0, - check_hermitian=check_hermitian, - backend=backend, + target = np.array([0.0, 1.0]) + target = backend.cast(target, dtype=target.dtype) + test = relative_entropy( + state, target, base=0, check_hermitian=check_hermitian, backend=backend + ) + with pytest.raises(TypeError): + state = np.array([1.0, 0.0]) + state = backend.cast(state, dtype=state.dtype) + target = np.array([0.0, 1.0]) + target = backend.cast(target, dtype=target.dtype) + test = relative_entropy( + state, target, base=base, check_hermitian="False", backend=backend ) - if backend.__class__.__name__ == "CupyBackend": - with pytest.raises(NotImplementedError): - state = random_unitary(4, backend=backend) - test = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=True, - backend=backend, - ) - - # Bell state - state = np.array([1.0, 0.0, 0.0, 1.0]) / np.sqrt(2) - state = backend.cast(state, dtype=state.dtype) - - entang_entrop = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=check_hermitian, - backend=backend, - ) - if base == 2: - test = 1.0 - elif base == 10: - test = 0.30102999566398125 - elif base == np.e: - test = 0.6931471805599454 - else: - test = 0.4306765580733931 + nqubits = 2 + dims = 2**nqubits - backend.assert_allclose(entang_entrop, test, atol=PRECISION_TOL) + state = random_density_matrix(dims, backend=backend) + target = backend.identity_density_matrix(nqubits, normalize=True) - # Product state - state = np.kron( - random_statevector(2, backend=backend), random_statevector(2, backend=backend) - ) + print(relative_entropy(state, target, base, check_hermitian, backend)) + print(entropy(state, base, check_hermitian=check_hermitian, backend=backend)) - entang_entrop = entanglement_entropy( - state, - bipartition=bipartition, - base=base, - check_hermitian=check_hermitian, - backend=backend, + backend.assert_allclose( + relative_entropy(state, target, base, check_hermitian, backend), + np.log(dims) / np.log(base) + - entropy(state, base=base, check_hermitian=check_hermitian, backend=backend), + atol=1e-5, ) - backend.assert_allclose(entang_entrop, 0.0, atol=PRECISION_TOL) - @pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("validate", [False, True]) @@ -233,3 +215,77 @@ def test_classical_relative_entropy(backend, base, validate, kind): ) backend.assert_allclose(divergence, target, atol=1e-5) + + +@pytest.mark.parametrize("check_hermitian", [False, True]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("bipartition", [[0], [1]]) +def test_entanglement_entropy(backend, bipartition, base, check_hermitian): + with pytest.raises(TypeError): + state = np.random.rand(2, 3) + state = backend.cast(state, dtype=state.dtype) + test = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=check_hermitian, + backend=backend, + ) + with pytest.raises(ValueError): + state = np.array([1.0, 0.0]) + state = backend.cast(state, dtype=state.dtype) + test = entanglement_entropy( + state, + bipartition=bipartition, + base=0, + check_hermitian=check_hermitian, + backend=backend, + ) + if backend.__class__.__name__ == "CupyBackend": + with pytest.raises(NotImplementedError): + state = random_unitary(4, backend=backend) + test = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=True, + backend=backend, + ) + + # Bell state + state = np.array([1.0, 0.0, 0.0, 1.0]) / np.sqrt(2) + state = backend.cast(state, dtype=state.dtype) + + entang_entrop = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=check_hermitian, + backend=backend, + ) + + if base == 2: + test = 1.0 + elif base == 10: + test = 0.30102999566398125 + elif base == np.e: + test = 0.6931471805599454 + else: + test = 0.4306765580733931 + + backend.assert_allclose(entang_entrop, test, atol=PRECISION_TOL) + + # Product state + state = np.kron( + random_statevector(2, backend=backend), random_statevector(2, backend=backend) + ) + + entang_entrop = entanglement_entropy( + state, + bipartition=bipartition, + base=base, + check_hermitian=check_hermitian, + backend=backend, + ) + + backend.assert_allclose(entang_entrop, 0.0, atol=PRECISION_TOL) From 8c0d8758171dde1fce05da7891f726c51afc269b Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 14:19:39 +0400 Subject: [PATCH 067/200] docstring --- src/qibo/quantum_info/entropies.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 7a02c4b6f6..2f9e0a03a5 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -81,8 +81,9 @@ def entropy( return_spectrum: bool = False, backend=None, ): - """The von-Neumann entropy :math:`S(\\rho)` of a quantum ``state`` :math:`\\rho`, which - is given by + """Calculates the von-Neumann entropy :math:`S(\\rho)` of a quantum ``state`` :math:`\\rho`. + + It is given by .. math:: S(\\rho) = - \\text{tr}\\left[\\rho \\, \\log(\\rho)\\right] @@ -161,6 +162,28 @@ def entropy( def relative_entropy( state, target, base: float = 2, check_hermitian: bool = False, backend=None ): + """Calculates the relative entropy :math:`S(\\rho \\, \\| \\, \\sigma)` between ``state`` :math:`\\rho` and ``target`` :math:`\\sigma`. + + It is given by + + .. math:: + S(\\rho \\, \\| \\, \\sigma) = \\text{tr}\\left[\\rho \\, \\log(\\rho)\\right] + - \\text{tr}\\left[\\rho \\, \\log(\\sigma)\\right] + + Args: + state (ndarray): statevector or density matrix :math:`\\rho`. + target (ndarray): statevector or density matrix :math:`\\sigma`. + base (float, optional): the base of the log. Defaults to :math:`2`. + check_hermitian (bool, optional): If ``True``, checks if ``state`` is Hermitian. + If ``False``, it assumes ``state`` is Hermitian . + Defaults to ``False``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Relative (von-Neumann) entropy :math:`S(\\rho \\, \\| \\, \\sigma)`. + """ if backend is None: # pragma: no cover backend = GlobalBackend() From 8cc2ade0719f5ec408f99bab11c4899e291c5e08 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 14:35:11 +0400 Subject: [PATCH 068/200] fix coverage --- tests/test_quantum_info_entropies.py | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 2ef5689ee4..cd5cce3362 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -146,9 +146,6 @@ def test_relative_entropy(backend, base, check_hermitian): state = random_density_matrix(dims, backend=backend) target = backend.identity_density_matrix(nqubits, normalize=True) - print(relative_entropy(state, target, base, check_hermitian, backend)) - print(entropy(state, base, check_hermitian=check_hermitian, backend=backend)) - backend.assert_allclose( relative_entropy(state, target, base, check_hermitian, backend), np.log(dims) / np.log(base) @@ -156,6 +153,32 @@ def test_relative_entropy(backend, base, check_hermitian): atol=1e-5, ) + state = backend.cast([1.0, 0.0], dtype=np.float64) + target = backend.cast([0.0, 1.0], dtype=np.float64) + + assert relative_entropy(state, target, backend=backend) == 0.0 + + # for coverage when GPUs are present + if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + with pytest.raises(NotImplementedError): + state = random_unitary(4, backend=backend) + target = random_density_matrix(4, backend=backend) + test = relative_entropy( + state, target, base=base, check_hermitian=True, backend=backend + ) + with pytest.raises(NotImplementedError): + target = random_unitary(4, backend=backend) + state = random_density_matrix(4, backend=backend) + test = relative_entropy( + state, target, base=base, check_hermitian=True, backend=backend + ) + else: + state = random_unitary(4, backend=backend) + target = random_unitary(4, backend=backend) + test = relative_entropy( + state, target, base=base, check_hermitian=True, backend=backend + ) + @pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("validate", [False, True]) From 1815adc31c1a9163f360f6146b9d87cb6cb95a4e Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 15:14:34 +0400 Subject: [PATCH 069/200] reorder functions --- doc/source/api-reference/qibo.rst | 12 +- src/qibo/quantum_info/entropies.py | 166 +++++++++++++-------------- tests/test_quantum_info_entropies.py | 120 +++++++++---------- 3 files changed, 149 insertions(+), 149 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 73b3fec67b..fb1c5df5dd 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1537,6 +1537,12 @@ Shannon entropy .. autofunction:: qibo.quantum_info.shannon_entropy +Classical Relative Entropy +"""""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.classical_relative_entropy + + Entropy """"""" @@ -1564,12 +1570,6 @@ Relative Entropy an error will be raised when using `cupy` backend. -Classical Relative Entropy -"""""""""""""""""""""""""" - -.. autofunction:: qibo.quantum_info.classical_relative_entropy - - Entanglement Entropy """""""""""""""""""" diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 2f9e0a03a5..058b7e4a15 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -74,6 +74,89 @@ def shannon_entropy(probability_array, base: float = 2, backend=None): return complex(shan_entropy).real +def classical_relative_entropy( + prob_dist_p, prob_dist_q, base: float = 2, validate: bool = False, backend=None +): + """Calculates the relative entropy between two discrete probability distributions. + + For probabilities :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, it is defined as + + ..math:: + D(\\mathbf{p} \\, \\| \\, \\mathbf{q}) = \\sum_{x} \\, \\mathbf{p}(x) \\, + \\log\\left( \\frac{\\mathbf{p}(x)}{\\mathbf{q}(x)} \\right) \\, . + + The classical relative entropy is also known as the + `Kullback-Leibler (KL) divergence `_. + + Args: + prob_dist_p (ndarray or list): discrete probability distribution :math:`p`. + prob_dist_q (ndarray or list): discrete probability distribution :math:`q`. + base (float): the base of the log. Defaults to :math:`2`. + validate (bool, optional): If ``True``, checks if :math:`p` and :math:`q` are proper + probability distributions. Defaults to ``False``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be + used in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + Returns: + float: Classical relative entropy between :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if isinstance(prob_dist_p, list): + # np.float64 is necessary instead of native float because of tensorflow + prob_dist_p = backend.cast(prob_dist_p, dtype=np.float64) + if isinstance(prob_dist_q, list): + # np.float64 is necessary instead of native float because of tensorflow + prob_dist_q = backend.cast(prob_dist_q, dtype=np.float64) + + if (len(prob_dist_p.shape) != 1) or (len(prob_dist_q.shape) != 1): + raise_error( + TypeError, + "Probability arrays must have dims (k,) but have " + + f"dims {prob_dist_p.shape} and {prob_dist_q.shape}.", + ) + + if (len(prob_dist_p) == 0) or (len(prob_dist_q) == 0): + raise_error(TypeError, "At least one of the arrays is empty.") + + if base <= 0: + raise_error(ValueError, "log base must be non-negative.") + + if validate: + if (any(prob_dist_p < 0) or any(prob_dist_p > 1.0)) or ( + any(prob_dist_q < 0) or any(prob_dist_q > 1.0) + ): + raise_error( + ValueError, + "All elements of the probability array must be between 0. and 1..", + ) + if np.abs(np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "First probability array must sum to 1.") + + if np.abs(np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "Second probability array must sum to 1.") + + entropy_p = -1 * shannon_entropy(prob_dist_p, base=base, backend=backend) + + if base == 2: + log_prob_q = np.where(prob_dist_q != 0.0, np.log2(prob_dist_q), -np.inf) + elif base == 10: + log_prob_q = np.where(prob_dist_q != 0.0, np.log10(prob_dist_q), -np.inf) + elif base == np.e: + log_prob_q = np.where(prob_dist_q != 0.0, np.log(prob_dist_q), -np.inf) + else: + log_prob_q = np.where( + prob_dist_q != 0.0, np.log(prob_dist_q) / np.log(base), -np.inf + ) + + log_prob = np.where(prob_dist_p != 0.0, log_prob_q, 0.0) + + relative = np.sum(prob_dist_p * log_prob) + + return entropy_p - relative + + def entropy( state, base: float = 2, @@ -261,89 +344,6 @@ def relative_entropy( return float(entropy_state - relative) -def classical_relative_entropy( - prob_dist_p, prob_dist_q, base: float = 2, validate: bool = False, backend=None -): - """Calculates the relative entropy between two discrete probability distributions. - - For probabilities :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, it is defined as - - ..math:: - D(\\mathbf{p} \\, \\| \\, \\mathbf{q}) = \\sum_{x} \\, \\mathbf{p}(x) \\, - \\log\\left( \\frac{\\mathbf{p}(x)}{\\mathbf{q}(x)} \\right) \\, . - - The classical relative entropy is also known as the - `Kullback-Leibler (KL) divergence `_. - - Args: - prob_dist_p (ndarray or list): discrete probability distribution :math:`p`. - prob_dist_q (ndarray or list): discrete probability distribution :math:`q`. - base (float): the base of the log. Defaults to :math:`2`. - validate (bool, optional): If ``True``, checks if :math:`p` and :math:`q` are proper - probability distributions. Defaults to ``False``. - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be - used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. - Returns: - float: Classical relative entropy between :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. - """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - - if isinstance(prob_dist_p, list): - # np.float64 is necessary instead of native float because of tensorflow - prob_dist_p = backend.cast(prob_dist_p, dtype=np.float64) - if isinstance(prob_dist_q, list): - # np.float64 is necessary instead of native float because of tensorflow - prob_dist_q = backend.cast(prob_dist_q, dtype=np.float64) - - if (len(prob_dist_p.shape) != 1) or (len(prob_dist_q.shape) != 1): - raise_error( - TypeError, - "Probability arrays must have dims (k,) but have " - + f"dims {prob_dist_p.shape} and {prob_dist_q.shape}.", - ) - - if (len(prob_dist_p) == 0) or (len(prob_dist_q) == 0): - raise_error(TypeError, "At least one of the arrays is empty.") - - if base <= 0: - raise_error(ValueError, "log base must be non-negative.") - - if validate: - if (any(prob_dist_p < 0) or any(prob_dist_p > 1.0)) or ( - any(prob_dist_q < 0) or any(prob_dist_q > 1.0) - ): - raise_error( - ValueError, - "All elements of the probability array must be between 0. and 1..", - ) - if np.abs(np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: - raise_error(ValueError, "First probability array must sum to 1.") - - if np.abs(np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: - raise_error(ValueError, "Second probability array must sum to 1.") - - entropy_p = -1 * shannon_entropy(prob_dist_p, base=base, backend=backend) - - if base == 2: - log_prob_q = np.where(prob_dist_q != 0.0, np.log2(prob_dist_q), -np.inf) - elif base == 10: - log_prob_q = np.where(prob_dist_q != 0.0, np.log10(prob_dist_q), -np.inf) - elif base == np.e: - log_prob_q = np.where(prob_dist_q != 0.0, np.log(prob_dist_q), -np.inf) - else: - log_prob_q = np.where( - prob_dist_q != 0.0, np.log(prob_dist_q) / np.log(base), -np.inf - ) - - log_prob = np.where(prob_dist_p != 0.0, log_prob_q, 0.0) - - relative = np.sum(prob_dist_p * log_prob) - - return entropy_p - relative - - def entanglement_entropy( state, bipartition, diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index cd5cce3362..fc6d56ace6 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -56,6 +56,66 @@ def test_shannon_entropy(backend, base): backend.assert_allclose(result, 1.0) +@pytest.mark.parametrize("kind", [None, list]) +@pytest.mark.parametrize("validate", [False, True]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +def test_classical_relative_entropy(backend, base, validate, kind): + with pytest.raises(TypeError): + prob = np.random.rand(1, 2) + prob_q = np.random.rand(1, 5) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, backend=backend) + with pytest.raises(TypeError): + prob = np.random.rand(1, 2)[0] + prob_q = np.array([]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, backend=backend) + with pytest.raises(ValueError): + prob = np.array([-1, 2.0]) + prob_q = np.random.rand(1, 5)[0] + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + with pytest.raises(ValueError): + prob = np.random.rand(1, 2)[0] + prob_q = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob_q = np.random.rand(1, 2)[0] + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob_q = np.array([0.0, 1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_relative_entropy(prob, prob_q, base=-2, backend=backend) + + prob_p = np.random.rand(10) + prob_q = np.random.rand(10) + prob_p /= np.sum(prob_p) + prob_q /= np.sum(prob_q) + + target = np.sum(prob_p * np.log(prob_p) / np.log(base)) - np.sum( + prob_p * np.log(prob_q) / np.log(base) + ) + + if kind is not None: + prob_p, prob_q = kind(prob_p), kind(prob_q) + + divergence = classical_relative_entropy( + prob_p, prob_q, base=base, validate=validate, backend=backend + ) + + backend.assert_allclose(divergence, target, atol=1e-5) + + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) def test_entropy(backend, base, check_hermitian): @@ -180,66 +240,6 @@ def test_relative_entropy(backend, base, check_hermitian): ) -@pytest.mark.parametrize("kind", [None, list]) -@pytest.mark.parametrize("validate", [False, True]) -@pytest.mark.parametrize("base", [2, 10, np.e, 5]) -def test_classical_relative_entropy(backend, base, validate, kind): - with pytest.raises(TypeError): - prob = np.random.rand(1, 2) - prob_q = np.random.rand(1, 5) - prob = backend.cast(prob, dtype=prob.dtype) - prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, backend=backend) - with pytest.raises(TypeError): - prob = np.random.rand(1, 2)[0] - prob_q = np.array([]) - prob = backend.cast(prob, dtype=prob.dtype) - prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, backend=backend) - with pytest.raises(ValueError): - prob = np.array([-1, 2.0]) - prob_q = np.random.rand(1, 5)[0] - prob = backend.cast(prob, dtype=prob.dtype) - prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) - with pytest.raises(ValueError): - prob = np.random.rand(1, 2)[0] - prob_q = np.array([1.0, 0.0]) - prob = backend.cast(prob, dtype=prob.dtype) - prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) - with pytest.raises(ValueError): - prob = np.array([1.0, 0.0]) - prob_q = np.random.rand(1, 2)[0] - prob = backend.cast(prob, dtype=prob.dtype) - prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) - with pytest.raises(ValueError): - prob = np.array([1.0, 0.0]) - prob_q = np.array([0.0, 1.0]) - prob = backend.cast(prob, dtype=prob.dtype) - prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, base=-2, backend=backend) - - prob_p = np.random.rand(10) - prob_q = np.random.rand(10) - prob_p /= np.sum(prob_p) - prob_q /= np.sum(prob_q) - - target = np.sum(prob_p * np.log(prob_p) / np.log(base)) - np.sum( - prob_p * np.log(prob_q) / np.log(base) - ) - - if kind is not None: - prob_p, prob_q = kind(prob_p), kind(prob_q) - - divergence = classical_relative_entropy( - prob_p, prob_q, base=base, validate=validate, backend=backend - ) - - backend.assert_allclose(divergence, target, atol=1e-5) - - @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("bipartition", [[0], [1]]) From d7f885cc5a5dbeabdd05c6e7e61a1fae44728f08 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 15:59:28 +0400 Subject: [PATCH 070/200] api ref --- doc/source/api-reference/qibo.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index fb1c5df5dd..5f80e763c1 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1543,6 +1543,12 @@ Classical Relative Entropy .. autofunction:: qibo.quantum_info.classical_relative_entropy +Classical Rényi Entropy +""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.classical_renyi_entropy + + Entropy """"""" @@ -1570,6 +1576,12 @@ Relative Entropy an error will be raised when using `cupy` backend. +Rényi Entropy +""""""""""""" + +.. autofunction:: qibo.quantum_info.renyi_entropy + + Entanglement Entropy """""""""""""""""""" From 935d87fd172d27d41a102bfbcf9e4ca712ac9e09 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 15:59:38 +0400 Subject: [PATCH 071/200] classical renyi entropy --- src/qibo/quantum_info/entropies.py | 139 ++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 33 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 058b7e4a15..6d3492d45d 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -7,7 +7,7 @@ from qibo.quantum_info.metrics import _check_hermitian_or_not_gpu, purity -def shannon_entropy(probability_array, base: float = 2, backend=None): +def shannon_entropy(prob_dist, base: float = 2, backend=None): """Calculate the Shannon entropy of a probability array :math:`\\mathbf{p}`, which is given by .. math:: @@ -18,7 +18,7 @@ def shannon_entropy(probability_array, base: float = 2, backend=None): and :math:`0 \\log_{b}(0) \\equiv 0`. Args: - probability_array (ndarray or list): a probability array :math:`\\mathbf{p}`. + prob_dist (ndarray or list): a probability array :math:`\\mathbf{p}`. base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. @@ -30,43 +30,41 @@ def shannon_entropy(probability_array, base: float = 2, backend=None): if backend is None: # pragma: no cover backend = GlobalBackend() - if isinstance(probability_array, list): + if isinstance(prob_dist, list): # np.float64 is necessary instead of native float because of tensorflow - probability_array = backend.cast(probability_array, dtype=np.float64) + prob_dist = backend.cast(prob_dist, dtype=np.float64) if base <= 0: raise_error(ValueError, "log base must be non-negative.") - if len(probability_array.shape) != 1: + if len(prob_dist.shape) != 1: raise_error( TypeError, - f"Probability array must have dims (k,) but it has {probability_array.shape}.", + f"Probability array must have dims (k,) but it has {prob_dist.shape}.", ) - if len(probability_array) == 0: + if len(prob_dist) == 0: raise_error(TypeError, "Empty array.") - if any(probability_array < 0) or any(probability_array > 1.0): + if any(prob_dist < 0) or any(prob_dist > 1.0): raise_error( ValueError, "All elements of the probability array must be between 0. and 1..", ) - if np.abs(np.sum(probability_array) - 1.0) > PRECISION_TOL: + if np.abs(np.sum(prob_dist) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Probability array must sum to 1.") if base == 2: - log_prob = np.where(probability_array != 0.0, np.log2(probability_array), 0.0) + log_prob = np.where(prob_dist != 0.0, np.log2(prob_dist), 0.0) elif base == 10: - log_prob = np.where(probability_array != 0, np.log10(probability_array), 0.0) + log_prob = np.where(prob_dist != 0, np.log10(prob_dist), 0.0) elif base == np.e: - log_prob = np.where(probability_array != 0, np.log(probability_array), 0.0) + log_prob = np.where(prob_dist != 0, np.log(prob_dist), 0.0) else: - log_prob = np.where( - probability_array != 0, np.log(probability_array) / np.log(base), 0.0 - ) + log_prob = np.where(prob_dist != 0, np.log(prob_dist) / np.log(base), 0.0) - shan_entropy = -np.sum(probability_array * log_prob) + shan_entropy = -np.sum(prob_dist * log_prob) # absolute value if entropy == 0.0 to avoid returning -0.0 shan_entropy = np.abs(shan_entropy) if shan_entropy == 0.0 else shan_entropy @@ -74,9 +72,7 @@ def shannon_entropy(probability_array, base: float = 2, backend=None): return complex(shan_entropy).real -def classical_relative_entropy( - prob_dist_p, prob_dist_q, base: float = 2, validate: bool = False, backend=None -): +def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backend=None): """Calculates the relative entropy between two discrete probability distributions. For probabilities :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, it is defined as @@ -92,11 +88,10 @@ def classical_relative_entropy( prob_dist_p (ndarray or list): discrete probability distribution :math:`p`. prob_dist_q (ndarray or list): discrete probability distribution :math:`q`. base (float): the base of the log. Defaults to :math:`2`. - validate (bool, optional): If ``True``, checks if :math:`p` and :math:`q` are proper - probability distributions. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + Returns: float: Classical relative entropy between :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. """ @@ -123,19 +118,18 @@ def classical_relative_entropy( if base <= 0: raise_error(ValueError, "log base must be non-negative.") - if validate: - if (any(prob_dist_p < 0) or any(prob_dist_p > 1.0)) or ( - any(prob_dist_q < 0) or any(prob_dist_q > 1.0) - ): - raise_error( - ValueError, - "All elements of the probability array must be between 0. and 1..", - ) - if np.abs(np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: - raise_error(ValueError, "First probability array must sum to 1.") + if (any(prob_dist_p < 0) or any(prob_dist_p > 1.0)) or ( + any(prob_dist_q < 0) or any(prob_dist_q > 1.0) + ): + raise_error( + ValueError, + "All elements of the probability array must be between 0. and 1..", + ) + if np.abs(np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "First probability array must sum to 1.") - if np.abs(np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: - raise_error(ValueError, "Second probability array must sum to 1.") + if np.abs(np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "Second probability array must sum to 1.") entropy_p = -1 * shannon_entropy(prob_dist_p, base=base, backend=backend) @@ -157,6 +151,85 @@ def classical_relative_entropy( return entropy_p - relative +def classical_renyi_entropy(prob_dist, alpha: float, base: float = 2, backend=None): + """Calculates the classical Rényi entropy :math:`H_{\\alpha}` of a discrete probability distribution. + + For :math:`\\alpha \\in (0, \\, 1) \\cup (1, \\, \\infty)` and probability distribution + :math:`\\mathbf{p}`, the Rényi entropy is defined as + + .. math:: + H_{\\alpha}(\\mathbf{p}) = \\frac{1}{1 - \\alpha} \\, \\log\\left( \\sum_{x} + \\, \\mathbf{p}^{\\alpha}(x) \\right) \\, . + + For :math:`\\alpha \\in \\{0, 1, \\infty \\}`, it is further defined that + + .. math:: + H_{\\alpha}(\\mathbf{p}) = \\lim_{\\beta \\to \\alpha} \\, H_{\\beta}(\\mathbf{p}) \\, . + + A special case is the limit :math:`\\alpha \\to 1`, in which the classical Rényi entropy + coincides with the :func:`qibo.quantum_info.entropies.shannon_entropy`. + + Args: + prob_dist (ndarray): discrete probability distribution. + alpha (float): order of the Rényi entropy. + If :math:`\\alpha = 1`, defaults to :func:`qibo.quantum_info.entropies.shannon_entropy`. + If :math:`\\alpha = \\infty`, defaults to the + `min-entropy `_. + base (float): the base of the log. Defaults to :math:`2`. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be + used in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Rényi entropy :math:`H_{\\alpha}`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if isinstance(prob_dist, list): + # np.float64 is necessary instead of native float because of tensorflow + prob_dist = backend.cast(prob_dist, dtype=np.float64) + + if not isinstance(alpha, float): + raise_error( + TypeError, f"alpha must be type float, but it is type {type(alpha)}." + ) + + if alpha < 0.0: + raise_error(ValueError, "alpha must a non-negative float.") + + if base <= 0: + raise_error(ValueError, "log base must be non-negative.") + + if len(prob_dist.shape) != 1: + raise_error( + TypeError, + f"Probability array must have dims (k,) but it has {prob_dist.shape}.", + ) + + if len(prob_dist) == 0: + raise_error(TypeError, "Empty array.") + + if any(prob_dist < 0) or any(prob_dist > 1.0): + raise_error( + ValueError, + "All elements of the probability array must be between 0. and 1..", + ) + + if np.abs(np.sum(prob_dist) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "Probability array must sum to 1.") + + if alpha == 1.0: + return shannon_entropy(prob_dist, base=base, backend=backend) + + if alpha == np.inf: + return -1 * np.log2(max(prob_dist)) / np.log2(base) + + renyi_ent = (1 / (1 - alpha)) * np.log2(np.sum(prob_dist**alpha)) / np.log2(base) + + return renyi_ent + + def entropy( state, base: float = 2, From cb799bd281230f5f5da805e7d5d18587d1bf2634 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 15:59:48 +0400 Subject: [PATCH 072/200] remove variable --- tests/test_quantum_info_entropies.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index fc6d56ace6..392d4b108b 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -57,9 +57,8 @@ def test_shannon_entropy(backend, base): @pytest.mark.parametrize("kind", [None, list]) -@pytest.mark.parametrize("validate", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) -def test_classical_relative_entropy(backend, base, validate, kind): +def test_classical_relative_entropy(backend, base, kind): with pytest.raises(TypeError): prob = np.random.rand(1, 2) prob_q = np.random.rand(1, 5) @@ -77,19 +76,19 @@ def test_classical_relative_entropy(backend, base, validate, kind): prob_q = np.random.rand(1, 5)[0] prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + test = classical_relative_entropy(prob, prob_q, backend=backend) with pytest.raises(ValueError): prob = np.random.rand(1, 2)[0] prob_q = np.array([1.0, 0.0]) prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + test = classical_relative_entropy(prob, prob_q, backend=backend) with pytest.raises(ValueError): prob = np.array([1.0, 0.0]) prob_q = np.random.rand(1, 2)[0] prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_relative_entropy(prob, prob_q, validate=True, backend=backend) + test = classical_relative_entropy(prob, prob_q, backend=backend) with pytest.raises(ValueError): prob = np.array([1.0, 0.0]) prob_q = np.array([0.0, 1.0]) @@ -109,9 +108,7 @@ def test_classical_relative_entropy(backend, base, validate, kind): if kind is not None: prob_p, prob_q = kind(prob_p), kind(prob_q) - divergence = classical_relative_entropy( - prob_p, prob_q, base=base, validate=validate, backend=backend - ) + divergence = classical_relative_entropy(prob_p, prob_q, base=base, backend=backend) backend.assert_allclose(divergence, target, atol=1e-5) From e3474901f669a8bd17a04af0a7fe16972f1ac8e4 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 17:23:09 +0400 Subject: [PATCH 073/200] test errors --- src/qibo/quantum_info/entropies.py | 9 ++++-- tests/test_quantum_info_entropies.py | 43 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 6d3492d45d..ec869ba9c9 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -1,4 +1,5 @@ """Submodule with entropy measures.""" +from typing import Union import numpy as np @@ -151,7 +152,9 @@ def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backen return entropy_p - relative -def classical_renyi_entropy(prob_dist, alpha: float, base: float = 2, backend=None): +def classical_renyi_entropy( + prob_dist, alpha: Union[float, int], base: float = 2, backend=None +): """Calculates the classical Rényi entropy :math:`H_{\\alpha}` of a discrete probability distribution. For :math:`\\alpha \\in (0, \\, 1) \\cup (1, \\, \\infty)` and probability distribution @@ -171,7 +174,7 @@ def classical_renyi_entropy(prob_dist, alpha: float, base: float = 2, backend=No Args: prob_dist (ndarray): discrete probability distribution. - alpha (float): order of the Rényi entropy. + alpha (float or int): order of the Rényi entropy. If :math:`\\alpha = 1`, defaults to :func:`qibo.quantum_info.entropies.shannon_entropy`. If :math:`\\alpha = \\infty`, defaults to the `min-entropy `_. @@ -190,7 +193,7 @@ def classical_renyi_entropy(prob_dist, alpha: float, base: float = 2, backend=No # np.float64 is necessary instead of native float because of tensorflow prob_dist = backend.cast(prob_dist, dtype=np.float64) - if not isinstance(alpha, float): + if not isinstance(alpha, (float, int)): raise_error( TypeError, f"alpha must be type float, but it is type {type(alpha)}." ) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 392d4b108b..e7d19a4ef4 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -4,6 +4,7 @@ from qibo.config import PRECISION_TOL from qibo.quantum_info.entropies import ( classical_relative_entropy, + classical_renyi_entropy, entanglement_entropy, entropy, relative_entropy, @@ -113,6 +114,48 @@ def test_classical_relative_entropy(backend, base, kind): backend.assert_allclose(divergence, target, atol=1e-5) +@pytest.mark.parametrize("kind", [None, list]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("alpha", [1, 2, 3, np.inf]) +def test_classical_renyi_entropy(backend, alpha, base, kind): + with pytest.raises(TypeError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha="2", backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha=-2, backend=backend) + with pytest.raises(TypeError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, base="2", backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, base=-2, backend=backend) + with pytest.raises(TypeError): + prob = np.array([[1.0], [0.0]]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(TypeError): + prob = np.array([]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, -1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.1, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(ValueError): + prob = np.array([0.5, 0.4999999]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) def test_entropy(backend, base, check_hermitian): From f4a6b6aa0ee56e6aeaf25b37ab8bda65a5a8fa9c Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 17:33:36 +0400 Subject: [PATCH 074/200] test function --- tests/test_quantum_info_entropies.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index e7d19a4ef4..4853c2eef1 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -155,6 +155,25 @@ def test_classical_renyi_entropy(backend, alpha, base, kind): prob = backend.cast(prob, dtype=prob.dtype) test = classical_renyi_entropy(prob, alpha, backend=backend) + prob_dist = np.random.rand(10) + prob_dist /= np.sum(prob_dist) + + if alpha == 1: + target = shannon_entropy(prob_dist, base=base, backend=backend) + elif alpha == 2: + target = -1 * np.log2(np.sum(prob_dist**2)) / np.log2(base) + elif alpha == np.inf: + target = -1 * np.log2(max(prob_dist)) / np.log2(base) + else: + target = (1 / (1 - alpha)) * np.log2(np.sum(prob_dist**alpha)) / np.log2(base) + + if kind is not None: + prob_dist = kind(prob_dist) + + renyi_ent = classical_renyi_entropy(prob_dist, alpha, base=base, backend=backend) + + backend.assert_allclose(renyi_ent, target, atol=1e-5) + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) From aa23dbc38d6cd204f78574247f7b48fbfa131429 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 30 Jan 2024 17:48:29 +0400 Subject: [PATCH 075/200] add `alpha = 0` --- src/qibo/quantum_info/entropies.py | 19 +++++++++++-------- tests/test_quantum_info_entropies.py | 6 ++++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index ec869ba9c9..b22246cf5f 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -164,20 +164,20 @@ def classical_renyi_entropy( H_{\\alpha}(\\mathbf{p}) = \\frac{1}{1 - \\alpha} \\, \\log\\left( \\sum_{x} \\, \\mathbf{p}^{\\alpha}(x) \\right) \\, . - For :math:`\\alpha \\in \\{0, 1, \\infty \\}`, it is further defined that - - .. math:: - H_{\\alpha}(\\mathbf{p}) = \\lim_{\\beta \\to \\alpha} \\, H_{\\beta}(\\mathbf{p}) \\, . - A special case is the limit :math:`\\alpha \\to 1`, in which the classical Rényi entropy coincides with the :func:`qibo.quantum_info.entropies.shannon_entropy`. + Another special case is the limit :math:`\\alpha \\to 0`, where the function is + reduced to the :math:`\\log\\left(|\\mathbf{p}|\\right)`, with :math:`|\\mathbf{p}|` + being the support of :math:`\\mathbf{p}`. + + In the limit :math:`\\alpha \\to \\infty`, the function reduces to + :math:`-\\log(\\max_{x}(\\mathbf{p}(x)))`, which is called the + `min-entropy `_. + Args: prob_dist (ndarray): discrete probability distribution. alpha (float or int): order of the Rényi entropy. - If :math:`\\alpha = 1`, defaults to :func:`qibo.quantum_info.entropies.shannon_entropy`. - If :math:`\\alpha = \\infty`, defaults to the - `min-entropy `_. base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses @@ -222,6 +222,9 @@ def classical_renyi_entropy( if np.abs(np.sum(prob_dist) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Probability array must sum to 1.") + if alpha == 0.0: + return np.log2(len(prob_dist)) / np.log2(base) + if alpha == 1.0: return shannon_entropy(prob_dist, base=base, backend=backend) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 4853c2eef1..0153a3b778 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -116,7 +116,7 @@ def test_classical_relative_entropy(backend, base, kind): @pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) -@pytest.mark.parametrize("alpha", [1, 2, 3, np.inf]) +@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) def test_classical_renyi_entropy(backend, alpha, base, kind): with pytest.raises(TypeError): prob = np.array([1.0, 0.0]) @@ -158,7 +158,9 @@ def test_classical_renyi_entropy(backend, alpha, base, kind): prob_dist = np.random.rand(10) prob_dist /= np.sum(prob_dist) - if alpha == 1: + if alpha == 0.0: + target = np.log2(len(prob_dist)) / np.log2(base) + elif alpha == 1: target = shannon_entropy(prob_dist, base=base, backend=backend) elif alpha == 2: target = -1 * np.log2(np.sum(prob_dist**2)) / np.log2(base) From 36f91984803601ff477f215b71b1a3c925547d5a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 09:07:58 +0400 Subject: [PATCH 076/200] docstring --- src/qibo/quantum_info/entropies.py | 86 ++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index b22246cf5f..0da8fe2fe2 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -158,7 +158,7 @@ def classical_renyi_entropy( """Calculates the classical Rényi entropy :math:`H_{\\alpha}` of a discrete probability distribution. For :math:`\\alpha \\in (0, \\, 1) \\cup (1, \\, \\infty)` and probability distribution - :math:`\\mathbf{p}`, the Rényi entropy is defined as + :math:`\\mathbf{p}`, the classical Rényi entropy is defined as .. math:: H_{\\alpha}(\\mathbf{p}) = \\frac{1}{1 - \\alpha} \\, \\log\\left( \\sum_{x} @@ -168,8 +168,10 @@ def classical_renyi_entropy( coincides with the :func:`qibo.quantum_info.entropies.shannon_entropy`. Another special case is the limit :math:`\\alpha \\to 0`, where the function is - reduced to the :math:`\\log\\left(|\\mathbf{p}|\\right)`, with :math:`|\\mathbf{p}|` + reduced to :math:`\\log\\left(|\\mathbf{p}|\\right)`, with :math:`|\\mathbf{p}|` being the support of :math:`\\mathbf{p}`. + This is knows as the `Hartley entropy ` + (also known as *Hartley function* or *max-entropy*). In the limit :math:`\\alpha \\to \\infty`, the function reduces to :math:`-\\log(\\max_{x}(\\mathbf{p}(x)))`, which is called the @@ -184,7 +186,7 @@ def classical_renyi_entropy( :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. Returns: - float: Rényi entropy :math:`H_{\\alpha}`. + float: Classical Rényi entropy :math:`H_{\\alpha}`. """ if backend is None: # pragma: no cover backend = GlobalBackend() @@ -423,6 +425,84 @@ def relative_entropy( return float(entropy_state - relative) +def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None): + """Calculates the Rényi entropy :math:`H_{\\alpha}` of a quantum state :math:`\\rho`. + + For :math:`\\alpha \\in (0, \\, 1) \\cup (1, \\, \\infty)`, the Rényi entropy is defined as + + .. math:: + H_{\\alpha}(\\rho) = \\frac{1}{1 - \\alpha} \\, \\log\\left( \\rho^{\\alpha} \\right) \\, . + + A special case is the limit :math:`\\alpha \\to 1`, in which the Rényi entropy + coincides with the :func:`qibo.quantum_info.entropies.entropy`. + + Another special case is the limit :math:`\\alpha \\to 0`, where the function is + reduced to :math:`\\log\\left(d\\right)`, with :math:`d = 2^{n}` + being the dimension of the Hilbert space in which ``state`` :math:`\\rho` lives in. + This is knows as the `Hartley entropy _` + (also known as *Hartley function* or *max-entropy*). + + In the limit :math:`\\alpha \\to \\infty`, the function reduces to + :math:`-\\log(\\|\\rho\\|_{\\infty})`, with :math:`\\|\\cdot\\|_{\\infty}` + being the `spectral norm `_. + This is known as the `min-entropy `_. + + Args: + prob_dist (ndarray): discrete probability distribution. + alpha (float or int): order of the Rényi entropy. + base (float): the base of the log. Defaults to :math:`2`. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be + used in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Rényi entropy :math:`H_{\\alpha}`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if ( + (len(state.shape) >= 3) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + if not isinstance(alpha, (float, int)): + raise_error( + TypeError, f"alpha must be type float, but it is type {type(alpha)}." + ) + + if alpha < 0.0: + raise_error(ValueError, "alpha must a non-negative float.") + + if base <= 0.0: + raise_error(ValueError, "log base must be non-negative.") + + if purity(state) == 1.0: + return 0.0 + + if alpha == 0.0: + return np.log2(len(state)) / np.log2(base) + + if alpha == 1.0: + return entropy(state, base=base, backend=backend) + + if alpha == np.inf: + return ( + -1 + * np.log2(backend.calculate_norm_density_matrix(state, order=2)) + / np.log2(base) + ) + + log = np.log2(np.trace(np.linalg.matrix_power(state, alpha))) + + return (1 / (1 - alpha)) * log / np.log2(base) + + def entanglement_entropy( state, bipartition, From 8e61e250047cf2709a530a5df722bafb64791e13 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 09:28:43 +0400 Subject: [PATCH 077/200] fix bug --- src/qibo/quantum_info/entropies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 0da8fe2fe2..8c674b37a8 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -482,7 +482,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None if base <= 0.0: raise_error(ValueError, "log base must be non-negative.") - if purity(state) == 1.0: + if abs(purity(state) - 1.0) < PRECISION_TOL: return 0.0 if alpha == 0.0: From 6b7b1af87aec223e97fa68c0981722035641b6a4 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 09:28:48 +0400 Subject: [PATCH 078/200] tests --- tests/test_quantum_info_entropies.py | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 0153a3b778..702ce8db2e 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -8,6 +8,7 @@ entanglement_entropy, entropy, relative_entropy, + renyi_entropy, shannon_entropy, ) from qibo.quantum_info.random_ensembles import ( @@ -301,6 +302,47 @@ def test_relative_entropy(backend, base, check_hermitian): ) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) +def test_renyi_entropy(backend, alpha, base): + with pytest.raises(TypeError): + state = np.random.rand(2, 3) + state = backend.cast(state, dtype=state.dtype) + test = renyi_entropy(state, alpha=alpha, base=base, backend=backend) + with pytest.raises(TypeError): + state = random_statevector(4, backend=backend) + test = renyi_entropy(state, alpha="2", base=base, backend=backend) + with pytest.raises(ValueError): + state = random_statevector(4, backend=backend) + test = renyi_entropy(state, alpha=-1, base=base, backend=backend) + with pytest.raises(ValueError): + state = random_statevector(4, backend=backend) + test = renyi_entropy(state, alpha=alpha, base=0, backend=backend) + + state = random_density_matrix(4, backend=backend) + + if alpha == 0.0: + target = np.log2(len(state)) / np.log2(base) + elif alpha == 1.0: + target = entropy(state, base=base, backend=backend) + elif alpha == np.inf: + target = backend.calculate_norm_density_matrix(state, order=2) + target = -1 * np.log2(target) / np.log2(base) + else: + target = np.log2(np.trace(np.linalg.matrix_power(state, alpha))) + target = (1 / (1 - alpha)) * target / np.log2(base) + + backend.assert_allclose( + renyi_entropy(state, alpha=alpha, base=base, backend=backend), target, atol=1e-5 + ) + + # test pure state + state = random_density_matrix(4, pure=True, backend=backend) + backend.assert_allclose( + renyi_entropy(state, alpha=alpha, base=base, backend=backend), 0.0, atol=1e-8 + ) + + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("bipartition", [[0], [1]]) From 1ed2b39f226a3001f5752979d62e5769fee19b1f Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 10:19:56 +0400 Subject: [PATCH 079/200] api ref --- doc/source/api-reference/qibo.rst | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 5f80e763c1..9248affd9b 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1271,7 +1271,7 @@ Callbacks Callbacks provide a way to calculate quantities on the state vector as it propagates through the circuit. Example of such quantity is the entanglement entropy, which is currently the only callback implemented in -:class:`qibo.callbacks.EntanglementEntropy`. +:class:`qibo.callbacks.Entanglemententropy`. The user can create custom callbacks by inheriting the :class:`qibo.callbacks.Callback` class. The point each callback is calculated inside the circuit is defined by adding a :class:`qibo.gates.CallbackGate`. @@ -1284,7 +1284,7 @@ This can be added similarly to a standard gate and does not affect the state vec Entanglement entropy ^^^^^^^^^^^^^^^^^^^^ -.. autoclass:: qibo.callbacks.EntanglementEntropy +.. autoclass:: qibo.callbacks.Entanglemententropy :members: :member-order: bysource @@ -1537,18 +1537,24 @@ Shannon entropy .. autofunction:: qibo.quantum_info.shannon_entropy -Classical Relative Entropy +Classical relative entropy """""""""""""""""""""""""" .. autofunction:: qibo.quantum_info.classical_relative_entropy -Classical Rényi Entropy +Classical Rényi entropy """"""""""""""""""""""" .. autofunction:: qibo.quantum_info.classical_renyi_entropy +Classical Rényi relative entropy +"""""""""""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.classical_renyi_relative_entropy + + Entropy """"""" @@ -1562,7 +1568,7 @@ Entropy and ``state`` is non-Hermitian, an error will be raised when using `cupy` backend. -Relative Entropy +Relative entropy """""""""""""""" .. autofunction:: qibo.quantum_info.relative_entropy @@ -1576,13 +1582,19 @@ Relative Entropy an error will be raised when using `cupy` backend. -Rényi Entropy +Rényi entropy """"""""""""" .. autofunction:: qibo.quantum_info.renyi_entropy -Entanglement Entropy +Rényi relative entropy +"""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.renyi_relative_entropy + + +Entanglement entropy """""""""""""""""""" .. autofunction:: qibo.quantum_info.entanglement_entropy From 6d2fed8fd5c0c89d0c402890fd5fe8567e3d2cb9 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 10:20:10 +0400 Subject: [PATCH 080/200] calssical renyi relative entropy --- src/qibo/quantum_info/entropies.py | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 8c674b37a8..99b04e62a2 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -238,6 +238,70 @@ def classical_renyi_entropy( return renyi_ent +def classical_renyi_relative_entropy( + prob_dist_p, prob_dist_q, alpha: Union[float, int], base: float = 2, backend=None +): + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if isinstance(prob_dist_p, list): + # np.float64 is necessary instead of native float because of tensorflow + prob_dist_p = backend.cast(prob_dist_p, dtype=np.float64) + if isinstance(prob_dist_q, list): + # np.float64 is necessary instead of native float because of tensorflow + prob_dist_q = backend.cast(prob_dist_q, dtype=np.float64) + + if (len(prob_dist_p.shape) != 1) or (len(prob_dist_q.shape) != 1): + raise_error( + TypeError, + "Probability arrays must have dims (k,) but have " + + f"dims {prob_dist_p.shape} and {prob_dist_q.shape}.", + ) + + if (len(prob_dist_p) == 0) or (len(prob_dist_q) == 0): + raise_error(TypeError, "At least one of the arrays is empty.") + + if not isinstance(alpha, (float, int)): + raise_error( + TypeError, f"alpha must be type float, but it is type {type(alpha)}." + ) + + if alpha < 0.0: + raise_error(ValueError, "alpha must a non-negative float.") + + if base <= 0: + raise_error(ValueError, "log base must be non-negative.") + + if (any(prob_dist_p < 0) or any(prob_dist_p > 1.0)) or ( + any(prob_dist_q < 0) or any(prob_dist_q > 1.0) + ): + raise_error( + ValueError, + "All elements of the probability array must be between 0. and 1..", + ) + if np.abs(np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "First probability array must sum to 1.") + + if np.abs(np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "Second probability array must sum to 1.") + + if alpha == 0.5: + return -2 * np.log2(np.sum(np.sqrt(prob_dist_p * prob_dist_q))) / np.log2(base) + + if alpha == 1.0: + return classical_relative_entropy( + prob_dist_p, prob_dist_q, base=base, backend=backend + ) + + if alpha == np.inf: + return np.log2(max(prob_dist_p / prob_dist_q)) / np.log2(base) + + prob_p = prob_dist_p**alpha + prob_q = prob_dist_q ** (1 - alpha) + + return (1 / (alpha - 1)) * np.log2(np.sum(prob_p * prob_q)) / np.log2(base) + + def entropy( state, base: float = 2, From dac736e9589e5f35529a9ac1c72db82536eaf452 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 10:20:23 +0400 Subject: [PATCH 081/200] tests --- tests/test_quantum_info_entropies.py | 98 ++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 702ce8db2e..c12532424c 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -5,6 +5,7 @@ from qibo.quantum_info.entropies import ( classical_relative_entropy, classical_renyi_entropy, + classical_renyi_relative_entropy, entanglement_entropy, entropy, relative_entropy, @@ -115,6 +116,103 @@ def test_classical_relative_entropy(backend, base, kind): backend.assert_allclose(divergence, target, atol=1e-5) +@pytest.mark.parametrize("kind", [None, list]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("alpha", [0, 1 / 2, 1, 2, 3, np.inf]) +def test_classical_renyi_relative_entropy(backend, alpha, base, kind): + with pytest.raises(TypeError): + prob = np.random.rand(1, 2) + prob_q = np.random.rand(1, 5) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha, base, backend=backend + ) + with pytest.raises(TypeError): + prob = np.random.rand(1, 2)[0] + prob_q = np.array([]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha, base, backend=backend + ) + with pytest.raises(ValueError): + prob = np.array([-1, 2.0]) + prob_q = np.random.rand(1, 5)[0] + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha, base, backend=backend + ) + with pytest.raises(ValueError): + prob = np.random.rand(1, 2)[0] + prob_q = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha, base, backend=backend + ) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob_q = np.random.rand(1, 2)[0] + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha, base, backend=backend + ) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob_q = np.array([0.0, 1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha, base=-2, backend=backend + ) + with pytest.raises(TypeError): + prob = np.array([1.0, 0.0]) + prob_q = np.array([0.0, 1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha="1", base=base, backend=backend + ) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob_q = np.array([0.0, 1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + prob_q = backend.cast(prob_q, dtype=prob_q.dtype) + test = classical_renyi_relative_entropy( + prob, prob_q, alpha=-2, base=base, backend=backend + ) + + prob_p = np.random.rand(10) + prob_q = np.random.rand(10) + prob_p /= np.sum(prob_p) + prob_q /= np.sum(prob_q) + + if alpha == 0.5: + target = -2 * np.log2(np.sum(np.sqrt(prob_p * prob_q))) / np.log2(base) + elif alpha == 1.0: + target = classical_relative_entropy(prob_p, prob_q, base=base, backend=backend) + elif alpha == np.inf: + target = np.log2(max(prob_p / prob_q)) / np.log2(base) + else: + target = ( + (1 / (alpha - 1)) + * np.log2(np.sum(prob_p**alpha * prob_q ** (1 - alpha))) + / np.log2(base) + ) + + if kind is not None: + prob_p, prob_q = kind(prob_p), kind(prob_q) + + divergence = classical_renyi_relative_entropy( + prob_p, prob_q, alpha=alpha, base=base, backend=backend + ) + + backend.assert_allclose(divergence, target, atol=1e-5) + + @pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) From 5af2fe69948ee3ec925df29a782690b93ad28251 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 10:33:49 +0400 Subject: [PATCH 082/200] docstring --- src/qibo/quantum_info/entropies.py | 38 +++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 99b04e62a2..94e7c07cd3 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -170,7 +170,7 @@ def classical_renyi_entropy( Another special case is the limit :math:`\\alpha \\to 0`, where the function is reduced to :math:`\\log\\left(|\\mathbf{p}|\\right)`, with :math:`|\\mathbf{p}|` being the support of :math:`\\mathbf{p}`. - This is knows as the `Hartley entropy ` + This is knows as the `Hartley entropy `_ (also known as *Hartley function* or *max-entropy*). In the limit :math:`\\alpha \\to \\infty`, the function reduces to @@ -241,6 +241,42 @@ def classical_renyi_entropy( def classical_renyi_relative_entropy( prob_dist_p, prob_dist_q, alpha: Union[float, int], base: float = 2, backend=None ): + """Calculates the classical Rényi relative entropy between two discrete probability distributions. + + This function is also known as + `Rényi divergence `_. + + For :math:`\\alpha \\in (0, \\, 1) \\cup (1, \\, \\infty)` and probability distributions + :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, the classical Rényi relative entropy is defined as + + .. math:: + H_{\\alpha}(\\mathbf{p} \\, \\| \\, \\mathbf{q}) = \\frac{1}{\\alpha - 1} \\, + \\log\\left( \\sum_{x} \\, \\frac{\\mathbf{p}^{\\alpha}(x)} + {\\mathbf{q}^{\\alpha - 1}(x)} \\right) \\, . + + A special case is the limit :math:`\\alpha \\to 1`, in which the classical Rényi divergence + coincides with the :func:`qibo.quantum_info.entropies.classical_relative_entropy`. + + Another special case is the limit :math:`\\alpha \\to 1/2`, where the function is + reduced to :math:`-2 \\log\\left(\\sum_{x} \\, \\sqrt{\\mathbf{p}(x) \\, \\mathbf{q}(x)} \\right)`. + The sum inside the :math:`\\log` is known as the + `Bhattacharyya coefficient `_. + + In the limit :math:`\\alpha \\to \\infty`, the function reduces to + :math:`\\log(\\max_{x}(\\mathbf{p}(x) \\, \\mathbf{q}(x))`. + + Args: + prob_dist_p (ndarray or list): discrete probability distribution :math:`p`. + prob_dist_q (ndarray or list): discrete probability distribution :math:`q`. + alpha (float or int): order of the Rényi entropy. + base (float): the base of the log. Defaults to :math:`2`. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be + used in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Classical Rényi relative entropy :math:`H_{\\alpha}(\\mathbf{p} \\, \\| \\, \\mathbf{q})`. + """ if backend is None: # pragma: no cover backend = GlobalBackend() From d9e95c743d49522e45bf62bc712d39044fe8a841 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 12:26:37 +0400 Subject: [PATCH 083/200] rename function --- doc/source/api-reference/qibo.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 9248affd9b..0018faa93a 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1552,7 +1552,7 @@ Classical Rényi entropy Classical Rényi relative entropy """""""""""""""""""""""""""""""" -.. autofunction:: qibo.quantum_info.classical_renyi_relative_entropy +.. autofunction:: qibo.quantum_info.classical_relative_renyi_entropy Entropy From 39aadcd62e23253964aa26e2ce0bf7e759abc12a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 12:26:55 +0400 Subject: [PATCH 084/200] relative renyi entropy --- src/qibo/quantum_info/entropies.py | 103 +++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 94e7c07cd3..606be7d221 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -238,16 +238,16 @@ def classical_renyi_entropy( return renyi_ent -def classical_renyi_relative_entropy( +def classical_relative_renyi_entropy( prob_dist_p, prob_dist_q, alpha: Union[float, int], base: float = 2, backend=None ): - """Calculates the classical Rényi relative entropy between two discrete probability distributions. + """Calculates the classical relative Rényi entropy between two discrete probability distributions. This function is also known as `Rényi divergence `_. For :math:`\\alpha \\in (0, \\, 1) \\cup (1, \\, \\infty)` and probability distributions - :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, the classical Rényi relative entropy is defined as + :math:`\\mathbf{p}` and :math:`\\mathbf{q}`, the classical relative Rényi entropy is defined as .. math:: H_{\\alpha}(\\mathbf{p} \\, \\| \\, \\mathbf{q}) = \\frac{1}{\\alpha - 1} \\, @@ -275,7 +275,7 @@ def classical_renyi_relative_entropy( :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. Returns: - float: Classical Rényi relative entropy :math:`H_{\\alpha}(\\mathbf{p} \\, \\| \\, \\mathbf{q})`. + float: Classical relative Rényi entropy :math:`H_{\\alpha}(\\mathbf{p} \\, \\| \\, \\mathbf{q})`. """ if backend is None: # pragma: no cover backend = GlobalBackend() @@ -603,6 +603,101 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None return (1 / (1 - alpha)) * log / np.log2(base) +def relative_renyi_entropy( + state, target, alpha: Union[float, int], base: float = 2, backend=None +): + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if ( + (len(state.shape) >= 3) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + if ( + (len(target.shape) >= 3) + or (len(target) == 0) + or (len(target.shape) == 2 and target.shape[0] != target.shape[1]) + ): + raise_error( + TypeError, + f"target must have dims either (k,) or (k,k), but have dims {target.shape}.", + ) + + if not isinstance(alpha, (float, int)): + raise_error( + TypeError, f"alpha must be type float, but it is type {type(alpha)}." + ) + + if alpha < 0.0: + raise_error(ValueError, "alpha must a non-negative float.") + + if base <= 0.0: + raise_error(ValueError, "log base must be non-negative.") + + if ( + abs(purity(state) - 1.0) < PRECISION_TOL + and abs(purity(target) - 1) < PRECISION_TOL + ): + return 0.0 + + if alpha == 1.0: + return relative_entropy(state, target, base, backend=backend) + + if alpha == np.inf: + if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + eigenvalues_state, eigenvectors_state = np.linalg.eigh(state) + new_state = np.zeros_like(state, dtype=complex) + new_state = backend.cast(new_state, dtype=new_state.dtype) + for eigenvalue, eigenstate in zip( + eigenvalues_state, np.transpose(eigenvectors_state) + ): + new_state += np.sqrt(eigenvalue) * np.outer( + eigenstate, np.conj(eigenstate) + ) + + eigenvalues_target, eigenvectors_target = np.linalg.eigh(target) + new_target = np.zeros_like(target, dtype=complex) + new_target = backend.cast(new_target, dtype=new_target.dtype) + for eigenvalue, eigenstate in zip( + eigenvalues_target, np.transpose(eigenvectors_target) + ): + new_target += np.sqrt(eigenstate) * np.outer( + eigenstate, np.conj(eigenstate) + ) + else: + from scipy.linalg import sqrtm # pylint: disable=C0415 + + # astype method needed because of tensorflow + new_state = sqrtm(state).astype("complex128") + new_target = sqrtm(target).astype("complex128") + new_state = backend.cast(new_state, dtype=new_state.dtype) + new_target = backend.cast(new_target, dtype=new_target.dtype) + + log = np.log2( + backend.calculate_norm_density_matrix(new_state @ new_target, order=1) + ) + + return -2 * log / np.log2(base) + + if len(state.shape) == 1: + state = np.outer(state, np.conj(state)) + + if len(target.shape) == 1: + target = np.outer(target, np.conj(target)) + + log = np.linalg.matrix_power(state, alpha) + log = log @ np.linalg.matrix_power(target, 1 - alpha) + log = np.log2(np.trace(log)) + + return (1 / (alpha - 1)) * log / np.log2(base) + + def entanglement_entropy( state, bipartition, From 0c4b75a91e37aea94fec2647a6f0156424b99ed7 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 12:26:59 +0400 Subject: [PATCH 085/200] tests --- tests/test_quantum_info_entropies.py | 122 ++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 11 deletions(-) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index c12532424c..c7e7ebdf9b 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -1,14 +1,16 @@ import numpy as np import pytest +from scipy.linalg import sqrtm from qibo.config import PRECISION_TOL from qibo.quantum_info.entropies import ( classical_relative_entropy, + classical_relative_renyi_entropy, classical_renyi_entropy, - classical_renyi_relative_entropy, entanglement_entropy, entropy, relative_entropy, + relative_renyi_entropy, renyi_entropy, shannon_entropy, ) @@ -119,13 +121,13 @@ def test_classical_relative_entropy(backend, base, kind): @pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("alpha", [0, 1 / 2, 1, 2, 3, np.inf]) -def test_classical_renyi_relative_entropy(backend, alpha, base, kind): +def test_classical_relative_renyi_entropy(backend, alpha, base, kind): with pytest.raises(TypeError): prob = np.random.rand(1, 2) prob_q = np.random.rand(1, 5) prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha, base, backend=backend ) with pytest.raises(TypeError): @@ -133,7 +135,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): prob_q = np.array([]) prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha, base, backend=backend ) with pytest.raises(ValueError): @@ -141,7 +143,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): prob_q = np.random.rand(1, 5)[0] prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha, base, backend=backend ) with pytest.raises(ValueError): @@ -149,7 +151,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): prob_q = np.array([1.0, 0.0]) prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha, base, backend=backend ) with pytest.raises(ValueError): @@ -157,7 +159,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): prob_q = np.random.rand(1, 2)[0] prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha, base, backend=backend ) with pytest.raises(ValueError): @@ -165,7 +167,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): prob_q = np.array([0.0, 1.0]) prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha, base=-2, backend=backend ) with pytest.raises(TypeError): @@ -173,7 +175,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): prob_q = np.array([0.0, 1.0]) prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha="1", base=base, backend=backend ) with pytest.raises(ValueError): @@ -181,7 +183,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): prob_q = np.array([0.0, 1.0]) prob = backend.cast(prob, dtype=prob.dtype) prob_q = backend.cast(prob_q, dtype=prob_q.dtype) - test = classical_renyi_relative_entropy( + test = classical_relative_renyi_entropy( prob, prob_q, alpha=-2, base=base, backend=backend ) @@ -206,7 +208,7 @@ def test_classical_renyi_relative_entropy(backend, alpha, base, kind): if kind is not None: prob_p, prob_q = kind(prob_p), kind(prob_q) - divergence = classical_renyi_relative_entropy( + divergence = classical_relative_renyi_entropy( prob_p, prob_q, alpha=alpha, base=base, backend=backend ) @@ -441,6 +443,104 @@ def test_renyi_entropy(backend, alpha, base): ) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) +def test_relative_renyi_entropy(backend, alpha, base): + with pytest.raises(TypeError): + state = np.random.rand(2, 3) + state = backend.cast(state, dtype=state.dtype) + target = random_density_matrix(4, backend=backend) + test = relative_renyi_entropy( + state, target, alpha=alpha, base=base, backend=backend + ) + with pytest.raises(TypeError): + target = np.random.rand(2, 3) + target = backend.cast(target, dtype=target.dtype) + state = random_density_matrix(4, backend=backend) + test = relative_renyi_entropy( + state, target, alpha=alpha, base=base, backend=backend + ) + with pytest.raises(TypeError): + state = random_statevector(4, backend=backend) + target = random_statevector(4, backend=backend) + test = relative_renyi_entropy( + state, target, alpha="2", base=base, backend=backend + ) + with pytest.raises(ValueError): + state = random_statevector(4, backend=backend) + target = random_statevector(4, backend=backend) + test = relative_renyi_entropy( + state, target, alpha=-1, base=base, backend=backend + ) + with pytest.raises(ValueError): + state = random_statevector(4, backend=backend) + target = random_statevector(4, backend=backend) + test = relative_renyi_entropy( + state, target, alpha=alpha, base=0, backend=backend + ) + + state = random_density_matrix(4, backend=backend) + target = random_density_matrix(4, backend=backend) + + if alpha == 1.0: + log = relative_entropy(state, target, base, backend=backend) + elif alpha == np.inf: + if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + eigenvalues_state, eigenvectors_state = np.linalg.eigh(state) + new_state = np.zeros_like(state, dtype=complex) + new_state = backend.cast(new_state, dtype=new_state.dtype) + for eigenvalue, eigenstate in zip( + eigenvalues_state, np.transpose(eigenvectors_state) + ): + new_state += np.sqrt(eigenvalue) * np.outer( + eigenstate, np.conj(eigenstate) + ) + + eigenvalues_target, eigenvectors_target = np.linalg.eigh(target) + new_target = np.zeros_like(target, dtype=complex) + new_target = backend.cast(new_target, dtype=new_target.dtype) + for eigenvalue, eigenstate in zip( + eigenvalues_target, np.transpose(eigenvectors_target) + ): + new_target += np.sqrt(eigenstate) * np.outer( + eigenstate, np.conj(eigenstate) + ) + else: + new_state, new_target = sqrtm(state).astype("complex128"), sqrtm( + target + ).astype("complex128") + new_state = backend.cast(new_state, dtype=new_state.dtype) + new_target = backend.cast(new_target, dtype=new_target.dtype) + + log = np.log2( + backend.calculate_norm_density_matrix(new_state @ new_target, order=1) + ) + + log = -2 * log / np.log2(base) + + else: + log = np.linalg.matrix_power(state, alpha) + log = log @ np.linalg.matrix_power(target, 1 - alpha) + log = np.log2(np.trace(log)) + + log = (1 / (alpha - 1)) * log / np.log2(base) + + backend.assert_allclose( + relative_renyi_entropy(state, target, alpha=alpha, base=base, backend=backend), + log, + atol=1e-5, + ) + + # test pure states + state = random_density_matrix(4, pure=True, backend=backend) + target = random_density_matrix(4, pure=True, backend=backend) + backend.assert_allclose( + relative_renyi_entropy(state, target, alpha=alpha, base=base, backend=backend), + 0.0, + atol=1e-8, + ) + + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("bipartition", [[0], [1]]) From 5fea3d1d9bb8d83eaea0d517947ae8930f27bc86 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 12:48:43 +0400 Subject: [PATCH 086/200] docstring --- src/qibo/quantum_info/entropies.py | 33 +++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 606be7d221..3abdb3755b 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -548,7 +548,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None This is known as the `min-entropy `_. Args: - prob_dist (ndarray): discrete probability distribution. + state (ndarray): statevector or density matrix. alpha (float or int): order of the Rényi entropy. base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be @@ -606,6 +606,37 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None def relative_renyi_entropy( state, target, alpha: Union[float, int], base: float = 2, backend=None ): + """Calculates the relative Rényi entropy between two quantum states. + + For :math:`\\alpha \\in (0, \\, 1) \\cup (1, \\, \\infty)` and quantum states + :math:`\\rho` and :math:`\\sigma`, the relative Rényi entropy is defined as + + .. math:: + H_{\\alpha}(\\rho \\, \\| \\, \\sigma) = \\frac{1}{\\alpha - 1} \\, + \\log\\left( \\textup{tr}\\left( \\rho^{\\alpha} \\, + \\sigma^{1 - \\alpha} \\right) \\right) \\, . + + A special case is the limit :math:`\\alpha \\to 1`, in which the Rényi entropy + coincides with the :func:`qibo.quantum_info.entropies.relative_entropy`. + + In the limit :math:`\\alpha \\to \\infty`, the function reduces to + :math:`-2 \\, \\log(\\|\\sqrt{\\rho} \\, \\sqrt{\\sigma}\\|_{1})`, + with :math:`\\|\\cdot\\|_{1}` being the + `Schatten 1-norm `_. + This is known as the `min-relative entropy `_. + + Args: + state (ndarray): statevector or density matrix :math:`\\rho`. + target (ndarray): statevector or density matrix :math:`\\sigma`. + alpha (float or int): order of the Rényi entropy. + base (float): the base of the log. Defaults to :math:`2`. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be + used in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Relative Rényi entropy :math:`H_{\\alpha}(\\rho \\, \\| \\, \\sigma)`. + """ if backend is None: # pragma: no cover backend = GlobalBackend() From bd994ecaebf33322c70447ad20a973401754a31b Mon Sep 17 00:00:00 2001 From: Rahul Arvind Date: Wed, 31 Jan 2024 17:24:26 +0800 Subject: [PATCH 087/200] Explicitly add the fixture --- pyproject.toml | 6 +++++- src/qibo/models/qcnn.py | 2 +- tests/test_models_qcnn.py | 9 +++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 61641cc190..fd67a76f28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "qibo" -version = "0.2.4" +version = "0.2.5" description = "A framework for quantum computing with hardware acceleration." authors = ["The Qibo team"] license = "Apache License 2.0" @@ -95,3 +95,7 @@ output-format = "colorized" [tool.pytest.ini_options] testpaths = ['tests/'] filterwarnings = ['ignore::RuntimeWarning'] + +addopts = [ + '--durations=60', +] \ No newline at end of file diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 640904e6ee..48d4104e05 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -51,7 +51,7 @@ def __init__( nlayers, nclasses=2, params=None, - twoqubitansatz=None, + twoqubitansatz = None, copy_init_state=None, ): self.nclasses = nclasses diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 1f8d853c72..34f92da826 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -11,13 +11,8 @@ angles0 = [i * math.pi / num_angles for i in range(num_angles)] -def test_classifier_circuit2(backend, capsys): +def test_classifier_circuit2(backend): """ """ - - with capsys.disabled(): - backender = get_backend() - print(str(backender)) - nqubits = 2 nlayers = int(nqubits / 2) init_state = np.ones(2**nqubits) / np.sqrt(2**nqubits) # @@ -373,6 +368,7 @@ def test_two_qubit_ansatz(backend): c.add(gates.CNOT(1, 0)) test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_qcnn_training(backend): import random @@ -403,6 +399,7 @@ def test_qcnn_training(backend): predictions.append(1) labels = np.array([[1], [-1], [1]]) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_two_qubit_ansatz_training(backend): c = Circuit(2) From fd5c1ea7bffbf62c6b50ccdb9cbc5b89aa998005 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 13:49:27 +0400 Subject: [PATCH 088/200] fix test and coverage --- src/qibo/quantum_info/entropies.py | 23 ++++++++++++++++------- tests/test_quantum_info_entropies.py | 25 ++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 3abdb3755b..a2ef64899a 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -483,6 +483,12 @@ def relative_entropy( if purity(state) == 1.0 and purity(target) == 1.0: return 0.0 + if len(state.shape) == 1: + state = np.outer(state, np.conj(state)) + + if len(target.shape) == 1: + target = np.outer(target, np.conj(target)) + if not check_hermitian or _check_hermitian_or_not_gpu(state, backend=backend): eigenvalues_state = np.linalg.eigvalsh(state) else: @@ -677,11 +683,20 @@ def relative_renyi_entropy( ): return 0.0 + if len(state.shape) == 1: + state = np.outer(state, np.conj(state)) + + if len(target.shape) == 1: + target = np.outer(target, np.conj(target)) + if alpha == 1.0: return relative_entropy(state, target, base, backend=backend) if alpha == np.inf: - if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + if backend.__class__.__name__ in [ + "CupyBackend", + "CuQuantumBackend", + ]: # pragma: no cover eigenvalues_state, eigenvectors_state = np.linalg.eigh(state) new_state = np.zeros_like(state, dtype=complex) new_state = backend.cast(new_state, dtype=new_state.dtype) @@ -716,12 +731,6 @@ def relative_renyi_entropy( return -2 * log / np.log2(base) - if len(state.shape) == 1: - state = np.outer(state, np.conj(state)) - - if len(target.shape) == 1: - target = np.outer(target, np.conj(target)) - log = np.linalg.matrix_power(state, alpha) log = log @ np.linalg.matrix_power(target, 1 - alpha) log = np.log2(np.trace(log)) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index c7e7ebdf9b..bc2ec4abab 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -443,9 +443,12 @@ def test_renyi_entropy(backend, alpha, base): ) +@pytest.mark.parametrize( + ["state_flag", "target_flag"], [[True, True], [False, True], [True, False]] +) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) -def test_relative_renyi_entropy(backend, alpha, base): +def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): with pytest.raises(TypeError): state = np.random.rand(2, 3) state = backend.cast(state, dtype=state.dtype) @@ -479,8 +482,12 @@ def test_relative_renyi_entropy(backend, alpha, base): state, target, alpha=alpha, base=0, backend=backend ) - state = random_density_matrix(4, backend=backend) - target = random_density_matrix(4, backend=backend) + state = ( + random_statevector(4, backend=backend) + if state_flag + else random_density_matrix(4, backend=backend) + ) + target = backend.identity_density_matrix(2, normalize=True) if alpha == 1.0: log = relative_entropy(state, target, base, backend=backend) @@ -506,6 +513,12 @@ def test_relative_renyi_entropy(backend, alpha, base): eigenstate, np.conj(eigenstate) ) else: + if len(state.shape) == 1: + state = np.outer(state, np.conj(state)) + + if len(target.shape) == 1: + target = np.outer(target, np.conj(target)) + new_state, new_target = sqrtm(state).astype("complex128"), sqrtm( target ).astype("complex128") @@ -519,6 +532,12 @@ def test_relative_renyi_entropy(backend, alpha, base): log = -2 * log / np.log2(base) else: + if len(state.shape) == 1: + state = np.outer(state, np.conj(state)) + + if len(target.shape) == 1: + target = np.outer(target, np.conj(target)) + log = np.linalg.matrix_power(state, alpha) log = log @ np.linalg.matrix_power(target, 1 - alpha) log = np.log2(np.trace(log)) From 40e39d195149292dce4d8f2ef3dc354c26152b97 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:56:10 +0000 Subject: [PATCH 089/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyproject.toml | 2 +- src/qibo/models/qcnn.py | 2 +- tests/test_models_qcnn.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0e40057c74..bb2b539695 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,4 +101,4 @@ addopts = [ '--cov-report=xml', '--cov-report=html', '--durations=60', -] \ No newline at end of file +] diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 48d4104e05..640904e6ee 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -51,7 +51,7 @@ def __init__( nlayers, nclasses=2, params=None, - twoqubitansatz = None, + twoqubitansatz=None, copy_init_state=None, ): self.nclasses = nclasses diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 34f92da826..9e5d262871 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -368,8 +368,8 @@ def test_two_qubit_ansatz(backend): c.add(gates.CNOT(1, 0)) test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_qcnn_training(backend): import random @@ -399,8 +399,8 @@ def test_qcnn_training(backend): predictions.append(1) labels = np.array([[1], [-1], [1]]) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_two_qubit_ansatz_training(backend): c = Circuit(2) c.add(gates.H(0)) From 37e9d6da1013ee3468a6fdd489cb791c4b1c7522 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 14:45:12 +0400 Subject: [PATCH 090/200] entropies and tests --- src/qibo/quantum_info/entropies.py | 121 ++++++++++++++++++++++ tests/test_quantum_info_entropies.py | 144 ++++++++++++++++++++++----- 2 files changed, 242 insertions(+), 23 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index a2ef64899a..fcc20fff8c 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -338,6 +338,72 @@ def classical_relative_renyi_entropy( return (1 / (alpha - 1)) * np.log2(np.sum(prob_p * prob_q)) / np.log2(base) +def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend=None): + """Calculates the classical Tsallis entropy for a discrete probability distribution. + + This is defined as + + .. math:: + S_{\\alpha}(\\mathbf{p}) = \\frac{1}{\\alpha - 1} \\, + \\left(1 - \\sum_{x} \\, \\mathbf{p}^{\\alpha}(x) \\right) + + Args: + prob_dist (ndarray): discrete probability distribution. + alpha (float or int): entropic index. + base (float): the base of the log. Used when ``alpha=1.0``. + Defaults to :math:`2`. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be + used in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Classical Tsallis entropy :math:`S_{\\alpha}(\\mathbf{p})`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if isinstance(prob_dist, list): + # np.float64 is necessary instead of native float because of tensorflow + prob_dist = backend.cast(prob_dist, dtype=np.float64) + + if not isinstance(alpha, (float, int)): + raise_error( + TypeError, f"alpha must be type float, but it is type {type(alpha)}." + ) + + if alpha < 0.0: + raise_error(ValueError, "alpha must a non-negative float.") + + if base <= 0: + raise_error(ValueError, "log base must be non-negative.") + + if len(prob_dist.shape) != 1: + raise_error( + TypeError, + f"Probability array must have dims (k,) but it has {prob_dist.shape}.", + ) + + if len(prob_dist) == 0: + raise_error(TypeError, "Empty array.") + + if any(prob_dist < 0) or any(prob_dist > 1.0): + raise_error( + ValueError, + "All elements of the probability array must be between 0. and 1..", + ) + + if np.abs(np.sum(prob_dist) - 1.0) > PRECISION_TOL: + raise_error(ValueError, "Probability array must sum to 1.") + + if alpha == 1.0: + return shannon_entropy(prob_dist, base=base, backend=backend) + + if isinstance(prob_dist, list): + prob_dist = backend.cast(prob_dist, dtype=np.float64) + + return (1 / (1 - alpha)) * (np.sum(prob_dist**alpha) - 1) + + def entropy( state, base: float = 2, @@ -738,6 +804,61 @@ def relative_renyi_entropy( return (1 / (alpha - 1)) * log / np.log2(base) +def tsallis_entropy(state, alpha: float, base: float = 2, backend=None): + """Calculates the Tsallis entropy of a quantum state. + + .. math:: + S_{\\alpha}(\\rho) = \\frac{1}{1 - \\alpha} \\, + \\left( \\text{tr}(\\rho^{\\alpha}) - 1 \\right) + + When :math:`\\alpha = 1`, the functions defaults to + :func:`qibo.quantum_info.entropies.entropy`. + + Args: + state (ndarray): statevector or density matrix. + alpha (float or int): entropic index. + base (float, optional): the base of the log. Used when ``alpha=1.0``. + Defaults to :math:`2`. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used + in the execution. If ``None``, it uses + :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + Returns: + float: Tsallis entropy :math:`S_{\\alpha}(\\rho)`. + """ + if backend is None: # pragma: no cover + backend = GlobalBackend() + + if ( + (len(state.shape) >= 3) + or (len(state) == 0) + or (len(state.shape) == 2 and state.shape[0] != state.shape[1]) + ): + raise_error( + TypeError, + f"state must have dims either (k,) or (k,k), but have dims {state.shape}.", + ) + + if not isinstance(alpha, (float, int)): + raise_error( + TypeError, f"alpha must be type float, but it is type {type(alpha)}." + ) + + if alpha < 0.0: + raise_error(ValueError, "alpha must a non-negative float.") + + if base <= 0.0: + raise_error(ValueError, "log base must be non-negative.") + + if abs(purity(state) - 1.0) < PRECISION_TOL: + return 0.0 + + if alpha == 1.0: + return entropy(state, base=base, backend=backend) + + return (1 / (1 - alpha)) * (np.trace(np.linalg.matrix_power(state, alpha)) - 1) + + def entanglement_entropy( state, bipartition, diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index bc2ec4abab..0bcca2e087 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -7,12 +7,14 @@ classical_relative_entropy, classical_relative_renyi_entropy, classical_renyi_entropy, + classical_tsallis_entropy, entanglement_entropy, entropy, relative_entropy, relative_renyi_entropy, renyi_entropy, shannon_entropy, + tsallis_entropy, ) from qibo.quantum_info.random_ensembles import ( random_density_matrix, @@ -118,6 +120,69 @@ def test_classical_relative_entropy(backend, base, kind): backend.assert_allclose(divergence, target, atol=1e-5) +@pytest.mark.parametrize("kind", [None, list]) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) +def test_classical_renyi_entropy(backend, alpha, base, kind): + with pytest.raises(TypeError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha="2", backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha=-2, backend=backend) + with pytest.raises(TypeError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, base="2", backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, base=-2, backend=backend) + with pytest.raises(TypeError): + prob = np.array([[1.0], [0.0]]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(TypeError): + prob = np.array([]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.0, -1.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(ValueError): + prob = np.array([1.1, 0.0]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + with pytest.raises(ValueError): + prob = np.array([0.5, 0.4999999]) + prob = backend.cast(prob, dtype=prob.dtype) + test = classical_renyi_entropy(prob, alpha, backend=backend) + + prob_dist = np.random.rand(10) + prob_dist /= np.sum(prob_dist) + + if alpha == 0.0: + target = np.log2(len(prob_dist)) / np.log2(base) + elif alpha == 1: + target = shannon_entropy(prob_dist, base=base, backend=backend) + elif alpha == 2: + target = -1 * np.log2(np.sum(prob_dist**2)) / np.log2(base) + elif alpha == np.inf: + target = -1 * np.log2(max(prob_dist)) / np.log2(base) + else: + target = (1 / (1 - alpha)) * np.log2(np.sum(prob_dist**alpha)) / np.log2(base) + + if kind is not None: + prob_dist = kind(prob_dist) + + renyi_ent = classical_renyi_entropy(prob_dist, alpha, base=base, backend=backend) + + backend.assert_allclose(renyi_ent, target, atol=1e-5) + + @pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("alpha", [0, 1 / 2, 1, 2, 3, np.inf]) @@ -217,65 +282,61 @@ def test_classical_relative_renyi_entropy(backend, alpha, base, kind): @pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) -@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) -def test_classical_renyi_entropy(backend, alpha, base, kind): +@pytest.mark.parametrize("alpha", [0, 1, 2, 3]) +def test_classical_tsallis_entropy(backend, alpha, base, kind): with pytest.raises(TypeError): prob = np.array([1.0, 0.0]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha="2", backend=backend) + test = classical_tsallis_entropy(prob, alpha="2", backend=backend) with pytest.raises(ValueError): prob = np.array([1.0, 0.0]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha=-2, backend=backend) + test = classical_tsallis_entropy(prob, alpha=-2, backend=backend) with pytest.raises(TypeError): prob = np.array([1.0, 0.0]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha, base="2", backend=backend) + test = classical_tsallis_entropy(prob, alpha, base="2", backend=backend) with pytest.raises(ValueError): prob = np.array([1.0, 0.0]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha, base=-2, backend=backend) + test = classical_tsallis_entropy(prob, alpha, base=-2, backend=backend) with pytest.raises(TypeError): prob = np.array([[1.0], [0.0]]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha, backend=backend) + test = classical_tsallis_entropy(prob, alpha, backend=backend) with pytest.raises(TypeError): prob = np.array([]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha, backend=backend) + test = classical_tsallis_entropy(prob, alpha, backend=backend) with pytest.raises(ValueError): prob = np.array([1.0, -1.0]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha, backend=backend) + test = classical_tsallis_entropy(prob, alpha, backend=backend) with pytest.raises(ValueError): prob = np.array([1.1, 0.0]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha, backend=backend) + test = classical_tsallis_entropy(prob, alpha, backend=backend) with pytest.raises(ValueError): prob = np.array([0.5, 0.4999999]) prob = backend.cast(prob, dtype=prob.dtype) - test = classical_renyi_entropy(prob, alpha, backend=backend) + test = classical_tsallis_entropy(prob, alpha, backend=backend) prob_dist = np.random.rand(10) prob_dist /= np.sum(prob_dist) - if alpha == 0.0: - target = np.log2(len(prob_dist)) / np.log2(base) - elif alpha == 1: + if alpha == 1.0: target = shannon_entropy(prob_dist, base=base, backend=backend) - elif alpha == 2: - target = -1 * np.log2(np.sum(prob_dist**2)) / np.log2(base) - elif alpha == np.inf: - target = -1 * np.log2(max(prob_dist)) / np.log2(base) else: - target = (1 / (1 - alpha)) * np.log2(np.sum(prob_dist**alpha)) / np.log2(base) + target = (1 / (1 - alpha)) * (np.sum(prob_dist**alpha) - 1) if kind is not None: prob_dist = kind(prob_dist) - renyi_ent = classical_renyi_entropy(prob_dist, alpha, base=base, backend=backend) - - backend.assert_allclose(renyi_ent, target, atol=1e-5) + backend.assert_allclose( + classical_tsallis_entropy(prob_dist, alpha=alpha, base=base, backend=backend), + target, + atol=1e-5, + ) @pytest.mark.parametrize("check_hermitian", [False, True]) @@ -487,7 +548,11 @@ def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): if state_flag else random_density_matrix(4, backend=backend) ) - target = backend.identity_density_matrix(2, normalize=True) + target = ( + random_statevector(4, backend=backend) + if target_flag + else random_density_matrix(4, backend=backend) + ) if alpha == 1.0: log = relative_entropy(state, target, base, backend=backend) @@ -560,6 +625,39 @@ def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): ) +@pytest.mark.parametrize("base", [2, 10, np.e, 5]) +@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) +def test_tsallis_entropy(backend, alpha, base): + with pytest.raises(TypeError): + state = np.random.rand(2, 3) + state = backend.cast(state, dtype=state.dtype) + test = renyi_entropy(state, alpha=alpha, base=base, backend=backend) + with pytest.raises(TypeError): + state = random_statevector(4, backend=backend) + test = renyi_entropy(state, alpha="2", base=base, backend=backend) + with pytest.raises(ValueError): + state = random_statevector(4, backend=backend) + test = renyi_entropy(state, alpha=-1, base=base, backend=backend) + with pytest.raises(ValueError): + state = random_statevector(4, backend=backend) + test = renyi_entropy(state, alpha=alpha, base=0, backend=backend) + + state = random_density_matrix(4, backend=backend) + + if alpha == 1.0: + target = entropy(state, base=base, backend=backend) + else: + target = (1 / (1 - alpha)) * ( + np.trace(np.linalg.matrix_power(state, alpha)) - 1 + ) + + backend.assert_allclose( + tsallis_entropy(state, alpha=alpha, base=base, backend=backend), + target, + atol=1e-5, + ) + + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) @pytest.mark.parametrize("bipartition", [[0], [1]]) From c4a6bf1086fb311491bb38cf9f8217e95a2aa9fd Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 14:47:15 +0400 Subject: [PATCH 091/200] api ref --- doc/source/api-reference/qibo.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 964267ce4c..8dbf57a43d 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1555,6 +1555,12 @@ Classical Rényi relative entropy .. autofunction:: qibo.quantum_info.classical_relative_renyi_entropy +Classical Tsallis entropy +""""""""""""""""""""""""" + +.. autofunction:: qibo.quantum_info.classical_tsallis_entropy + + Entropy """"""" @@ -1594,6 +1600,12 @@ Rényi relative entropy .. autofunction:: qibo.quantum_info.renyi_relative_entropy +Tsallis entropy +""""""""""""""" + +.. autofunction:: qibo.quantum_info.tsallis_entropy + + Entanglement entropy """""""""""""""""""" From 9a0b3156915b8514df483fd1b5cb07d9b58547d3 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 14:48:45 +0400 Subject: [PATCH 092/200] fix doc bug --- doc/source/api-reference/qibo.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 8dbf57a43d..936ff6ba90 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1271,7 +1271,7 @@ Callbacks Callbacks provide a way to calculate quantities on the state vector as it propagates through the circuit. Example of such quantity is the entanglement entropy, which is currently the only callback implemented in -:class:`qibo.callbacks.Entanglemententropy`. +:class:`qibo.callbacks.EntanglementEntropy`. The user can create custom callbacks by inheriting the :class:`qibo.callbacks.Callback` class. The point each callback is calculated inside the circuit is defined by adding a :class:`qibo.gates.CallbackGate`. @@ -1284,7 +1284,7 @@ This can be added similarly to a standard gate and does not affect the state vec Entanglement entropy ^^^^^^^^^^^^^^^^^^^^ -.. autoclass:: qibo.callbacks.Entanglemententropy +.. autoclass:: qibo.callbacks.EntanglementEntropy :members: :member-order: bysource From 7eab0724727ecbbc8789718a604c33bfa3326f1b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 Jan 2024 10:52:45 +0000 Subject: [PATCH 093/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/entropies.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index fcc20fff8c..73b89df413 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -1,4 +1,5 @@ """Submodule with entropy measures.""" + from typing import Union import numpy as np From 03b7d6d103d461a2de7039bf825ceac143151317 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 31 Jan 2024 15:53:23 +0400 Subject: [PATCH 094/200] fix multiple issues --- src/qibo/quantum_info/entropies.py | 75 +++++++++++---------- tests/test_quantum_info_entropies.py | 97 ++++++++++++---------------- 2 files changed, 76 insertions(+), 96 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 73b89df413..f1b3e08a68 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -3,6 +3,7 @@ from typing import Union import numpy as np +from scipy.linalg import fractional_matrix_power from qibo.backends import GlobalBackend from qibo.config import PRECISION_TOL, raise_error @@ -671,7 +672,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None / np.log2(base) ) - log = np.log2(np.trace(np.linalg.matrix_power(state, alpha))) + log = np.log2(np.trace(_matrix_power(state, alpha, backend))) return (1 / (1 - alpha)) * log / np.log2(base) @@ -698,6 +699,12 @@ def relative_renyi_entropy( `Schatten 1-norm `_. This is known as the `min-relative entropy `_. + .. note:: + Function raises ``NotImplementedError`` when ``target`` :math:`sigma` + is a pure state and :math:`\\alpha > 1`. This is due to the fact that + it is not possible to calculate :math:`\\sigma^{1 - \\alpha}` when + :math:`\\alpha > 1` and :math:`\\sigma` is a projector, i.e. a singular matrix. + Args: state (ndarray): statevector or density matrix :math:`\\rho`. target (ndarray): statevector or density matrix :math:`\\sigma`. @@ -744,53 +751,28 @@ def relative_renyi_entropy( if base <= 0.0: raise_error(ValueError, "log base must be non-negative.") + purity_target = purity(target) if ( abs(purity(state) - 1.0) < PRECISION_TOL - and abs(purity(target) - 1) < PRECISION_TOL + and abs(purity_target - 1) < PRECISION_TOL ): return 0.0 + if alpha > 1.0 and abs(purity_target - 1) < PRECISION_TOL: + raise_error( + NotImplementedError, + "It is not possible to invert a singular matrix. ``target`` is a pure state and alpha > 1.", + ) + if len(state.shape) == 1: state = np.outer(state, np.conj(state)) - if len(target.shape) == 1: - target = np.outer(target, np.conj(target)) - if alpha == 1.0: return relative_entropy(state, target, base, backend=backend) if alpha == np.inf: - if backend.__class__.__name__ in [ - "CupyBackend", - "CuQuantumBackend", - ]: # pragma: no cover - eigenvalues_state, eigenvectors_state = np.linalg.eigh(state) - new_state = np.zeros_like(state, dtype=complex) - new_state = backend.cast(new_state, dtype=new_state.dtype) - for eigenvalue, eigenstate in zip( - eigenvalues_state, np.transpose(eigenvectors_state) - ): - new_state += np.sqrt(eigenvalue) * np.outer( - eigenstate, np.conj(eigenstate) - ) - - eigenvalues_target, eigenvectors_target = np.linalg.eigh(target) - new_target = np.zeros_like(target, dtype=complex) - new_target = backend.cast(new_target, dtype=new_target.dtype) - for eigenvalue, eigenstate in zip( - eigenvalues_target, np.transpose(eigenvectors_target) - ): - new_target += np.sqrt(eigenstate) * np.outer( - eigenstate, np.conj(eigenstate) - ) - else: - from scipy.linalg import sqrtm # pylint: disable=C0415 - - # astype method needed because of tensorflow - new_state = sqrtm(state).astype("complex128") - new_target = sqrtm(target).astype("complex128") - new_state = backend.cast(new_state, dtype=new_state.dtype) - new_target = backend.cast(new_target, dtype=new_target.dtype) + new_state = _matrix_power(state, 0.5, backend) + new_target = _matrix_power(target, 0.5, backend) log = np.log2( backend.calculate_norm_density_matrix(new_state @ new_target, order=1) @@ -798,8 +780,8 @@ def relative_renyi_entropy( return -2 * log / np.log2(base) - log = np.linalg.matrix_power(state, alpha) - log = log @ np.linalg.matrix_power(target, 1 - alpha) + log = _matrix_power(state, alpha, backend) + log = log @ _matrix_power(target, 1 - alpha, backend) log = np.log2(np.trace(log)) return (1 / (alpha - 1)) * log / np.log2(base) @@ -857,7 +839,7 @@ def tsallis_entropy(state, alpha: float, base: float = 2, backend=None): if alpha == 1.0: return entropy(state, base=base, backend=backend) - return (1 / (1 - alpha)) * (np.trace(np.linalg.matrix_power(state, alpha)) - 1) + return (1 / (1 - alpha)) * (np.trace(_matrix_power(state, alpha, backend)) - 1) def entanglement_entropy( @@ -925,3 +907,18 @@ def entanglement_entropy( ) return entropy_entanglement + + +def _matrix_power(matrix, alpha, backend): + """Calculates ``matrix ** alpha`` according to backend.""" + if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + new_matrix = backend.to_numpy(matrix) + else: + new_matrix = np.copy(matrix) + + if len(new_matrix.shape) == 1: + new_matrix = np.outer(new_matrix, np.conj(new_matrix)) + + new_matrix = fractional_matrix_power(new_matrix, alpha) + + return backend.cast(new_matrix, dtype=new_matrix.dtype) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index 0bcca2e087..d709f76056 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -4,6 +4,7 @@ from qibo.config import PRECISION_TOL from qibo.quantum_info.entropies import ( + _matrix_power, classical_relative_entropy, classical_relative_renyi_entropy, classical_renyi_entropy, @@ -508,7 +509,7 @@ def test_renyi_entropy(backend, alpha, base): ["state_flag", "target_flag"], [[True, True], [False, True], [True, False]] ) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) -@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) +@pytest.mark.parametrize("alpha", [0, 1, 2, 3, 5.4, np.inf]) def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): with pytest.raises(TypeError): state = np.random.rand(2, 3) @@ -554,66 +555,48 @@ def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): else random_density_matrix(4, backend=backend) ) - if alpha == 1.0: - log = relative_entropy(state, target, base, backend=backend) - elif alpha == np.inf: - if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: - eigenvalues_state, eigenvectors_state = np.linalg.eigh(state) - new_state = np.zeros_like(state, dtype=complex) - new_state = backend.cast(new_state, dtype=new_state.dtype) - for eigenvalue, eigenstate in zip( - eigenvalues_state, np.transpose(eigenvectors_state) - ): - new_state += np.sqrt(eigenvalue) * np.outer( - eigenstate, np.conj(eigenstate) - ) - - eigenvalues_target, eigenvectors_target = np.linalg.eigh(target) - new_target = np.zeros_like(target, dtype=complex) - new_target = backend.cast(new_target, dtype=new_target.dtype) - for eigenvalue, eigenstate in zip( - eigenvalues_target, np.transpose(eigenvectors_target) - ): - new_target += np.sqrt(eigenstate) * np.outer( - eigenstate, np.conj(eigenstate) - ) - else: - if len(state.shape) == 1: - state = np.outer(state, np.conj(state)) - - if len(target.shape) == 1: - target = np.outer(target, np.conj(target)) - - new_state, new_target = sqrtm(state).astype("complex128"), sqrtm( - target - ).astype("complex128") - new_state = backend.cast(new_state, dtype=new_state.dtype) - new_target = backend.cast(new_target, dtype=new_target.dtype) - - log = np.log2( - backend.calculate_norm_density_matrix(new_state @ new_target, order=1) + if state_flag and target_flag: + backend.assert_allclose( + relative_renyi_entropy(state, target, alpha, base, backend), 0.0, atol=1e-5 ) - - log = -2 * log / np.log2(base) - else: - if len(state.shape) == 1: - state = np.outer(state, np.conj(state)) + if target_flag and alpha > 1: + with pytest.raises(NotImplementedError): + relative_renyi_entropy(state, target, alpha, base, backend) + else: + if alpha == 1.0: + log = relative_entropy(state, target, base, backend=backend) + elif alpha == np.inf: + new_state = _matrix_power(state, 0.5, backend) + new_target = _matrix_power(target, 0.5, backend) + + log = np.log2( + backend.calculate_norm_density_matrix( + new_state @ new_target, order=1 + ) + ) - if len(target.shape) == 1: - target = np.outer(target, np.conj(target)) + log = -2 * log / np.log2(base) + else: + if len(state.shape) == 1: + state = np.outer(state, np.conj(state)) - log = np.linalg.matrix_power(state, alpha) - log = log @ np.linalg.matrix_power(target, 1 - alpha) - log = np.log2(np.trace(log)) + if len(target.shape) == 1: + target = np.outer(target, np.conj(target)) - log = (1 / (alpha - 1)) * log / np.log2(base) + log = _matrix_power(state, alpha, backend) + log = log @ _matrix_power(target, 1 - alpha, backend) + log = np.log2(np.trace(log)) - backend.assert_allclose( - relative_renyi_entropy(state, target, alpha=alpha, base=base, backend=backend), - log, - atol=1e-5, - ) + log = (1 / (alpha - 1)) * log / np.log2(base) + + backend.assert_allclose( + relative_renyi_entropy( + state, target, alpha=alpha, base=base, backend=backend + ), + log, + atol=1e-5, + ) # test pure states state = random_density_matrix(4, pure=True, backend=backend) @@ -626,7 +609,7 @@ def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): @pytest.mark.parametrize("base", [2, 10, np.e, 5]) -@pytest.mark.parametrize("alpha", [0, 1, 2, 3, np.inf]) +@pytest.mark.parametrize("alpha", [0, 1, 2, 3, 5.4]) def test_tsallis_entropy(backend, alpha, base): with pytest.raises(TypeError): state = np.random.rand(2, 3) @@ -648,7 +631,7 @@ def test_tsallis_entropy(backend, alpha, base): target = entropy(state, base=base, backend=backend) else: target = (1 / (1 - alpha)) * ( - np.trace(np.linalg.matrix_power(state, alpha)) - 1 + np.trace(_matrix_power(state, alpha, backend)) - 1 ) backend.assert_allclose( From d50888dd14f93ea0e05b3e53eba8ba8e91360975 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Thu, 1 Feb 2024 08:46:45 +0400 Subject: [PATCH 095/200] fix coverage --- tests/test_quantum_info_entropies.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index d709f76056..bb091196fb 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -614,16 +614,16 @@ def test_tsallis_entropy(backend, alpha, base): with pytest.raises(TypeError): state = np.random.rand(2, 3) state = backend.cast(state, dtype=state.dtype) - test = renyi_entropy(state, alpha=alpha, base=base, backend=backend) + test = tsallis_entropy(state, alpha=alpha, base=base, backend=backend) with pytest.raises(TypeError): state = random_statevector(4, backend=backend) - test = renyi_entropy(state, alpha="2", base=base, backend=backend) + test = tsallis_entropy(state, alpha="2", base=base, backend=backend) with pytest.raises(ValueError): state = random_statevector(4, backend=backend) - test = renyi_entropy(state, alpha=-1, base=base, backend=backend) + test = tsallis_entropy(state, alpha=-1, base=base, backend=backend) with pytest.raises(ValueError): state = random_statevector(4, backend=backend) - test = renyi_entropy(state, alpha=alpha, base=0, backend=backend) + test = tsallis_entropy(state, alpha=alpha, base=0, backend=backend) state = random_density_matrix(4, backend=backend) @@ -640,6 +640,12 @@ def test_tsallis_entropy(backend, alpha, base): atol=1e-5, ) + # test pure state + state = random_density_matrix(4, pure=True, backend=backend) + backend.assert_allclose( + tsallis_entropy(state, alpha=alpha, base=base, backend=backend), 0.0, atol=1e-5 + ) + @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) From bd8f5215b1444224ebd97aedebd06b4b284a0910 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Thu, 1 Feb 2024 09:25:21 +0400 Subject: [PATCH 096/200] fix coverage --- src/qibo/quantum_info/entropies.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index f1b3e08a68..0174df02b1 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -400,9 +400,6 @@ def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend= if alpha == 1.0: return shannon_entropy(prob_dist, base=base, backend=backend) - if isinstance(prob_dist, list): - prob_dist = backend.cast(prob_dist, dtype=np.float64) - return (1 / (1 - alpha)) * (np.sum(prob_dist**alpha) - 1) @@ -911,7 +908,10 @@ def entanglement_entropy( def _matrix_power(matrix, alpha, backend): """Calculates ``matrix ** alpha`` according to backend.""" - if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: + if backend.__class__.__name__ in [ + "CupyBackend", + "CuQuantumBackend", + ]: # pragma: no cover new_matrix = backend.to_numpy(matrix) else: new_matrix = np.copy(matrix) From 6decd8cef13786ac2c853351463214849a52c122 Mon Sep 17 00:00:00 2001 From: Alejandro Sopena Date: Fri, 2 Feb 2024 21:57:33 +0100 Subject: [PATCH 097/200] fix backend --- src/qibo/models/error_mitigation.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 2e2d577d2e..1f69c07a10 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -314,7 +314,8 @@ def CDR( train_val = {"noise-free": [], "noisy": []} for circ in training_circuits: - val = circ(nshots=nshots).expectation_from_samples(observable) + result = backend.execute_circuit(circ, nshots=nshots) + val = result.expectation_from_samples(observable) train_val["noise-free"].append(val) val = get_expectation_val_with_readout_mitigation( circ, observable, noise_model, nshots, readout, qubit_map, backend=backend @@ -400,7 +401,8 @@ def vnCDR( train_val = {"noise-free": [], "noisy": []} for circ in training_circuits: - val = circ(nshots=nshots).expectation_from_samples(observable) + result = backend.execute_circuit(circ, nshots=nshots) + val = result.expectation_from_samples(observable) train_val["noise-free"].append(val) for level in noise_levels: noisy_c = get_noisy_circuit(circ, level, insertion_gate=insertion_gate) @@ -897,7 +899,7 @@ def ICS( lambda_list = [] for training_circuit in training_circuits: - circuit_result = training_circuit(nshots=nshots) + circuit_result = backend.execute_circuit(training_circuit, nshots=nshots) expectation = observable.expectation_from_samples(circuit_result.frequencies()) noisy_expectation = get_expectation_val_with_readout_mitigation( From 9168a8784e5df469d2acce30a32fbbd4a9e8e563 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 04:17:21 +0000 Subject: [PATCH 098/200] Update src/qibo/quantum_info/entropies.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- src/qibo/quantum_info/entropies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 0174df02b1..30d2e746c7 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -610,7 +610,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None Another special case is the limit :math:`\\alpha \\to 0`, where the function is reduced to :math:`\\log\\left(d\\right)`, with :math:`d = 2^{n}` being the dimension of the Hilbert space in which ``state`` :math:`\\rho` lives in. - This is knows as the `Hartley entropy _` + This is knows as the `Hartley entropy `_ (also known as *Hartley function* or *max-entropy*). In the limit :math:`\\alpha \\to \\infty`, the function reduces to From ce78900e5c68900de952e70577b9a6a0ac24863f Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 12:21:05 +0400 Subject: [PATCH 099/200] Alejandro suggestion --- doc/source/api-reference/qibo.rst | 14 +++---- src/qibo/quantum_info/entropies.py | 12 +++--- tests/test_quantum_info_entropies.py | 61 +++++++++++++++++----------- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index e4f691487d..a91e1a9ee8 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1587,10 +1587,10 @@ Classical Tsallis entropy .. autofunction:: qibo.quantum_info.classical_tsallis_entropy -Entropy -""""""" +von Neumann entropy +""""""""""""""""""" -.. autofunction:: qibo.quantum_info.entropy +.. autofunction:: qibo.quantum_info.von_neumann_entropy .. note:: ``validate`` flag allows the user to choose if the function will check if input @@ -1600,10 +1600,10 @@ Entropy and ``state`` is non-Hermitian, an error will be raised when using `cupy` backend. -Relative entropy -"""""""""""""""" +Relative von Neumann entropy +"""""""""""""""""""""""""""" -.. autofunction:: qibo.quantum_info.relative_entropy +.. autofunction:: qibo.quantum_info.relative_von_neumann_entropy .. note:: ``validate`` flag allows the user to choose if the function will check if input @@ -1620,7 +1620,7 @@ Rényi entropy .. autofunction:: qibo.quantum_info.renyi_entropy -Rényi relative entropy +Relative Rényi entropy """""""""""""""""""""" .. autofunction:: qibo.quantum_info.renyi_relative_entropy diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 30d2e746c7..a577263039 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -403,7 +403,7 @@ def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend= return (1 / (1 - alpha)) * (np.sum(prob_dist**alpha) - 1) -def entropy( +def von_neumann_entropy( state, base: float = 2, check_hermitian: bool = False, @@ -488,7 +488,7 @@ def entropy( return ent -def relative_entropy( +def relative_von_neumann_entropy( state, target, base: float = 2, check_hermitian: bool = False, backend=None ): """Calculates the relative entropy :math:`S(\\rho \\, \\| \\, \\sigma)` between ``state`` :math:`\\rho` and ``target`` :math:`\\sigma`. @@ -660,7 +660,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None return np.log2(len(state)) / np.log2(base) if alpha == 1.0: - return entropy(state, base=base, backend=backend) + return von_neumann_entropy(state, base=base, backend=backend) if alpha == np.inf: return ( @@ -765,7 +765,7 @@ def relative_renyi_entropy( state = np.outer(state, np.conj(state)) if alpha == 1.0: - return relative_entropy(state, target, base, backend=backend) + return relative_von_neumann_entropy(state, target, base, backend=backend) if alpha == np.inf: new_state = _matrix_power(state, 0.5, backend) @@ -834,7 +834,7 @@ def tsallis_entropy(state, alpha: float, base: float = 2, backend=None): return 0.0 if alpha == 1.0: - return entropy(state, base=base, backend=backend) + return von_neumann_entropy(state, base=base, backend=backend) return (1 / (1 - alpha)) * (np.trace(_matrix_power(state, alpha, backend)) - 1) @@ -895,7 +895,7 @@ def entanglement_entropy( else backend.partial_trace_density_matrix(state, bipartition, nqubits) ) - entropy_entanglement = entropy( + entropy_entanglement = von_neumann_entropy( reduced_density_matrix, base=base, check_hermitian=check_hermitian, diff --git a/tests/test_quantum_info_entropies.py b/tests/test_quantum_info_entropies.py index bb091196fb..3cf8b2d721 100644 --- a/tests/test_quantum_info_entropies.py +++ b/tests/test_quantum_info_entropies.py @@ -10,12 +10,12 @@ classical_renyi_entropy, classical_tsallis_entropy, entanglement_entropy, - entropy, - relative_entropy, relative_renyi_entropy, + relative_von_neumann_entropy, renyi_entropy, shannon_entropy, tsallis_entropy, + von_neumann_entropy, ) from qibo.quantum_info.random_ensembles import ( random_density_matrix, @@ -342,33 +342,43 @@ def test_classical_tsallis_entropy(backend, alpha, base, kind): @pytest.mark.parametrize("check_hermitian", [False, True]) @pytest.mark.parametrize("base", [2, 10, np.e, 5]) -def test_entropy(backend, base, check_hermitian): +def test_von_neumann_entropy(backend, base, check_hermitian): with pytest.raises(TypeError): state = np.random.rand(2, 3) state = backend.cast(state, dtype=state.dtype) - test = entropy( + test = von_neumann_entropy( state, base=base, check_hermitian=check_hermitian, backend=backend ) with pytest.raises(ValueError): state = np.array([1.0, 0.0]) state = backend.cast(state, dtype=state.dtype) - test = entropy(state, base=0, check_hermitian=check_hermitian, backend=backend) + test = von_neumann_entropy( + state, base=0, check_hermitian=check_hermitian, backend=backend + ) with pytest.raises(TypeError): state = np.array([1.0, 0.0]) state = backend.cast(state, dtype=state.dtype) - test = entropy(state, base=base, check_hermitian="False", backend=backend) + test = von_neumann_entropy( + state, base=base, check_hermitian="False", backend=backend + ) if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: with pytest.raises(NotImplementedError): state = random_unitary(4, backend=backend) - test = entropy(state, base=base, check_hermitian=True, backend=backend) + test = von_neumann_entropy( + state, base=base, check_hermitian=True, backend=backend + ) else: state = random_unitary(4, backend=backend) - test = entropy(state, base=base, check_hermitian=True, backend=backend) + test = von_neumann_entropy( + state, base=base, check_hermitian=True, backend=backend + ) state = np.array([1.0, 0.0]) state = backend.cast(state, dtype=state.dtype) - backend.assert_allclose(entropy(state, backend=backend), 0.0, atol=PRECISION_TOL) + backend.assert_allclose( + von_neumann_entropy(state, backend=backend), 0.0, atol=PRECISION_TOL + ) state = np.array([1.0, 0.0, 0.0, 0.0]) state = np.outer(state, state) @@ -386,7 +396,10 @@ def test_entropy(backend, base, check_hermitian): test = 0.8613531161467861 backend.assert_allclose( - entropy(state, base, check_hermitian=check_hermitian, backend=backend), test + von_neumann_entropy( + state, base, check_hermitian=check_hermitian, backend=backend + ), + test, ) @@ -397,14 +410,14 @@ def test_relative_entropy(backend, base, check_hermitian): state = np.random.rand(2, 3) state = backend.cast(state, dtype=state.dtype) target = random_density_matrix(2, pure=True, backend=backend) - test = relative_entropy( + test = relative_von_neumann_entropy( state, target, base=base, check_hermitian=check_hermitian, backend=backend ) with pytest.raises(TypeError): target = np.random.rand(2, 3) target = backend.cast(target, dtype=target.dtype) state = random_density_matrix(2, pure=True, backend=backend) - test = relative_entropy( + test = relative_von_neumann_entropy( state, target, base=base, check_hermitian=check_hermitian, backend=backend ) with pytest.raises(ValueError): @@ -412,7 +425,7 @@ def test_relative_entropy(backend, base, check_hermitian): state = backend.cast(state, dtype=state.dtype) target = np.array([0.0, 1.0]) target = backend.cast(target, dtype=target.dtype) - test = relative_entropy( + test = relative_von_neumann_entropy( state, target, base=0, check_hermitian=check_hermitian, backend=backend ) with pytest.raises(TypeError): @@ -420,7 +433,7 @@ def test_relative_entropy(backend, base, check_hermitian): state = backend.cast(state, dtype=state.dtype) target = np.array([0.0, 1.0]) target = backend.cast(target, dtype=target.dtype) - test = relative_entropy( + test = relative_von_neumann_entropy( state, target, base=base, check_hermitian="False", backend=backend ) @@ -431,35 +444,37 @@ def test_relative_entropy(backend, base, check_hermitian): target = backend.identity_density_matrix(nqubits, normalize=True) backend.assert_allclose( - relative_entropy(state, target, base, check_hermitian, backend), + relative_von_neumann_entropy(state, target, base, check_hermitian, backend), np.log(dims) / np.log(base) - - entropy(state, base=base, check_hermitian=check_hermitian, backend=backend), + - von_neumann_entropy( + state, base=base, check_hermitian=check_hermitian, backend=backend + ), atol=1e-5, ) state = backend.cast([1.0, 0.0], dtype=np.float64) target = backend.cast([0.0, 1.0], dtype=np.float64) - assert relative_entropy(state, target, backend=backend) == 0.0 + assert relative_von_neumann_entropy(state, target, backend=backend) == 0.0 # for coverage when GPUs are present if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: with pytest.raises(NotImplementedError): state = random_unitary(4, backend=backend) target = random_density_matrix(4, backend=backend) - test = relative_entropy( + test = relative_von_neumann_entropy( state, target, base=base, check_hermitian=True, backend=backend ) with pytest.raises(NotImplementedError): target = random_unitary(4, backend=backend) state = random_density_matrix(4, backend=backend) - test = relative_entropy( + test = relative_von_neumann_entropy( state, target, base=base, check_hermitian=True, backend=backend ) else: state = random_unitary(4, backend=backend) target = random_unitary(4, backend=backend) - test = relative_entropy( + test = relative_von_neumann_entropy( state, target, base=base, check_hermitian=True, backend=backend ) @@ -486,7 +501,7 @@ def test_renyi_entropy(backend, alpha, base): if alpha == 0.0: target = np.log2(len(state)) / np.log2(base) elif alpha == 1.0: - target = entropy(state, base=base, backend=backend) + target = von_neumann_entropy(state, base=base, backend=backend) elif alpha == np.inf: target = backend.calculate_norm_density_matrix(state, order=2) target = -1 * np.log2(target) / np.log2(base) @@ -565,7 +580,7 @@ def test_relative_renyi_entropy(backend, alpha, base, state_flag, target_flag): relative_renyi_entropy(state, target, alpha, base, backend) else: if alpha == 1.0: - log = relative_entropy(state, target, base, backend=backend) + log = relative_von_neumann_entropy(state, target, base, backend=backend) elif alpha == np.inf: new_state = _matrix_power(state, 0.5, backend) new_target = _matrix_power(target, 0.5, backend) @@ -628,7 +643,7 @@ def test_tsallis_entropy(backend, alpha, base): state = random_density_matrix(4, backend=backend) if alpha == 1.0: - target = entropy(state, base=base, backend=backend) + target = von_neumann_entropy(state, base=base, backend=backend) else: target = (1 / (1 - alpha)) * ( np.trace(_matrix_power(state, alpha, backend)) - 1 From 8ac8c6ef67818686d658049d6df751b941583fde Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 12:25:26 +0400 Subject: [PATCH 100/200] Alejandro suggestion --- doc/source/api-reference/qibo.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index a91e1a9ee8..4f1fea5f24 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1593,10 +1593,10 @@ von Neumann entropy .. autofunction:: qibo.quantum_info.von_neumann_entropy .. note:: - ``validate`` flag allows the user to choose if the function will check if input - ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the + ``check_hermitian`` flag allows the user to choose if the function will check if input + ``state`` is Hermitian or not. Default option is ``check_hermitian=False``, i.e. the assumption of Hermiticity. This is faster and, more importantly, - this function are intended to be used on Hermitian inputs. When ``validate=True`` + this function are intended to be used on Hermitian inputs. When ``check_hermitian=True`` and ``state`` is non-Hermitian, an error will be raised when using `cupy` backend. @@ -1606,10 +1606,10 @@ Relative von Neumann entropy .. autofunction:: qibo.quantum_info.relative_von_neumann_entropy .. note:: - ``validate`` flag allows the user to choose if the function will check if input - ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the + ``check_hermitian`` flag allows the user to choose if the function will check if input + ``state`` is Hermitian or not. Default option is ``check_hermitian=False``, i.e. the assumption of Hermiticity. This is faster and, more importantly, - this function are intended to be used on Hermitian inputs. When ``validate=True`` + this function are intended to be used on Hermitian inputs. When ``check_hermitian=True`` and either ``state`` or ``target`` is non-Hermitian, an error will be raised when using `cupy` backend. @@ -1638,11 +1638,11 @@ Entanglement entropy .. autofunction:: qibo.quantum_info.entanglement_entropy .. note:: - ``validate`` flag allows the user to choose if the function will check if + ``check_hermitian`` flag allows the user to choose if the function will check if the reduced density matrix resulting from tracing out ``bipartition`` from input - ``state`` is Hermitian or not. Default option is ``validate=False``, i.e. the + ``state`` is Hermitian or not. Default option is ``check_hermitian=False``, i.e. the assumption of Hermiticity. This is faster and, more importantly, - this function are intended to be used on Hermitian inputs. When ``validate=True`` + this function are intended to be used on Hermitian inputs. When ``check_hermitian=True`` and the reduced density matrix is non-Hermitian, an error will be raised when using `cupy` backend. @@ -1671,11 +1671,11 @@ Trace distance .. autofunction:: qibo.quantum_info.trace_distance .. note:: - ``validate`` flag allows the user to choose if the function will check if difference + ``check_hermitian`` flag allows the user to choose if the function will check if difference between inputs, ``state - target``, is Hermitian or not. Default option is - ``validate=False``, i.e. the assumption of Hermiticity, because it is faster and, + ``check_hermitian=False``, i.e. the assumption of Hermiticity, because it is faster and, more importantly, the functions are intended to be used on Hermitian inputs. - When ``validate=True`` and ``state - target`` is non-Hermitian, an error will be + When ``check_hermitian=True`` and ``state - target`` is non-Hermitian, an error will be raised when using `cupy` backend. From dd6e31ac4011bb39030b5dc440cfbbb1a3c71d16 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 13:10:18 +0400 Subject: [PATCH 101/200] initial commit --- src/qibo/transpiler/decompositions.py | 50 ++++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index cb106d423b..cbefc02dc9 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -116,7 +116,7 @@ def _u3_to_gpi2(t, p, l): # Decompose single qubit gates using U3 u3_dec = GateDecompositions() -u3_dec.add(gates.H, [gates.U3(0, 7 * np.pi / 2, np.pi, 0)]) +u3_dec.add(gates.H, [gates.U3(0, -np.pi / 2, np.pi, 0)]) u3_dec.add(gates.X, [gates.U3(0, np.pi, 0, np.pi)]) u3_dec.add(gates.Y, [gates.U3(0, np.pi, 0, 0)]) u3_dec.add(gates.Z, [gates.Z(0)]) @@ -159,28 +159,28 @@ def _u3_to_gpi2(t, p, l): gates.CNOT, [ gates.U3(0, 3 * np.pi / 2, np.pi, 0), - gates.U3(1, np.pi / 2, -np.pi, -np.pi), + gates.U3(1, np.pi / 2, np.pi, np.pi), gates.iSWAP(0, 1), gates.U3(0, np.pi, 0, np.pi), - gates.U3(1, np.pi / 2, -np.pi, -np.pi), + gates.U3(1, np.pi / 2, np.pi, np.pi), gates.iSWAP(0, 1), - gates.U3(0, np.pi / 2, np.pi / 2, -np.pi), - gates.U3(1, np.pi / 2, -np.pi, -np.pi / 2), + gates.U3(0, np.pi / 2, np.pi / 2, np.pi), + gates.U3(1, np.pi / 2, np.pi, -np.pi / 2), ], ) iswap_dec.add( gates.CZ, [ - gates.U3(0, 7 * np.pi / 2, np.pi, 0), - gates.U3(1, 7 * np.pi / 2, np.pi, 0), - gates.U3(1, np.pi / 2, -np.pi, -np.pi), + gates.U3(0, -np.pi / 2, np.pi, 0), + gates.U3(1, -np.pi / 2, np.pi, 0), + gates.U3(1, np.pi / 2, np.pi, np.pi), gates.iSWAP(0, 1), gates.U3(0, np.pi, 0, np.pi), - gates.U3(1, np.pi / 2, -np.pi, -np.pi), + gates.U3(1, np.pi / 2, np.pi, np.pi), gates.iSWAP(0, 1), - gates.U3(0, np.pi / 2, np.pi / 2, -np.pi), - gates.U3(1, np.pi / 2, -np.pi, -np.pi / 2), - gates.U3(1, 7 * np.pi / 2, np.pi, 0), + gates.U3(0, np.pi / 2, np.pi / 2, np.pi), + gates.U3(1, np.pi / 2, np.pi, -np.pi / 2), + gates.U3(1, -np.pi / 2, np.pi, 0), ], ) iswap_dec.add( @@ -304,14 +304,14 @@ def _u3_to_gpi2(t, p, l): cz_dec.add( gates.FSWAP, [ - gates.U3(0, np.pi / 2, -np.pi / 2, -np.pi), + gates.U3(0, np.pi / 2, -np.pi / 2, np.pi), gates.U3(1, np.pi / 2, np.pi / 2, np.pi / 2), gates.CZ(0, 1), gates.U3(0, np.pi / 2, 0, -np.pi / 2), gates.U3(1, np.pi / 2, 0, np.pi / 2), gates.CZ(0, 1), - gates.U3(0, np.pi / 2, np.pi / 2, -np.pi), - gates.U3(1, np.pi / 2, 0, -np.pi), + gates.U3(0, np.pi / 2, np.pi / 2, np.pi), + gates.U3(1, np.pi / 2, 0, np.pi), ], ) cz_dec.add( @@ -328,7 +328,7 @@ def _u3_to_gpi2(t, p, l): gates.RYY, lambda gate: [ gates.RX(0, np.pi / 2), - gates.U3(1, np.pi / 2, np.pi / 2, -np.pi), + gates.U3(1, np.pi / 2, np.pi / 2, np.pi), gates.CZ(0, 1), gates.RX(1, gate.parameters[0]), gates.CZ(0, 1), @@ -392,3 +392,21 @@ def _u3_to_gpi2(t, p, l): gates.H(1), ], ) + + +# standard gate decompositions used by :meth:`qibo.gates.gates.Gate.decompose` +standard = GateDecompositions() +standard.add(gates.SX, [gates.RX(0, np.pi / 2, trainable=False)]) +standard.add(gates.SXDG, [gates.RX(0, -np.pi / 2, trainable=False)]) +standard.add(gates.U3, [gates.RZ, gates.SX, gates.RZ, gates.SX, gates.RZ]) +standard.add(gates.CY, [gates.SDG, gates.CNOT, gates.S]) +standard.add(gates.CZ, [gates.H, gates.CNOT, gates.H]) +standard.add(gates.CSX, []) +standard.add(gates.CSXDG, []) +standard.add(gates.FSWAP, []) +standard.add(gates.RZX, []) +standard.add(gates.RXXYY, []) +standard.add(gates.GIVENS, []) +standard.add(gates.RBS, []) +standard.add(gates.ECR, []) +standard.add(gates.TOFFOLI, []) From b8b95813a31e575dd1ae2e73938ffbaf8c68ea41 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 14:13:04 +0000 Subject: [PATCH 102/200] Update doc/source/api-reference/qibo.rst Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- doc/source/api-reference/qibo.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 4f1fea5f24..b2405a01c0 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1623,7 +1623,7 @@ Rényi entropy Relative Rényi entropy """""""""""""""""""""" -.. autofunction:: qibo.quantum_info.renyi_relative_entropy +.. autofunction:: qibo.quantum_info.relative_renyi_entropy Tsallis entropy From ba3de9c3173018d21791bb86afc11b45cb501e3a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 18:40:02 +0400 Subject: [PATCH 103/200] fix local state and backend --- src/qibo/quantum_info/random_ensembles.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index ddccc3b6f0..8c61aa38b7 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -419,19 +419,7 @@ def random_statevector(dims: int, seed=None, backend=None): TypeError, "seed must be either type int or numpy.random.Generator." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() - - if seed is None or isinstance(seed, int): - if backend.__class__.__name__ in [ - "CupyBackend", - "CuQuantumBackend", - ]: # pragma: no cover - local_state = backend.np.random.default_rng(seed) - else: - local_state = np.random.default_rng(seed) - else: - local_state = seed + backend, local_state = _set_backend_and_local_state(seed, backend) state = local_state.standard_normal(dims).astype(complex) state += 1.0j * local_state.standard_normal(dims) From 230f5853a34e0eea122c0bac4fe8ea6166029cf0 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 15:01:58 +0000 Subject: [PATCH 104/200] Update src/qibo/quantum_info/entropies.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- src/qibo/quantum_info/entropies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index a577263039..c303c37f0a 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -172,7 +172,7 @@ def classical_renyi_entropy( Another special case is the limit :math:`\\alpha \\to 0`, where the function is reduced to :math:`\\log\\left(|\\mathbf{p}|\\right)`, with :math:`|\\mathbf{p}|` being the support of :math:`\\mathbf{p}`. - This is knows as the `Hartley entropy `_ + This is known as the `Hartley entropy `_ (also known as *Hartley function* or *max-entropy*). In the limit :math:`\\alpha \\to \\infty`, the function reduces to From 9e761fb9617fe18c471436391246b6521c35c369 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 3 Feb 2024 15:02:06 +0000 Subject: [PATCH 105/200] Update src/qibo/quantum_info/entropies.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- src/qibo/quantum_info/entropies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index c303c37f0a..0108bcddbc 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -610,7 +610,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None Another special case is the limit :math:`\\alpha \\to 0`, where the function is reduced to :math:`\\log\\left(d\\right)`, with :math:`d = 2^{n}` being the dimension of the Hilbert space in which ``state`` :math:`\\rho` lives in. - This is knows as the `Hartley entropy `_ + This is known as the `Hartley entropy `_ (also known as *Hartley function* or *max-entropy*). In the limit :math:`\\alpha \\to \\infty`, the function reduces to From 287528256b3cdbb15489a63e1873e1fe6a0050d6 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 4 Feb 2024 04:08:28 +0000 Subject: [PATCH 106/200] Update src/qibo/quantum_info/random_ensembles.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- src/qibo/quantum_info/random_ensembles.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 8c61aa38b7..dd66a7e0a6 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -424,6 +424,7 @@ def random_statevector(dims: int, seed=None, backend=None): state = local_state.standard_normal(dims).astype(complex) state += 1.0j * local_state.standard_normal(dims) state /= np.linalg.norm(state) + state = backend.cast(state, dtype=state.dtype) return backend.cast(state, dtype=state.dtype) From 5192b14599a79b95ec684ab9f0296ea863dd2f82 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 4 Feb 2024 04:08:34 +0000 Subject: [PATCH 107/200] Update src/qibo/quantum_info/random_ensembles.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- src/qibo/quantum_info/random_ensembles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index dd66a7e0a6..3d11c0d1ce 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -426,7 +426,7 @@ def random_statevector(dims: int, seed=None, backend=None): state /= np.linalg.norm(state) state = backend.cast(state, dtype=state.dtype) - return backend.cast(state, dtype=state.dtype) + return state def random_density_matrix( From 2bfd6ecbad2b348a7f4b47bbb033e25160aea742 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 4 Feb 2024 04:08:54 +0000 Subject: [PATCH 108/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/random_ensembles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 3d11c0d1ce..18e2eedaa1 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -424,7 +424,7 @@ def random_statevector(dims: int, seed=None, backend=None): state = local_state.standard_normal(dims).astype(complex) state += 1.0j * local_state.standard_normal(dims) state /= np.linalg.norm(state) - state = backend.cast(state, dtype=state.dtype) + state = backend.cast(state, dtype=state.dtype) return state From 645e6f1eec20cc8f5c59db6d7a1309334019dc6b Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 4 Feb 2024 08:36:46 +0400 Subject: [PATCH 109/200] testing function --- src/qibo/transpiler/decompositions.py | 34 +++++++++++++++------------ 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index cbefc02dc9..56901c8920 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -1,3 +1,4 @@ +#%% import numpy as np from qibo import gates @@ -395,18 +396,21 @@ def _u3_to_gpi2(t, p, l): # standard gate decompositions used by :meth:`qibo.gates.gates.Gate.decompose` -standard = GateDecompositions() -standard.add(gates.SX, [gates.RX(0, np.pi / 2, trainable=False)]) -standard.add(gates.SXDG, [gates.RX(0, -np.pi / 2, trainable=False)]) -standard.add(gates.U3, [gates.RZ, gates.SX, gates.RZ, gates.SX, gates.RZ]) -standard.add(gates.CY, [gates.SDG, gates.CNOT, gates.S]) -standard.add(gates.CZ, [gates.H, gates.CNOT, gates.H]) -standard.add(gates.CSX, []) -standard.add(gates.CSXDG, []) -standard.add(gates.FSWAP, []) -standard.add(gates.RZX, []) -standard.add(gates.RXXYY, []) -standard.add(gates.GIVENS, []) -standard.add(gates.RBS, []) -standard.add(gates.ECR, []) -standard.add(gates.TOFFOLI, []) +standard_decompositions = GateDecompositions() +standard_decompositions.add(gates.SX, [gates.RX(0, np.pi / 2, trainable=False)]) +standard_decompositions.add(gates.SXDG, [gates.RX(0, -np.pi / 2, trainable=False)]) +standard_decompositions.add( + gates.U3, + lambda gate: [gates.RZ(0, gate.parameters[2]), gates.SX(0), gates.RZ(0, gate.parameters[0] + np.pi), gates.SX(0), gates.RZ(0, gate.parameters[1] + np.pi)], +) +standard_decompositions.add(gates.CY, [gates.SDG, gates.CNOT, gates.S]) +standard_decompositions.add(gates.CZ, [gates.H, gates.CNOT, gates.H]) +standard_decompositions.add(gates.CSX, []) +standard_decompositions.add(gates.CSXDG, []) +standard_decompositions.add(gates.FSWAP, []) +standard_decompositions.add(gates.RZX, []) +standard_decompositions.add(gates.RXXYY, []) +standard_decompositions.add(gates.GIVENS, []) +standard_decompositions.add(gates.RBS, []) +standard_decompositions.add(gates.ECR, []) +standard_decompositions.add(gates.TOFFOLI, []) From 62971ea411e7f29cbcc3a79a2b03d7b4899d5554 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 4 Feb 2024 04:37:13 +0000 Subject: [PATCH 110/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/transpiler/decompositions.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index 56901c8920..72e49154fd 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -1,4 +1,4 @@ -#%% +# %% import numpy as np from qibo import gates @@ -400,8 +400,14 @@ def _u3_to_gpi2(t, p, l): standard_decompositions.add(gates.SX, [gates.RX(0, np.pi / 2, trainable=False)]) standard_decompositions.add(gates.SXDG, [gates.RX(0, -np.pi / 2, trainable=False)]) standard_decompositions.add( - gates.U3, - lambda gate: [gates.RZ(0, gate.parameters[2]), gates.SX(0), gates.RZ(0, gate.parameters[0] + np.pi), gates.SX(0), gates.RZ(0, gate.parameters[1] + np.pi)], + gates.U3, + lambda gate: [ + gates.RZ(0, gate.parameters[2]), + gates.SX(0), + gates.RZ(0, gate.parameters[0] + np.pi), + gates.SX(0), + gates.RZ(0, gate.parameters[1] + np.pi), + ], ) standard_decompositions.add(gates.CY, [gates.SDG, gates.CNOT, gates.S]) standard_decompositions.add(gates.CZ, [gates.H, gates.CNOT, gates.H]) From a7ac562498f5678679659944dc18303ae46066d2 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 4 Feb 2024 09:43:36 +0400 Subject: [PATCH 111/200] implement refactoring --- src/qibo/gates/gates.py | 124 +++++++++++++------------- src/qibo/transpiler/decompositions.py | 69 +++++++++++--- 2 files changed, 118 insertions(+), 75 deletions(-) diff --git a/src/qibo/gates/gates.py b/src/qibo/gates/gates.py index aa0e0d5ede..588145a5dc 100644 --- a/src/qibo/gates/gates.py +++ b/src/qibo/gates/gates.py @@ -271,7 +271,11 @@ def decompose(self): being the :class:`qibo.gates.RX` gate. More precisely, :math:`\\sqrt{X} = e^{i \\pi / 4} \\, \\text{RX}(\\pi / 2)`. """ - return [RX(self.init_args[0], np.pi / 2, trainable=False)] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) def _dagger(self): """""" @@ -314,7 +318,11 @@ def decompose(self): being the :class:`qibo.gates.RX` gate. More precisely, :math:`(\\sqrt{X})^{\\dagger} = e^{-i \\pi / 4} \\, \\text{RX}(-\\pi / 2)`. """ - return [RX(self.init_args[0], -np.pi / 2, trainable=False)] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) def _dagger(self): """""" @@ -892,14 +900,11 @@ def decompose(self) -> List[Gate]: where :math:`\\text{RZ}` and :math:`\\sqrt{X}` are, respectively, :class:`qibo.gates.RZ` and :class`qibo.gates.SX`. """ - q = self.init_args[0] - return [ - RZ(q, self.init_kwargs["lam"]), - SX(q), - RZ(q, self.init_kwargs["theta"] + math.pi), - SX(q), - RZ(q, self.init_kwargs["phi"] + math.pi), - ] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class U1q(_Un_): @@ -1020,8 +1025,11 @@ def decompose(self) -> List[Gate]: the target qubit, followed by :class:`qibo.gates.CNOT`, followed by a :class:`qibo.gates.S` in the target qubit. """ - q0, q1 = self.init_args - return [SDG(q1), CNOT(q0, q1), S(q1)] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class CZ(Gate): @@ -1063,8 +1071,11 @@ def decompose(self) -> List[Gate]: the target qubit, followed by :class:`qibo.gates.CNOT`, followed by another :class:`qibo.gates.H` in the target qubit """ - q0, q1 = self.init_args - return [H(q1), CNOT(q0, q1), H(q1)] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class CSX(Gate): @@ -1100,8 +1111,11 @@ def qasm_label(self): def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]: """""" - q0, q1 = self.init_args - return [H(q1), CU1(q0, q1, np.pi / 2), H(q1)] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) def _dagger(self): """""" @@ -1141,8 +1155,11 @@ def qasm_label(self): def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]: """""" - q0, q1 = self.init_args - return [H(q1), CU1(q0, q1, -np.pi / 2), H(q1)] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) def _dagger(self): """""" @@ -1868,9 +1885,11 @@ def __init__(self, q0, q1, theta, trainable=True): def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]: """""" - q0, q1 = self.target_qubits - theta = self.init_kwargs["theta"] - return [H(q1), CNOT(q0, q1), RZ(q1, theta), CNOT(q0, q1), H(q1)] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class RXXYY(_Rnn_): @@ -1909,22 +1928,11 @@ def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]: the original gate due to a phase difference in :math:`\\left(\\sqrt{X}\\right)^{\\dagger}`. """ - q0, q1 = self.target_qubits - theta = self.init_kwargs["theta"] - return [ - RZ(q1, -np.pi / 2), - S(q0), - SX(q1), - RZ(q1, np.pi / 2), - CNOT(q1, q0), - RY(q0, -theta / 2), - RY(q1, -theta / 2), - CNOT(q1, q0), - SDG(q0), - RZ(q1, -np.pi / 2), - SX(q1).dagger(), - RZ(q1, np.pi / 2), - ] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class MS(ParametrizedGate): @@ -2029,18 +2037,13 @@ def _dagger(self) -> "Gate": return self.__class__(*self.target_qubits, -self.parameters[0]) def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]: - """Decomposition of Givens gate according to `ArXiv:2106.13839 - `_.""" - q0, q1 = self.target_qubits - theta = self.init_kwargs["theta"] - return [ - CNOT(q0, q1), - RY(q0, theta), - CNOT(q1, q0), - RY(q0, -theta), - CNOT(q1, q0), - CNOT(q0, q1), - ] + """Decomposition of RBS gate according to `ArXiv:2109.09685 + `_.""" + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class RBS(ParametrizedGate): @@ -2090,18 +2093,11 @@ def _dagger(self) -> "Gate": def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]: """Decomposition of RBS gate according to `ArXiv:2109.09685 `_.""" - q0, q1 = self.target_qubits - theta = self.init_kwargs["theta"] - return [ - H(q0), - CNOT(q0, q1), - H(q1), - RY(q0, theta), - RY(q1, -theta), - H(q1), - CNOT(q0, q1), - H(q0), - ] + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) + + return standard_decompositions(self) class ECR(Gate): @@ -2142,9 +2138,11 @@ def decompose(self, *free, use_toffolis: bool = True) -> List[Gate]: \\textup{ECR} = e^{i 7 \\pi / 4} \\, S(q_{0}) \\, \\sqrt{X}(q_{1}) \\, \\textup{CNOT}(q_{0}, q_{1}) \\, X(q_{0}) """ + from qibo.transpiler.decompositions import ( # pylint: disable=C0415 + standard_decompositions, + ) - q0, q1 = self.target_qubits - return [S(q0), SX(q1), CNOT(q0, q1), X(q0)] + return standard_decompositions(self) class TOFFOLI(Gate): diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index 72e49154fd..813549e046 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -1,4 +1,3 @@ -# %% import numpy as np from qibo import gates @@ -409,14 +408,60 @@ def _u3_to_gpi2(t, p, l): gates.RZ(0, gate.parameters[1] + np.pi), ], ) -standard_decompositions.add(gates.CY, [gates.SDG, gates.CNOT, gates.S]) -standard_decompositions.add(gates.CZ, [gates.H, gates.CNOT, gates.H]) -standard_decompositions.add(gates.CSX, []) -standard_decompositions.add(gates.CSXDG, []) -standard_decompositions.add(gates.FSWAP, []) -standard_decompositions.add(gates.RZX, []) -standard_decompositions.add(gates.RXXYY, []) -standard_decompositions.add(gates.GIVENS, []) -standard_decompositions.add(gates.RBS, []) -standard_decompositions.add(gates.ECR, []) -standard_decompositions.add(gates.TOFFOLI, []) +standard_decompositions.add(gates.CY, [gates.SDG(1), gates.CNOT(0, 1), gates.S(1)]) +standard_decompositions.add(gates.CZ, [gates.H(1), gates.CNOT(0, 1), gates.H(1)]) +standard_decompositions.add( + gates.CSX, [gates.H(1), gates.CU1(0, 1, np.pi / 2), gates.H(1)] +) +standard_decompositions.add( + gates.CSXDG, [gates.H(1), gates.CU1(0, 1, -np.pi / 2), gates.H(1)] +) +standard_decompositions.add( + gates.FSWAP, [gates.X(1)] + gates.GIVENS(0, 1, np.pi / 2).decompose() + [gates.X(0)] +) +standard_decompositions.add( + gates.RZX, + lambda gate: [ + gates.H(1), + gates.CNOT(0, 1), + gates.RZ(1, gate.parameters[0]), + gates.CNOT(0, 1), + gates.H(1), + ], +) +standard_decompositions.add( + gates.RXXYY, + lambda gate: [ + gates.RZ(1, -np.pi / 2), + gates.S(0), + gates.SX(1), + gates.RZ(1, np.pi / 2), + gates.CNOT(1, 0), + gates.RY(0, -gate.parameters[0] / 2), + gates.RY(1, -gate.parameters[0] / 2), + gates.CNOT(1, 0), + gates.SDG(0), + gates.RZ(1, -np.pi / 2), + gates.SX(1).dagger(), + gates.RZ(1, np.pi / 2), + ], +) +standard_decompositions.add( + gates.GIVENS, lambda gate: gates.RBS(0, 1, -gate.parameters[1]).decompose() +) +standard_decompositions.add( + gates.RBS, + lambda gate: [ + gates.H(0), + gates.CNOT(0, 1), + gates.H(1), + gates.RY(0, gate.parameters[0]), + gates.RY(1, -gate.parameters[0]), + gates.H(1), + gates.CNOT(0, 1), + gates.H(0), + ], +) +standard_decompositions.add( + gates.ECR, [gates.S(0), gates.SX(1), gates.CNOT(0, 1), gates.X(0)] +) From a86e2acab1488fcadd254a5ca059c8f481cfd71e Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 4 Feb 2024 10:17:53 +0400 Subject: [PATCH 112/200] fix order --- src/qibo/transpiler/decompositions.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index 813549e046..b36ff1c139 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -416,9 +416,6 @@ def _u3_to_gpi2(t, p, l): standard_decompositions.add( gates.CSXDG, [gates.H(1), gates.CU1(0, 1, -np.pi / 2), gates.H(1)] ) -standard_decompositions.add( - gates.FSWAP, [gates.X(1)] + gates.GIVENS(0, 1, np.pi / 2).decompose() + [gates.X(0)] -) standard_decompositions.add( gates.RZX, lambda gate: [ @@ -446,9 +443,6 @@ def _u3_to_gpi2(t, p, l): gates.RZ(1, np.pi / 2), ], ) -standard_decompositions.add( - gates.GIVENS, lambda gate: gates.RBS(0, 1, -gate.parameters[1]).decompose() -) standard_decompositions.add( gates.RBS, lambda gate: [ @@ -462,6 +456,12 @@ def _u3_to_gpi2(t, p, l): gates.H(0), ], ) +standard_decompositions.add( + gates.GIVENS, lambda gate: gates.RBS(0, 1, -gate.parameters[1]).decompose() +) +standard_decompositions.add( + gates.FSWAP, [gates.X(1)] + gates.GIVENS(0, 1, np.pi / 2).decompose() + [gates.X(0)] +) standard_decompositions.add( gates.ECR, [gates.S(0), gates.SX(1), gates.CNOT(0, 1), gates.X(0)] ) From 2a7b55b479c6fb7a98fa9521017752424df04052 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 4 Feb 2024 10:31:46 +0400 Subject: [PATCH 113/200] fix bug --- src/qibo/transpiler/decompositions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index b36ff1c139..f559f0088a 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -457,7 +457,7 @@ def _u3_to_gpi2(t, p, l): ], ) standard_decompositions.add( - gates.GIVENS, lambda gate: gates.RBS(0, 1, -gate.parameters[1]).decompose() + gates.GIVENS, lambda gate: gates.RBS(0, 1, -gate.parameters[0]).decompose() ) standard_decompositions.add( gates.FSWAP, [gates.X(1)] + gates.GIVENS(0, 1, np.pi / 2).decompose() + [gates.X(0)] From 330200828ac5dc3d41244e4fa0c698b2a94fceb9 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 5 Feb 2024 10:29:08 +0400 Subject: [PATCH 114/200] functions --- src/qibo/models/encodings.py | 46 +++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/qibo/models/encodings.py b/src/qibo/models/encodings.py index a85024ad3c..ba0e5a4352 100644 --- a/src/qibo/models/encodings.py +++ b/src/qibo/models/encodings.py @@ -70,6 +70,47 @@ def comp_basis_encoder( return circuit +def phase_encoder(data, rotation: str = "RY"): + """Creates circuit that performs the phase encoding of ``data``. + + Args: + data (ndarray or list): :math:`1`-dimensional array of phases to be loaded. + rotation (str, optional): If ``"RX"``, uses :class:`qibo.gates.gates.RX` as rotation. + If ``"RY"``, uses :class:`qibo.gates.gates.RY` as rotation. + If ``"RZ"``, uses :class:`qibo.gates.gates.RZ` as rotation. + Defaults to ``"RY"``. + + Returns: + :class:`qibo.models.circuit.Circuit`: circuit that loads ``data`` in phase encoding. + """ + if isinstance(data, list): + data = np.array(data) + + if len(data.shape) != 1: + raise_error( + TypeError, + f"``data`` must be a 1-dimensional array, but it has dimensions {data.shape}.", + ) + + if not isinstance(rotation, str): + raise_error( + TypeError, + f"``rotation`` must be type str, but it is type {type(rotation)}.", + ) + + if rotation not in ["RX", "RY", "RZ"]: + raise_error(ValueError, f"``rotation`` {rotation} not found.") + + nqubits = len(data) + gate = getattr(gates, rotation.upper()) + + circuit = Circuit(nqubits) + circuit.add(gate(qubit, 0.0) for qubit in range(nqubits)) + circuit.set_parameters(data) + + return circuit + + def unary_encoder(data, architecture: str = "tree"): """Creates circuit that performs the unary encoding of ``data``. @@ -91,7 +132,7 @@ def unary_encoder(data, architecture: str = "tree"): :math:`d`. Args: - data (ndarray, optional): :math:`1`-dimensional array of data to be loaded. + data (ndarray): :math:`1`-dimensional array of data to be loaded. architecture(str, optional): circuit architecture used for the unary loader. If ``diagonal``, uses a ladder-like structure. If ``tree``, uses a binary-tree-based structure. @@ -104,6 +145,9 @@ def unary_encoder(data, architecture: str = "tree"): 1. S. Johri *et al.*, *Nearest Centroid Classification on a Trapped Ion Quantum Computer*. `arXiv:2012.04145v2 [quant-ph] `_. """ + if isinstance(data, list): + data = np.array(data) + if len(data.shape) != 1: raise_error( TypeError, From 743e3acc7c7844f81363903b0e694560b07e86e7 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 5 Feb 2024 10:29:16 +0400 Subject: [PATCH 115/200] tests --- tests/test_models_encodings.py | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/test_models_encodings.py b/tests/test_models_encodings.py index b71faa5c97..ac997460c2 100644 --- a/tests/test_models_encodings.py +++ b/tests/test_models_encodings.py @@ -1,6 +1,7 @@ """Tests for qibo.models.encodings""" import math +from itertools import product import numpy as np import pytest @@ -8,6 +9,7 @@ from qibo.models.encodings import ( comp_basis_encoder, + phase_encoder, unary_encoder, unary_encoder_random_gaussian, ) @@ -48,6 +50,54 @@ def test_comp_basis_encoder(backend, basis_element): backend.assert_allclose(state, target) +@pytest.mark.parametrize("kind", [None, list]) +@pytest.mark.parametrize("rotation", ["RX", "RY", "RZ"]) +def test_phase_encoder(backend, rotation, kind): + sampler = np.random.default_rng(1) + + nqubits = 3 + dims = 2**nqubits + + with pytest.raises(TypeError): + data = sampler.random((nqubits, nqubits)) + data = backend.cast(data, dtype=data.dtype) + phase_encoder(data, rotation=rotation) + with pytest.raises(TypeError): + data = sampler.random(nqubits) + data = backend.cast(data, dtype=data.dtype) + phase_encoder(data, rotation=True) + with pytest.raises(ValueError): + data = sampler.random(nqubits) + data = backend.cast(data, dtype=data.dtype) + phase_encoder(data, rotation="rzz") + + phases = np.random.rand(nqubits) + + if rotation in ["RX", "RY"]: + functions = list(product([np.cos, np.sin], repeat=nqubits)) + target = [] + for row in functions: + elem = 1.0 + for phase, func in zip(phases, row): + elem *= func(phase / 2) + if rotation == "RX" and func.__name__ == "sin": + elem *= -1.0j + target.append(elem) + else: + target = [np.exp(-0.5j * sum(phases))] + [0.0] * (dims - 1) + + target = np.array(target, dtype=complex) + target = backend.cast(target, dtype=target.dtype) + + if kind is not None: + phases = kind(phases) + + state = phase_encoder(phases, rotation=rotation) + state = backend.execute_circuit(state).state() + + backend.assert_allclose(state, target) + + @pytest.mark.parametrize("architecture", ["tree", "diagonal"]) @pytest.mark.parametrize("nqubits", [8]) def test_unary_encoder(backend, nqubits, architecture): From a8994b09f39ec4c51d98a4bce51baa0105060960 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 5 Feb 2024 10:57:57 +0400 Subject: [PATCH 116/200] add image to doc --- doc/source/_static/phase_encoder.png | Bin 0 -> 199388 bytes doc/source/api-reference/qibo.rst | 36 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 doc/source/_static/phase_encoder.png diff --git a/doc/source/_static/phase_encoder.png b/doc/source/_static/phase_encoder.png new file mode 100644 index 0000000000000000000000000000000000000000..df6796e1d92e6aef5a8b19a744f02584e5eb39d5 GIT binary patch literal 199388 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

?Fu1MGiR@&Jt=#Kwn|+kiU{JlGfDl;68rDPPdnv zjV4lnQ?NS%3o2+WK{QM-0hE$}-sq~4bn=|H*nUaX7DB3nw`o5Gg6i~G+|uRpbHS@1 zol>UXJH&SG4> z0LiZIhb9=RxQrz`Yg`dE(d&GtUsU=_7~dOc?wF6YX-Vw1_%s5g!((n3!HA|B8KlaC zF?>#_jX@Gq*Eynl&)@-y1g4WjAbR9@ZC_^TK}m<#0`yy6ZZ7ids{bl4ow!dq@@i`a*^d_QbkF@& zal*|dXDCnyxE<@bjrzV&~(uUrGi`&AvL`DXH(=W^q4U&sfBQ(+-v4y zi5QO_d?{t?Qeeq$HOV_I|Ql~0~M+yWqb=NT2@so;*+&Cew z{Zr&d#)|(a&y6C&cB>x^@=yCd(*Tc##eAZ?s0===ca%89QW=@LNUTE>-{IIn*p50q zM=Cy~>VA&?kV6zS{rRB|ya#z4F}pJVAio|`5{O+mABZC)kUDXdJi>&tdqja(b-mTO zBU?wlU_qJUg$0S~;4UcwD^;Xf6usrd_MA+Xo>lxfqJBK9xM!PahZBax&-k~_*T*@0 zG!&>GPgb>O-Bn1A-?R=cA*J4{GI(r`==y4!mtXG;1WYOMIUt>vhXX zR3^x!vBD-pdHdoA_QFbU7gG!No&~ZdHd|^6VzdhJhX*&pilyJhlM$E|v*PfwagHO* z`}qGDoP4qaU*3< zj@UBu?M*4R>Yl)_gay}zyr$&Ry-j1T zEH1Y}Pydau;_@X@uCiStaOaSa--ztvM}>sqc~>Qyge71@;6wo+6OdCKRmY;R&%cEh zX1{I0uD0%7n63B&LN)xK7WK4?h6`4(2p>%Tgw~gA=!`^bZIStPNbB#E!Fy$hw0b~5 zfUlG{F~9=nZsp3XlrHxU#(=ko-edaw>`3$4jJ9493fy8D+#9pJnz`lUWmtg;Gr*;d z`m$2{z9EwUP=`YU!F9GHvTT2{jFpmO$q8h*%s*?Jlh9-7)vw{s*ydv^m`;sPVl(T~ zk}qNX4e!?zMT!1S+o($(*{@@`khp>hu!K?;C(pP0({%5TLG+9hLRWp?(UoNwCjQI% z(aPMpj3EAdVJwP^*an1UTX${*t7WBn(_HEEK3UDP+&3zC;Y~SKA=u0LCX4IUua3Yt zkXh9|Nxt-fJ|s)TcPLP}+x@<7Q9 zZvi$>pXr-BG!o6gi6Y2iOdRS50FXWEj zn2fwZX=bWFUdZDQ@9J^c=1xJ0K2PNV-M99Z8WkKFh05}SdP|9ewMkSuEV7T@>TzHM zdZ`q>O{w?22hX$eOVkIwERLzdh7?7VBiYQFT|sL!H$JjpoGL9Fg6J5hFUrlOj5P6_ zS4Quu$Sf@gwGBvUhxCV(Thiw=`}Fot{zGCWqedv58qw2?PZOs4((wPdo~^nS>^E2~ zx%S*FF7+yiV2+aF2tFAe;Ghz?3zi@oO><2(G<7AL1`42T-!L6%{ z(t&uuaD~#ye!BtD)XugUW{l|m9#(Clw+xTWPR!Lz0w(P0TX9$=i-?sy!A_8;O@MZj zjiNU_!@ zEDML_SF$k+A>Xji_iamE1Ci7!uMel7nM zx&pZ(3S6&_CCsC$den9$1rrxC6s$orj>kNuTgDvgfXwe-xg6vC22EXsGK)dI^4`F) zR~4HW8HS__s>*gM+D3yj=EW+|NJi#{}=X|@r9Tk9ujK*G7<3)p-{wt&TQTz z6-!a^KG|x<62uq3y`3noT3ZB(6p!WAys)fsK4OqxXSXoF8j=@?e}zheZ7>%koKZ>! zg@oZ+o_2ehlP7|ct^|g&2?=pnirPu&!nT35a=$y1y-U0_z?5UEZd7;?+4q8yOce~+ zqfW}!mf#^SHG~XT-c957OCL~e1E{qdrQ;6NUYBV?BRpHMCm`2JN+eqB@_ez$*@R^w zY%;dbjQ&9za-jj7SuZve*l52HN$KgJ+BN8D6F3L#x9nk`lYi>e%yeYhZiS76LLB%a z?#SgXBPX?TRlnGGaHe910*lWc=ckb@`*JeHN&w+A#I-_NM{{IJbE)bD=WH?H_&G#E zZ>sMnc^?M+k|GxWfpf;I>KDKQZw+QVOvmuRF{gng-pz&g1qv5{ezbI?Ml=RZVMXRqf zZ1Aez;#nuuT>fw8;eyYLXOgU?VE#=0g3{*}dKxv|#NWSL;30``YMUaMdRo~xWpuye z!P|IPE&g)!g<_gtAQ8C5iX4K6n$h1gL0A-S87`@&dy~bMf)81U#)#J!meppm1%3MM zNK8o+sG-?3PdiPnNa+4Tu&^*@3@RoPWl=KQ?+M~IrznndgS8g&2uI`h34SA(?yl1iqBQV9Kw_}j_iPP-!aEUJe+iX&PdNTO%GC7P(>DH*hEQa9`d{4=%8qQ7$2O*ku?ZFtL9dUK=@ zyYYVAYW!ZK-4MBiriCT*_LCJlb2PFp-m&$0;HrGArkUxT%nx9kv5aUKq0F07jxFjT ze1_^h?DJF^ksVs;EiK_LR4d_6SdF1ayF@;$G2i23tN$!8!267fQ&PphNJ8kRq-5gF zBTm}>{^R_)*=RQLHKTVLR9;1{jutoMla(R!4N_o<}k}-2nd|3a#;0UP_IuhLt18wKbf#TY>*dc zqUaIlh||$T3o=IWsuc~~wHkS=T`XnsE|5=L>Lg6Nb~jeSzAYXZFM^EKEpFxo2|oh( zZBIK*)rk{Al!*1Nm@C1|<~`mS_f7;7xdM>rZS>zF(C)@^9P5s>w~Z#!^lvl>CyzD2 za{w{!`A_M_{g#OsU47;5y;}--xk=r6AkRt0D>dQ6dXrr)z=z^Xxf8QrIfRLkY{?cX z)EQcoKKDuEy@xSILb9i_IC)hz?017hmvpH~?ErntXkw4HTr|QLHo^x$Uw=5eH;tcf z0F0q}Kbg^2WTgC*S{OT1R6ZI_Nu$O^jmk}ZKfre|d>!x-M#b3IXMQ{Q znKU!i`;5jdI|X{`gCpvdlr&(@maSGc`Bua& zh^>2AiOpot{>x`K0#Gh2#}cXlT?z3}ue_EGZAuYujlOs-uGrQzg&LbmhmNZt6TI?IYKCm?dzyE z5;fUR`)EkCA3c|1lUsCPiI=upYs{pyxecJazGLGO!nRzhl9D7JIi3~&!Kis}WcGh& zVUMx+{w9!weEw&^^W#_J-j5HP&-U^kZMpE>ne0<& z0d#ax7tQp%tUGVfnfx$wNE)s9Foc?Ph%P!p2#k$xs?|@-n@JM2U+9JwmlIOEfU+Cy zeS(@=Y&;x@0iXE=XPxhH1M(NL(V(AAv;6^;A$H$)O~}mKg&)J+C(|wb9tG634a`9G z5O^KMCcFDLaE)*$I5j>FJ1EbV%g zleru}U%#4w?jKVn?pM?Hf6JFewU_D1#G{D8#j@;ARg6!nS3=3Rzy&ELLx~Yl#Clms zemP>{O@ma56{tLnJh~c)ZsusoYC-L)rvRM6jn==79L`bGKbL0v_T3I7Q!UVuZqC7p z--v8kMX*Z`mvvm~ivZ-DC!cZ4s1I4V+;V0G6;>fyS-9040{Z6tUUGGP_VjS`ydPlK zQ7VKigbNy4VJj5N}1sT=4x;3>7x3YAO~C;b{W4Pa*UX^Q#qR|^kp z#{xi&Xv8cPh&DCZ)3;DZ`(5}7GuExJi8EBu17T6}UXXIU;#hPhDh}zXuSYr?=72MM zvQENf^CJZz@%j-q%7Z{L%!*&2n_aQwo&_wdi2T~xbJKlh&e?5EYgGr#7p|0ntF&Bs>Ak3nr4h3kZMK4`1uC6mK-_^l#J7d^1^QKeY&3^QyfhU(zwx;R6jdy z4S}j>f4a8WrzMmB3$n_;uz+BX(93VZH~)Hr&qAJfNjF0pohF{9gQDlu5H0DU0#ZNP zgj-zEf{X14@{tokQ)`l;SfE{L#d>0V}9)9bX$y;SvrJ$cBmUn@O*tq(Z>1XmG?$F$ zbg%=%rECexcoWu=$V?$o6|(BZl+IMLb3lou(InEA=uABAR*(#}FggG|t$mjLb%!(D$L>A8+YjOG<2KzMFoqJZ$o(ILRcVGh_EVJ(ZM74Q4ay zRx_r^U%9(b_7aSBziH``(O(`}nvq56_1S#JLMzs$XLwb=A5WfN8fC~EaiZz32snRl z_C%FMv{Ko9oElQSnWyHB%=;0T9a(+?~j z`c^h0FXHy;e&3I*(L{mKqr+#GRXA4+02p<*c={ZvdAe_N1049h=o_vk_jr0aS&fWxbaTq6rqDWe)?+tGvha&z*XRFNQ-t~_08kK%k5nkctV~xemOk$%!?@!PFSOMADB~mJ$ zn5m2aWfr7l9Df@2zp)6HyMHZFu4X`@@6?0US7N&_G72o)vwYn+%v|2vp#@1t%*~1q z?eoH=QLn090LSN(WZr)CtLDU3ahF_jH?I4e(76fMFp4lpd zTHsI1*-DHUgp(igV#w8!BwN|JSOiRq&-_7r2CCVrX2|1In;z#8$)ayF&^_a&kpV1b z7^ob&VsTPjWu;>lf{`L}!Hn|?<72ucZcA;=uT{=pSN?qIiVR84-oQ6!qa?rVt_?wb4KpA}rF1HLuy^eq zeUB17QI5&hPML!~157u?g|(6(>NZ$CkoUVUyhh=QrzMp$f6Oz#q`5Fg+Pqxg*eKCF zf~S0p;fU=ECT0y&j35`)@u5WS9 z$B&Y^)YsUKGGW`uoe;liF~*bSCinEWLMILrjOd&kUJKspv#-WzdA8KwzsiEl4rf*n z=LIUgxOqCp3|9I7lFkYCY#2u@b?C4$)A;qv_30Okd5^7n6~J|{iE7dFMzpjWtLK{g z=d_}uGHTFlsQtc;5AyD;l2lO&H9NZe!&{-Qs1e}NO{%NL51?5|Q6?Y|S7#B0#UokE z)@Yk6;3C+Mlyo>l3X@2%DyI+RhyR9=df0+Ik}}O`#3!HB;^@7q-PK|2uVI!&-LEMy zB$_^CU^o?xlWK3uK{kxSOc8|7T6l*+9>bTuug=Z%4i~*mZT;Ns75j&Gg9MNvi=w$K zVSzfve|RL$%RM*ydriT=7Q81tTM(XA)}pA6R2`f5(}+zlcRJILh)-_mB{GAweD0>_ z<~pS0tshc?(ZQ?|s(~_RH0fx%={Zezrl7NdF0yLb9L#{pNVjpB95rGSeD?4#9DE!$pV>`)Pa3_{H7LC3rB2JW7 z91_rt>=(=U=2%1RQgf{2M}=4-uxSl=SFXm|d2;*-I^_%M`gWrS4$ zBp0=9#YJfR9(G;swgu_;)rPwItKx*k$olUw8 zLLU5leK-FR$BlvxM0@R4Z2ogFqQk8(zZ!HfZX_>1zr@LyP4sRxwZM39Ug!cscJ!>h zYtD9==^>u7R#@1J0BlNgH92}+e^s{6vEF@!#ifJ(^65Ap$*QIQ;{qgt(tt&HMb#}1 zWTe%gGP73(j)qk*sZ(F$=~c0rS>*?bUeAst)#csJP4oJt{D=0>D)Gn;40?*C$R<^t zG4I5VM(rRH?w7+6d)gCOs(z>?yH)Ddl%lQnVDq!{8AT-^gBH;tdMM)~8n7vp$kdXE z^Rrz$+9{UQVaFIxE(hKXbH9M);1z|Pr=yO?s;6)d< zTYN+jhUo|6_xX1BCg&woekp)=asj1_f(%(ol|hmlnl`pYI~YERDSNM9`w}1*KY`RY z?WX6J3POPGH@O=XpLyq9-}Ib_qt53+%com=>mBf6a~`0BUs9MB!Ox!b2hA@G3lw(P zcOQO^hEg(I20uT29&nHUgk6b|T>oX_Y4~@8)dR_q=z^~gLkGJK6l=XE}TLU z-ln32gaMYJ4SS|KQHs`HvgUo=<{Pd3x6w&-MW4`JCbe29yA4f-4`7n%mTgjsPzNFO zYjZBbndxSJ^8TbVyM}g?;Bq3v`G!s$pJ^g`2ojd|`1l0^|#ih`rltZg^%?`PL*AK|Omh!NelNh1ux2nCZVe+3ZL ze^G5zu~bs4#CGMIKz=j3st>T021<%?_HhURAx<714O_H+N`704_j3_vtp7+H_&zCA zygeMV6OZje!?0xeQFM>xfJD6Zr3Zi&?!BaD3g|mK?IMY2H2fysEOIQy3 z)b;9A)F0uWop%Wrk2`zcruf0#lx=0ldxo+Tue-;EUf%c@bE?$ui@hjdA^M!QWXekP z{Svw-<#^-(>CYDEZ%8TcN%fS6x|kid6Ow$B)U3mL%zhkxDspF16VPIS!(B<2E3IslMH!1?2DCL$N-dNexE+SG z6=dTxb7GLz9OG9A(aYs8RjEqfD|g7V6Che0QDx?<9?3BnN7uqYDUzB@e73mq6hI*^ z;9i%<7#Y6o-g09H%l;iSf1!(r*QEEn5|4Sz$=UOHf-gKCnDP|#2dvBT9zb(+vfCH; z&$JlJ%B~Fbc^cU1?T#z4&HrSyFRkskf1AD?>f1ubZ&PE?==$W6VNiD(%?TOIgdSe_QMKLZ6 zVCj*incI5Z7W#<#;)43(J2q0{#<0cp@bFiBna}>teDvl0(I)T%dbrt`9*yb0Swp4B z?AJ=0JpYTET&N*T^Yn3&N`In!^YIP+jaYh2%4fDN&=49tqT=_1RDZ=Q)V^7x`vaje zG2Kj=%kIt99{6^O3aGyiYz6_ve|rZG^+FWoXC>Bz~viq;AJsw#!>SAU$M-lt@nr);zK zTbZhmYbCV^CExq$8a0o_uK4HXLFzu_Wiojf;nQf6I*m3IF))g>#ad7|60Ys1`_K8< zN@djqTR@uUZ*A|kQ!;e)K8!p@D|DII2XKg5pK=y&wkAJ=v+Y*S5JoSTe=S@YnQmc) zcW4HV?<2!1nKIPg)Q|Qvf|M(q%t*+;X3vfd@T!o*tXBrs95>Q1ErGF$fCeX2y*?*1j(vVSq;qH)MULh@`YOhcOF}4kR`?rZSY&xl&_9 zju1JhX^~~JbznS$tjw<86&1~_Dn7>4(4*QLxKPQ65CIrCU<7WdbY1h=Y=LgX02JW} zLJ{1;d2IAB4s*U{kE#fxwb3`rbE}Gg*X*bpEZZ!@$q(hqguee=!v(b^9@m{%3cm=YWkL6`h3I~bN^31`}b&* zHTIf%!w>h{u!ryFEde*ZH&x{g0#>IJSBysXlBQfvP#y@dq9mnf;n3BuabT8*HCO6# zIAUXj+l)6J9x8e{1wF0R1;#J@vZlxAO3}fB6e6F}ss8G>n2A9K{6k@WyFANV-Nwk- zf5Z`O5HBkougy(RS2k8ih0LUHl1fRNwo|$?L~!>3DJA0DZ5CcjFaRT3UxlT8zZGDW zUhDiDCEXpn+6gI+p2NoNx4Q!{2ukx`i`k#p{ z*kWU*D@U~PSOi=2G<8Zr??YAG7=1B(i5ndbZ7JF2kV$=NjsE?8qPuiFV*{6W;+IFt z4~N9O2Co$>zHxs1}_8_gIJ|uyeG#V6KWmGtpFfv$+44;Xe=x(Nt+J|+FjR#d}=%F>6 zHS&7|J}Ff2bRLst?%*d>4T;?F!Eu9;Nv*ga`=2jfuD5~;O{^<4Ly^mOJ~1)Qp5M7J zz^ti)S7xF$mWxGBU7sf}aCZJPbnvrO$a^{aNtkIbSvr%9`fNq%09E{*4Sf5FVhxt+ zht<37z_78jqqA7uarZ3s_+69_gx`)P-@9W#bwSCA~BMB|7++(nlI(1*xb@SYvlCA)-TCcV=X{l4x zkdLTZ>a35(wi9Q{h5?(Fg6lE-3cKPq&g3o8=tI$*F$EbH zBPg)pGGo}y<+2-leRhqPB=T%2439tDGTcE2gvb!J%AmvswbI(JypQOra(U~t78Xru zF3;qE-7bl)cD!DJyVOfO^$?7n=ewdPV-72s=Ml-|#Ug)h3kz_CtoNV|pTBdwc0l*SpwBHtMBd+-~ zThyG|u@*IvP@6Zv2oqj=IvYx(Q4UN&1>=Td58!ZPcyb16c@%2}`eD8_F6y)HG(v*J zc>x5wGxidplo6Sna2iv!TJ(F)bDTC=C{VjR0;~x#s2mIhS2U8p%N%Dhy}GhB`}-?O zkSQ7=Ym83*g4WUZUOpQuJY@ihrw`ZnW$C5mGmutCT8F*Esp+JF573>%l>2n+~Q+yU1ih_Cp_RpA_XgTvWB;>C{Y&9Tc-48+# z&gfxh)RHHM=BKu1$6VV<6f066+0)mmyy8FFYDJsdWmnOEEyPJMqz^Hn|0A1XNUh2u z_P1Rcm+FIK^_3)y7y9E_bKEYqUbH z_7c;;{B=Y_u^+5KTQKf-ebN@*nCVOc_Rh}UE0;dVLZlA$s5^`_5%&BW>o7EuAU1Oa zJOJi1zv!4vrirwE&bJKG#Z-Df(aiWPWMeHO(x6c8u9<$dll%Z5Gex9o1OK`>;gvGZ z57HJh8GS&^b7iQ-tr}ef%vTb_?5h2V>0|mETe(U+3XPsUUVhZgr=}5$#OKq8S|~A! zf^fOq5yJHDbV?a`z3IBs)KZShHPpce-$Yg;&f5Ep5p-e#aIU-Nnq^N7;ZnzEoy+S}@wV*|rsHZfC)+^7Okd z_Vu#5tyui_ZFM4As(ffCl{bBHJHpv=PBn#|ufBUB$S}J{%qaNyG~zvBviOcmJP!lL zLNCZX;X)=Hmad{dk7@=j6;B%f?S%xyY_1jC`ow}9S@RVWr+^_eR4QB60bGpCLHKE4Rbbg9l^CS@ zS67I12oQrw#LLxxxF?uHjCVYv7(NEnDe;EKz>Aji4pM$~q{5NpfdF?(4e;;gb2Q35 z7E^b8g7;MMO!})rJ%~70WOZxG#)Is)+Fg)^yg z(*w(k+jk_QAykQkjoUuq1*Py*f{F&eSWp^k( z3$$qGJ#gcUX``SZm*Znz@68C~!3x@yx%zN7uA7BRzEil^YuL(o;cf#OXbxo$=AOLL za3b!8e0#9tR=jf0H>w5$a}ZUf1yNNxd-3IBI&ym-h+wJN&;ezwm?r2*qvG{GdH~6z z5n6xuo|GS6Xt)<@J+{kbS}1)1u)iV!IY3)XV?b4Nj>HZZhJ!7I5($uV0o)=h%{tCQ z62HVoHhZ`stwCl*tVpa($X28&Z*j|04>Z{Lx-eE|?Gubk7^4@@Lu&+&YkxP1p0_j+7tFA4EEGc19}nsE@tcLbz+1D?@R^rQ z1=GjeX7|*d`S{P*pGhei_qI2?GeURrbYbkG-!vL*&=T%g_|ApM97Z?*>OFU!oR2Uc z)P0Crs$m3`G9D1IFU%7sjMOi#(yBD3L5a``JyJ&mJ(_Z+ojV^HTm_zr9iB{(RDW87 z)GIo7Pq-Sn5-D3lobR(zX+&y!yZwI6P{$)a-g8n29o;?lau{^L)+ zeCXNpGwKdv3{Crd9ilW+gJmhrE9%;x)t7BWX|5Xd4i>(?*U}%Sk1m^7`(^79{s{#P z19jy^=2!zMe1krLU>sZ$LD3ax6R}KCA{k}b5p*}j>d6E!O;c?o@M6pIFks0Uzy)FNq4SqOfUFGRm$mwGy4SD&XeSMl6<*D-Z|Gub*ptc73 zND^Z$Iz3$1h7!0l%#vGWGerIUc)=LM1RJ|0R9BIWFDM5IB8w>;kG^(zgIv_(HSmvs z%JUPP4imXiI_8uGi7`UgOl~PL#RYcsd$CBrh1n3e=Y&e3CoHGCXuLA4){(WVjVX(p zlPR&A{#`ajd!kGVo4$v1o^c6DyBu*Mi~ee>-#x2RB7f5Glu+OVQob6TL|6PM`F^h~ z&!se%Bn&I_9JLJl%Qn7Z7v7LtitE#MV+}BG0%L?-x=&%C3-lsz~exJC!F} z>sA@#3iio0McIAmOeOY=Kxj0hOSokTcaHy(sWqF$uSW$P?y^|h2Zk1VaR!JE{gw|y zjn<=vTSlx2a&hcBjVKqU>I6|&yK-U;GR_lizEzMWXjj1?Q=+mW<-)W8kD1AYs_UtM z=nUe~xZJZ2DVe*riicvXPBe*pw}dzEMw5c`@7bIsO$#>j0)KqOC>KNZm1^eoPjvR% z^-U((Vwfm-k7MMe!br3Hj<(#5A6vFm5GKCHmn8j%1K02$P>q@A3Ct5Hb12dV-h#{Nqi}uOB#t#Z% zY=a4=Zt4N;Nq#sr2@Zo!WqaBZC(NLF%WOfT^>99BnCf5H#(c@L7}#uK-CZBACFOv~ zBW{D=$jLzQXcZZZlJpXMu~;iK6EvplEYjiIVcOhf{Bf#pNpo%Xr`mwN!%e>eJmw{9 zA^SxaAu@pwF*1g?%NAfCAa1U3*T)NUJQlRvCfc+zri7Rx$Du%{b@k!vO=TT7%rtLh zy;u~y^4Qrv#SV1%xm8^SDt}BrxUD4SP9blWN45dk0^>@L5K7KIh@>{^Pw?G0-8V`- zh}0Tu6xD)(MoD6M4^4zf=d{ClR1mNXql@d<8qPxR$^LoAZOzg*k91I}rs}pk|8oC> zn%Z9``?c#C?{uw3&k+Kc%!eME3R6_Ch6077kuEP?6&23CEWK)JnG;H1{%tNKAKC$- zs>;36X>^w(5b8Ou=}BM|^|C><^3y8>Wr?W1oRL$?WPUmx=*bwpgSQ&C{Ro>UH?o ziHHou1Jt1r%h8pYe%pcVamF)&RnirCeWb_9uy$F9b0WYa5R^nL)LJ6Te$fU4G93=a zWNtG|<00aYSp0o)$jx9%e!?XxJd%d^T07Z0l(BJX52Z9mD`~KMSBi0{I&}n0Ks6-_ zVAeG^gk%UsC|iJsb|gM^iC<9HD2e!=p3?EjBbQUD`~TKW5PLI-+P21PZTgVnh0PO|s++S2zboCHbz9AIGbBrD&$SZg++UT~V zUc5|zfGnH(96S0jF@3j}BFF#;T?SYR3U++BX_bMlm-wY)EHTh1Ff<1rhi0GW4w8&g z0x$oJkUkw;N>BXWcs=gBp7#HoMgt;G@u0)63QQW!FR5J-@^4MojliqJ0edGuKSPAu zQ%Tj>cQVJ2)vBpje6zOiRLszuf6=;5JYJ<)zv zpbLmaE5c7~!@i929qY9(CDGRkvVH3FqFHSwdO#vWZnQLKKqhg2K!{&PSnG&+Dc`cv zQICm?hjH(}$xVq@TsC)>wdwmyET&!sQ2Xh=vJXDh{bdnlP21a1LSR9WOtG#6+dM(% z35+;2Tz)=Ir}6rL{_KGFmq*U^l8FR4IbpXv>MzBYdB3O<;a;&;gzdZ#I|Z)3Yl zVI*?-cy}2^kRR}{P+4)~k?u|C8Ug*=n1K20^zhSt-|>UwM$4Zmv9q;0g{J+-yKeEd zlPPX$-ODMDYPG$MEIRK0Hx!f#0-ZkA0nHC$KXcL!jWdjzZY683v2{Z?J8wTNAv_jx z`|?2Y?u}@-$f3mivCN;qUm_$F(8BQVu(bUBe&*NrSmv|V0eBbD4V)!9GXC7I;}qB3 zu56e8$P=tK*sm8R9lmJwYqY{ud1v#1&y8L=bBK&^ zUJc6i!9{y@F3$X_#=v*)lo#^j7yuWx5EWyDdNeK}8;`D124r zZixc=J{8aTGcPiAv4vq|YxkFg5=zUDuoEP--Qv5c1Xpnzo_6`}iYEGPZgfBLotqLJ zkx1pW4y8>72t5q-1U(4LguLuTWxZIe4eNz`JddBeS#Nb2KYA!=|1~UfS|gsN-gCq& zf|}HIyDJj6@vvgsE1~jcXLNT#pfC=T=<3BfxFqFj6FETg{xBx#)YRwVa$2g_@2_Ua z{nMVU@#i2xLBSTgsq46nfV1w-v*3$--{8M-bUhbiB}p5e)77m#Zs(D7k6RT|65o5H zV#6^Xd#>ixl#q%s=}=<}J{};MU7a@iuDK68BM~!J-~0IuHzIsrwsLla`(Uk&_V+gcwck%18aVe>56hGPl&TS}#_uluY({?e&iLA%+{mF5E43~EIWe>L|{YRtZqN?w$ zlaFz+ZzFDNY5sh6s`>hds>Y=4_PCK^^R|z%RorcyvGuV;Cv&51pIqo86NYcA_{9$6 z)=Cmx@53nT=Z8VgS}a8dZ4luM|7#P`3*zJZ#emcHU$eI{_$y7qJ0!&!a%gSWi%O<< zgPxj_A8*!^q=J9XF@7Rd>e)}htogk3!(;uI+INMt)~r`AkDAxqj5^H&jjn-PbosZN zftW7trb&U!HI_#nrh$*A!xi08y(`wi^wZKJh?LT5vGVYc*<*-!Gdx`ax9-t_WHLC<(~yY=#n zhn5-2x5S&>YxmdUd1Dy&1v%tm-usbGY3$`;vo;X@BVvzF8|iD-i@-g~5&mRb(6sb_ z{`*Ia3%vjH!~c07|Ns9SUPcicSK~u2$vUPnY1@LoKaL%(rsUo~pF*Lhr!BHUjzLAm zJ-t0W!FFGo+sn(#+l!0KJ-;-EboKUrZsow?X6zZVtFfoFx34*KrFL+BMRnxlQdwQ| z$#d72&TRN)%gFWP)(|=_BE7WI-R<*+Jl-NynRk1h(@#55wc`HA)lxx+WsHQ9|1QR- zX%GcY?9Fsf!TPd46c1h~!ytZ6=p-|bBs_1AV?e32S-KgnqK{1yC`#e7=@>}2fPjF+fYIF{ zAl)h5tu#n?iGYZJAd33i`*Z!if9^Ve?40Yo&YjQuao=T*jU}8dH}rqQxa-@kSM>DT zcdkX#VGcWTm#Zn!g|AEF`$g^-{?}$=y8kXCA9PgkYCGVfley1(R!*?zawvvkW0vW0 zPp}M8+Rn!VYr1jcR=$mh?j**;3eljOQ=-0ol9|VCZ~ooa7?Z~)2Ki4ZGLy3Bc^ThV7AME4b= zDzZFcmt0tDQM;Az_}4Vfw9$5!1H>cg<#jffa_=U_G9g9PZcN}q*O~)=oEp_U=eKGL z(ufyJ+!pJ7<6u5~_FvMl_*#cf*0itm)#R0!)|i&fgV250iQkjIX_u_5aP- zF8BMq`&-|~53-~F(qkSW*S8r5n;W0E|6b#Yh0zrMc@*Ub6yH)EacPvv@FecPUXJv@M|#MF1Uov?AS38GyC(5582 zcD@|WcTHOtKYU!rMkKlpAP zo)zALH-l$C-qqQEax4GNe@1%g<;?tZ&v*eXQc6U&(xckPyePAOu>rhj8Oeo-u93rZJEb+~cfNx@E7nu86Ed1PKQy7M+ z(we>9>L_i`qM9JROI+-&uty4|^Q_?8?~?w$-zscw_`9L1gS^iO zXu`8#8OgP1CU;17#z5&$(ScI`T|w#9f6u?&3G^Qf3jbL?{D_f5P1AN9jk4X<|9YgQ z+j##Lifs_~B+Engg3?$=uH&?&v*%!eO_VyiR>#;Z!M7|dsBp!lq;T4iIsO4cq(Qpei;;2!en=hks8aHNnvQ=H_ z+fSP<5&KQ$Bs9ClGp~<2?zY|N+p#%Rdy0tw|XKZ(ER5q-_7bKOLZrv2E+$0P-@b|6*d~5H&@AW^JjK2(f>MG@X zx>;<|efv$``?i>Z>AX-aiSe}x7nb1Tfa_@q`FoMM%P$pg{$5vLl!c$|bf$GAwr+Z> zPn$lBT3Pfs{_P2{wY^@a@2;+?i9U;pK0EDjsy;hCt-hdhab=*VcR6=vIIFHd_~UGO zi8`nM>9kg8{fnIbZR5bT3Ne=XPHpt>y&~Z1!0`Bi`i9jwy5m+Bd?+gct|fOIHyM6W4+YIa5 zxc)zse3&;k8w*^YPi6Ys6mT^?c^7k-=UONxB~{acEUkX;*U{uX|DbXmmaU2hF<4n* zA5yoh?xyoEZmJG|qLhFn#*%1nS|!@ijSU(b3WdFvn+~|1%hO9RE3I_lN*gkiV#IWJDDj%^^}w zEaEZ$AeBE3g)ACUx#D&|BC!}AGiu|XF8EO}t*9;bNY-I6U*)Ti#q z=C2WHZ<9!F>dd7j*SFx?^Vnm_;-aD^m5!VmO(phroV?Eiv7TaCBJxZz|AS(P>c3JX zj1yCc*LqnS>_>C@1wTKM{Z!m<4K$RDw0rFP4}yOH#cWdlT-n#w(gHZo7CrE4&M|k! zFv%BSsRPQKXVGH~Y-*`;KFg#jq$Z0)XKY5s68qt@w(}(_83~13>LOT&_X+W>I7!&_ zW?15PMBl=!vEkRe4tN^#&>>@QFe#pFSAW!)pD4WmVOPsUjhXqHz)=-bJu73{OQ=); zPf5(P9hu&M8MFV%F8z0t8klt;*O%A9z=MNem!t-iUUDj$N@QF7vGO|0$G(=5vTA30 zs-?*O+lOgpdyYrw6!|HuR!ri_67^!8lCp@L!?(6sSOJWmvB0qL>$jOk{u9WeAj;Rr z=Z=PxS2^?8WO{laCz1h?luMRPE=~$Gs3|Xj3F-KeBwz;l?%I8+rHOR&GLNZelyCP2 zcj;`2gDR^dd$F|HLRn8nm?Xbv+LN%p#YXb*(oE-wykR;vDpOWfCrIAgOnU%iUoz!h zvWnw$h6+x^2UWOa=aLt=9sFT?Bi*V;*K#@|{Ad4v4!aj)w@$TFUq5%-mI`fJfX}V0 zC=t*shp3tTOLm$O%5HGtOlZ`1`A>rK&@FFX;T%TU;>d&*F~4UTN#GdX2w$DLHuu$VHs%5`1fh$lOXYLTO!o>P6Lpf)w- zOQ9WUA{eu=VI^(7QIbLlu9aw@|IF>G9v~hf0-&79Uqe#i@41w|4-_v&y|f&;y@WpP zYHDJscj)M{sh!u_2W;Y>8@|tBi;68W-?+pNo#a^R>vZXbv`8yW-SjyI)L^_RruX?x zOr_}6VpY59_=c{wbQj(T^tn7G2*n*L$TzbKbfoR_kC19?1R|-sEoq)7PTQA7DS;em z>CK=cB{fgbPC5{_4&$OhZ!oTP`5T53yI|;L#2?$AIAfkdSb#LXDfVIjCu>?&=%{D- z023C+2$oJL1Y+=f#RvsOL8&Yi2)uIhajU$C~BJ^ZN4^UC+>D~!;TN4id;C)k*V{Pg48 zPt1_#-3daXG{XDk->(i_A&y?`a$`o5`-g%dzk5daO7w!fM#X)^46Ds1kZ3uD9>f_g zt?6%m!LpR4byNBF7K;2Z;e>X81pgJ~D>-508n zG}+n^_pY-3%$c;`JL_471NcR!Lgl?FS{i@2PoY;JG4nn3Rn`!2iz z-#DcoX9$(L8M-NBE~ZGEcaiw3`swWsUfdUpwijI@1??Y2bTct&>I!E6n2UJ+&h{3+ z%D~E^+}!d`)N5L{a@sOwdZi}2V{Omf*DUwp{9qPNd~71Glzpzi31g+eg-_-1Em*)f}7EtLuJb zv;X-a6g^amaSj5OX3RT0T zC-mUbPR@$}BNnNuE@M?b>k~W_!Hy)hS5IPU_=NfMk4<4vM$JK_X9L(2{%xO_gs&Oa8Ttv}G2Y+OW&pT34Sj&> zT=w^{`P`=wqvn|2+fBbqz{mf3Z(V+oYEIL`4v$M3U+h@#II4w1r*i*3s|3Id2E%<3 z;8+L+8JthcwOE(OI1vGsxaQdywoEm`f+w;{#c@w*hgjDWT8?ZRr+7s;ZC>{+N`Wq<^Jt(f#6h zDs>uhS+lvseMyBp@NIA3lQr+jVVOI~e7E>i1DnyBF z4LRi8guKGjZaY&Ox{7!&X$Rj2lOE4n#bcLwY`i=__sDzrO52t_g)IN4^U*Bx3)t{m zUL#|O%DZfNzTdSMkiv1?i;-!9ue(HqWSX*%NWVQ)HZ*uZ8pyXxFMcUj z?7ceJvj%z0*%InP210$!G5kL}zixf)Y)Xw}g_L>Qt?kwA#Qt2LxAjq7IB*0WGoH)< zeqf#t$_(F3+Y&&BYC|cM?x^|T+g1_cSmoQG1?wp`0<& z+&9qps;aQXO;jkQET?#WI5dZ_5zQanz_<$$WqGmCgiGXZE`$qLaNK;>7BfeW2J`q_ z+kNx^BAeBmx^`N6EY@ZaWJsa($ENFQW4d?#cUaz2x;126sHRjYRD%@j??J%6rZusR z5z1}exavttsouX$JPdz$Ok4OvX_Ep|L~6JZn?F~qC{0N*0gHe9dvR^fDE;Q-Fok!& zA`l1oA_OtzU0s@*ia)_WOL9i#=Voxip&SvKTyQmmU4?XwAoU2s!vzTrW@ke-LiYK; z8h!<0^r28+O9;rH07Yg2lacLyj89AxojLt}Rg<5s5z4#sB1wO(K0j!0F+c2))f3aH z`GW4OTjKb{TQC?xPQjfVI^dtz8;63fMsK@-ImpI*4)F)+hfgj^d#Wp;6oDS(fi+6; zd*2>AX$B^sXj#g)cRSzDGg%xm9^f3%YK_-NWML^s{d$D9;ZPd`K!D~GTDgyaNE{A? z8j)5p?xppoYZRm#2VP=e4VDB3(w>}&tAF73dComdpeocZF80y82M?O{+J5 zenwlHw`ysO#8o6EA=Uzn=+fdwx`gt`{X`W6o z#<%QJCpDQ;iJCUtf@Y?E6yzToeJHkC6_65&!^$G>(zf8okB|n8G|spXqA=OW-49~O zXNhgA%5i79h9q!_wRG|CP-aIi{zJN|+RD01ll?0m&ZZR~WiM45>%pW@au147FB)ud z*QbVHuF`h;AOe&Pv$1kAZ)zRmy1ZAl>KM!-I)lB^Tt7C(>mWhGa>z4vEQm3yXMvc5 zu_Ipo1+_t69H-TNR!-QfLIUat>Xzux?!@^*aoa;(t;WvquD1UZ#HWDVJ@}%?ym4Y0K z9Z19VNs$dUtU)BiwPFL^s`O1C`+m{y_$`xR ztJ9&C-^Z9o_e*owq;W>ITaiO!bU2YPevjm`qgRfpU{uGt0Oqj;;>d(Uv;F?`Ti6R# zV2{AIATQ%`C?W4?I$P?Z`M81)j=8{tY3LiGpur7P0*<6Lc?w@$6p$|lPN$>@hS^=4 z971CsS3a0-SN9twV=Hj|D$U6$>&T_}rV>cels)enbK=mTjxXP%wv|DEqJ7(HZGR;)d}5B~ zRBL(JU0XyvX{H%E#{05_7%8V!rWEL^6s~9J>3ZhS@z9a%0i)dmwo)kL#nj2{IO z-`}>0oW3PHR>u~bx8qF!92WJ$Wf|h`V!ndrZiFlci>Sf;XX2dy`qcm2G$iYZs%>Fw-!t5rVuVZ>L)oXv+ z!CYf&;6?lvixrkx;&noEfNsVv969wvLI8oo5-U z2GU!z-#z`RK&x<^{Yg8X{tMy|hz(S4%KT1@wh{XX1`mtDaNWbG7Zc}g{=WMnhwia3 zeM(GhM{Orco)+Z~BuPeQ#<5#O^?T4{gmXpH~`s~OB3RiZQL zU}KdhMl~OQZKMf4o*kf>K}_mO|60jtVHztvHw{<>eEWH|90sv4XuU%K;-rDn+a?%k3;mO-xt()L@#DFx_s~bZ&nrV4 z%@BfE23$U`qq{W6oLEEL>D^UpVxykHjD|`1fs`Vh1?Uo~eBpyqNruBPI@{Wj3KBtD zFl;Rn!@{XTpsWi`0*#=af>}UlxYNRZu+Fotv}mbV1^A$CYf|{ACs7i%Crq43z=kVF zan8tMLwGF+Zq#em*HzmucfWrP4%!3vytICYdUHQN{OFU!DUpEHpYCL0t=%7Nle_{ZSP%o}Y(eSktJ|ZW1 zO<1GF{M;A#`GZayv~#r)+ERyrViu@q$B)?h`*Eure0dK-R$nGqZN4>`q6z7|0tJBj zt}x%t2_I1fW21T_7pRRBbqLPGd4qXCKVF68dIK zJGR#r78f6#V5s>Mi|7sN$f?QFgz!BHDfx=f!8(KnMN4WsD(&;x-Y%Drr?2Rb(Ec;& zVYAK90RMKyz*|NtS{=#LSS5R$Nhku0rKIRE$o?eOM>WW!t3ZceCImGBFZjmE^`&aL z$%i`zuF^W_+@*|F$hfVJ-lY^CIsBC7U~MX*i^?`5ADsI?Er3xYbm-@gFKFB$1>BF` zmCWNwB^tpZVf^*qN02vFm8q*(bRet|u3JKQU~`@}0Jr`6>y(}AVd5w5B>#uVzh-pmXG zgwHHPU+)7HdBbCbYAdO5;>|+JZ?@TctzlGa;5&`Hre7A-%|>Y~_NF`aJ$i*<4YIF( z_u63e%t6BOEOjhHwv(^j2R)s|wzKRtlj+G+{E}l)S~f#Cn%;udPBN&msMlD;zMQb(Q;sBb}0QxCtf+l~5!~#+#BRcS*Sa>F@ya>nCQ7D zWnyfy_(W78gN5dU4IVO_HdFx{UcZkcsFzOo8#e%Vn@ynv+VO0Lcpo_57aGUXPfmxE zlbjJOO!P2ls>Q&$MExH4iCsTPI3&;OW#{vO$Se*x&X*XJqXf@_D?2H&KV{rR59?h| z>;#qC>F9joMw}f7k=`g*U`BX4@TM4W$D7@p3P`_w*Zp|#H{;9c|Eu+Q7Q z2LEw^azuG^$^*_mg7%d>$1d8=$1`@0+*BpO7Ts|;h|HTa}Klu5W+r!qm?`f z-KG|6yEkTKvT+OJ4aLzNu3y#C6RWChCnL1vn5OStR-T9Jnn?->$GKu=d;^1IzX}H zE(X5sB3Le0ZAc(*$yb2DvreE1`3UM!b|GwJba!~UhJ66?vL<)Pp)ql&J&jHx+~Hhv zDtqIphdP5iw$Qp*-%RH4htYCH=f23Qk-QJ8)2bH$Wt?Bl+~2~P_TwvT-eM%(>(tg~ zCjAY4+e;r#OtEfq?8NFi(y*k-9Jq7E}Zh}Z>6;)j#7p~=|@{aImWgUB+4Kl^VH^!rL7liefNudGmGTu4H__^cGZ6Yl zjOyjP@Pr&S(^ucQk7(0sx6*@&T+X>p{pq%B8N3)Wc_^X&7$PKulmeeET0@c?@h*lE z@sisn{-=_qpWZy@P5t%Z*=wa?Q;R;Uf}kVJ2^Rr!P`AALt(7I0zp_ovjr=A zYfZ$A!q<(L*2S%X4ON8zen(+;n9GRz^IA5gqw-`Yp(1tU2(Eh#cBbsxeUhBfq(@(t zC5XdV2A3eio)ohRi;>B*1LwdQhe`@xownZw8^&|IT+3P<<%{zXYoh^I$uB1uAb+984h7cP z5K2d615&*-gQ-~!y?sHG((LpscdVJ74D&T5A@0H`e}X0zx_5c%uTsDqp(wX9E?nT5 zP`WJDtxtr*v%N6M_-=khu%!z!Xf0mLmekllG_rPSr@lax>ecgfU+gUWvr$!mO<&Er z%)hf|TMOfEs*iYl_2MR@^g9KMg8o>E0-q~_aR!dql)_-iWt2^Kkf>N|KGl2{5RLI) zZl33LpFr5?S^;yOL;Xzwh4^}#+_iT`d zxE#tOC-lt}UCPve>?+9u#0)QjtT(>d#!Q?a%Q75x!Zm_&jsJn67mMWOzPlg}cy`E% zReXWMx5~#D&B$UDgY6wki<@o^*l z8k~M;xsQbKa()RbPbVZ3S~QJk+3GUbO|h<=Y`(2CQKQFZ8Ot&<#RixF@mWWHCPgx+ zlCLU+@tW^6Lzj7(R$CPRI*BbFL zIO@IY*PGBEbZ#-1EHF;zyLy4of=~NyWr0?*7*EOCwF1fh`}YJWrR)%>Q~dsnol+QQ zSsq9Ey6SN(Jh@L>m;phv{kCLbo_OlDwH|eWc;3Fu|`!lu>vW-l;&y&I}mXL*ujlV zz?k{d&aMQb7`;$m@L=)?)=7$Ngt<$Z#Y#1E29RY>wSfCOx(62@JOQ&r8x2}lSEHao zhfGDCyY4(#EKk(YHWJG@dqymrQ*dEHIjljE@XQqW%LCua_`lq|PqVdD0?DHw^`}}q z7|b#ECdtU&B!gr8DA?2*U+gQ1o{I`g znj~zmaU8=ldY%OpA*Iqi&Wv-EW+_$UmumBwJQ2eIds*{IRo zv(yexb%+WVQP=*p_U zT9&9eOX>XV6493G7tNiR+0Pg2A_Wpt|7(nx#NGD{M=i?*M@0CD6-O>$@!R;0G=`d# z31!SV+Oa4d82T5TwdKf9r$tU`Ja;!tTM!}kpe=R}Unc}nKj3I$H)^MHD8In7vuqUGx%O+~ z>j%jH4dWN#!|hDpmY%7#AG2PZ?Zsa1|c$(?nPFT!Np*K)YXI1{%WAD0OON9N8_k{N(bDDDLQ zH$V7kUw>v3A3oj#ost)p(K(M}IfNk07gWmj>7$S0=aHZj3S9r`BUpZkR5pOVS}?+0 z_qvZ{0M?0#9fb671kH7f^?tTRLS1G*@XTCi3-4_0z&^n#^B^3RI ziSaA8MJAJ#l%!ANf25^ zTb#U%j`JRyU)Qeoam5h%@iVB6qBc_Im>;A*_aY|qNtjRxNs8a97@wQxyAK@hilw{7 zhscEpjVGv{pMDvARb1l58?h4PLZ-K>8-o5cH{+z(?$$cWdt~gk{Za|~CeY#QJ zU<-MhNAGcU8*!1Yv{Xcz|Us7?d^Y-!Gl@A+=uxAiqp+HX<3^WSj zt!mlsQC_0PPg*CG99mwW&i{k}8&fr?jmVFv&>avfp^H&W_}Eh6$@s!0l%ivU0?O_F zIKH`N^6hIuye6zIKNVrGc$)YyE{M;#NX#+kt|IC>T!T828Qav2=lYIo@f>e;5 z&Yuva46)|gRa<>bfHeNB(pMzkjU|sA)ffg<@+9n?fW_|<(ub4Hk^4vQNiO?o2p&8k zH`lkZRNx#!mSlrHsXYL~tm&Uv?f0!dr^~uab}2f#mx;8WNUd)zSHIFa9wnX;^o#e1 zAie!A~CMyrQ@mcIDalm_EY&Uj+Di2vbTAJK!VE`lbJc$CRfu`h+a@zCU3 z4E#ip5L?xOjB7aYcS;Nkr8gAs<{jXVB&@uy&a#DI<<(LpTwYo@9fy9J{m4P5Y2a-R zCtSHuf_XqYT=aXYE2x!Cc6PPfU1tE>+|FKJY-Lp_HtErMNwboSub9$T{&3AEkwXrZ z9Im@Yw6~!mIGOs_%%svF@?r`ivgKjAU9at69Xsl3wJfm;9PlanwZFr`2QniFro?M| zG4#WLckqfPs9ut75FUuz_73nH@5{ZIR83P#)p_XFNaToR)SqsW1UD#v{*tT-VAi_4e_2>q z{Ho{?lgMle=|1E2&1R15nBpF2%#ksMTjjCA4Zq50wF+t!vgWeRc^O0f(ml^~s`u>U z&FeHljP^|Qe>X3`CL%dOS9*liU&`6drRRVhK4QF%6Gd1`RdTWmGnL`)YDcQ`x6#Xz zt6UO3Zza|t&%JcfQR9difRlPr_Pq% zUX}l-$C|I|S2(;V9{9~SwwukfoSe=!g#71_Z+?)BW&noEa(u_<@$CJ7VSPRWG2J^( zy7GA9Cl57(7R7v2SNQBWpGC^72t%=SveLu!Uda636FSBskbd9=`$AN;5cy7PgDU5b zbkv-THCpz3V(YBIWhF(FyUGBSS z6l*6l%*An$|9r_#G#m07yO$eHAeh5X8Y&VcN`#j!_Ipg-5MVa~JugvVnQ-LbzPtMN zONvuOZ^FhOTKAmhp^$ZC^ZEN7ObhD&mkOrzq+_Py7$U@M)=8VVI|3E*W`@kO*amsJ z8je`9CF)A8HV)7g#{_#0iob|o6KYp~do+xeL)h5~*Z;CF1i%|fN3x3e6txdoMrxec z*e;F#oRhW?L4W{!t9cLrkFT1>M)1~FGhhdSt~g}6XK${PnoDNT!>7>7dm`U8DA~2~ zJyPL4TI={_-=;LpjPi((ZxHb%F`6X>D?VmCOn_`ds}el_${Osf&A2ka;&R*5tDxj` z(C0Mmz0Ea?SeqH3;w!f`O!`4Nva2-IlwV00#%B#kk2vBO*{$Fn(DSzpn?EE>tUV72 zzYC=+0-^^^O7#qPV&NlJA@H%Is+QmfH-r<%p~AA(gw+l%chCm?XJfPSE3*Ea0M0P7)_E61h&=jSfGJ(|3efIcCp zd;I>7DC6wZ0!kIz)X(cbEp<2qO788VvYRbL?uYu9z~+NUbS$lTXKE{UDE5V7Hc{gM zfHUwpD5A+gXb8996NKhEM${W@i_N3>_fspOf7p@#ETG-k(Err{^xzwU;#vQL5>km9 zRCrcxZ$*cgPD?9QwcQBC)f7R)?H=nh7{_bO0nSn6!1s-eLNxenIQJyXHlKe~JxWiR zutWhj7Y?sSD4ROfTVHe}QHh6TH$;a~POyGBQ6U7z_~C>TZ*$I7q*4NAa2RSQ_>Q%L zr?1A2WPk=zn$cOl6f%lSTcP%ettvsfO}Gr<9gyF%2CG1J7GY}QxEkmBl|O9!16+f3 zIF5$ebZ?2;;nr_mS%MJNLdINNQpniuWPI9^k|tcAsx?nGjwPk2!QQd_5cn=Q=BwD>Cj^pqyDEADQTRK@fiU~Fs0EDL^{ytZL3Vb)$KJZya%wM4 zwVwohOGdFsYp5b%p!B!p_z5nL;Aw5C>MbHcvs0<|EYLFP#_@)DE{e)L8wL1e@H%Sx z`wl+bvB6H|+Jr$RNE8MVB_Ji2Y3)!dikBS$QiJD!i8rPzMimzzeOS_LIn3zuoG%lR z6vtdl^I&tnh5{M9viohss2A3|@IcW4f@3{LB5$0SrhICPUFS39Y#caG?@K!&TNX@# z(}u4KKm;!y^W+>JX7{s4=gegBdZan*@>=C+M#%O|O~@=+64pS{N|sn+(AFkik&TvX zg!_bXJCRJjHZW1lm#F*E62pgEx(~S&UG@}X(tmAIEL0e^E+ghLB z2N-MQs*`6Qny2(;P&UWQOH1haT5s*pd1-xB>>kRqC;O3*KsT;);+x`ad@>n*Xkg0%EnmE$7 zS=rM8Kdwt9(%s>Vh)`^ZY-;4Wklz5|<6UaScrJESqu?j{P6EPKQBVSIlF`rZaI^2^ z+fG8DoUE2z*t0yLXe>i)4?d`~Axjl$=5-BY;(I{G`>0mW@}Q`F!^%ExT4BIz8wqdv zfOz*a=Wc_(02>cXtpDozImSd5hP@I0Urm^~EPJ@ps1jO-n;q_(mAiOaabH}YT_UfV z2?QyFkiwRPSkb54zL!(T*e8n!@RwyCHt7%m3C<%?>!7E69%T4RoPiZMBguvAbCn~F zyu}JJpinpyCkK-gXfQ@OA>3(ed5q1ueR~#1X75Ey849ZE^2jbGq3Tv67HF=eIZU9; zNVrP(wYWOBi>HcOso2vU-A@D?>@H2Ad{0iN9W$!C7=~qa8nM{FyDo3F+Cyk}Ve#g- zeBS1R<$tq(vs+AGf)G=MePQmYHTN!7q40r6=wV{?J>3+*v&gdDNd>O!!vYtE@IeX2 zYE9B!rs!{h8SuY}Dv#;+CF6VJg@4(NaUVAKengh{91F`@eQD^0;Yn<+u)n0=HJ?=c zqy_;JFjLBrEicU4J4YS<iu$Sg7qN+k@2LYkV*M6+;7CWVI)apd>!D+7_#NYfRq=mE>F*k*`9zD% zyiInbRQymn6q^}iuIyfXt6L%`a$3*4ZAIHbJxhP$o@#>G> zKONio=S{_Q8(+N@8NTN|3LiCpxg+w=)%*JOf76$;uP`wu-&go7U9>*xQ#ieVFJB2% z59_%&(z~s}w6iQz?5X({F;u_y6_^>!bIvG+R7t0P9EX=P%G`;606cu8oZ}AW61C=v zC3aR*b%*7Ws$YAaaQ;kNeG@LprJoV`T7mUdwJXpme6*2vD0ZU6XIRdjv|;J#g0Y5D zJd|o$Hg4MTF?Xf>ng2J zFWjE8*mu%Bi^}dnU4b92X*c?6bs`WX9>yyDIuwb~#>ZxeJxw-*)EFf3JGC*Z-lU817_PQgJ-<=R$EH3!ncbC9{ z9ml3s@0~$==dvkb#USBgOld~C`G(R;n1ZRUn_kX`(^sm$ow><;fe9FC^PflP6XPN4 zg)+nD6iribs;BMqg3Yh(8xf;77q9O#z5juZ&Spg}pE~Rolq}LErD`Nwg9Yd&iI8=@ z_QlwA9Qd?0{Xa=QniYl{#`4W8^S?RIKNM3WnJ-h0F3rq&->&vpgB?)d&p-|wQTF0m z1aoeYP*mh(XX%Cvk?DvEl`)3P+ElXit%^iic=e#?W3Xgq2v*ayY@V2)K;?GgR9Lp( zIsmWq3QHC zoO)N8Xp;vGADMSMv=9R$U`xtPM>Y_ttBaqX01%wZ)*R)JFMECTW6g$kEND_t z)z#=eyS_ps1~HdyLsI^EdxQj6S?!JszS&SIW9L`qgaMsepyE z0b_>#1%c{)Oa&R^Pkom&6`yj9p?vJ7lF+u?ic{=o`ZAb$7u!DHrv&36{kIyotn8qc z%7H7+-{Z(`)v3-4GCS}l+kS#`AY*W_k0`4vhpZfg<16D0Rmtg3t|i<*5>y5Hp=8f+ zXep9w$=PyZntLGmq0mTrXbNt#r0mmlMD;Q|S)jn^{1*9Q#2vx3cMcohm z%49H}F}sf1rM4rBB+Hc1Vq`3TCj$d@tcOr>J7$4KL#2wm9;-v z_?N<`?(X(T#!z<+zX3c6B%^g%5~x`*Vw6gT3WkTV4?|@?kuQhf9tCIU(egVtyX(}m z>({uJ0MRTu*oyP=J_R*Q63v8yGQ@us;8w=qlTm?Mi=)T$K}Hc6bGr|}+~1hY-M8JJ zwnHtTs;H}5cY(_$;m$q?3E6QBflB%W;v2N~=S{~O+|1Nt*t>ucRZZn{)_Z;Fms3}- zPI?rO05?{P82UxLvGp1o4-vh%kk^te*>C=ie!!S0b&<=NqYfxV-S>{wvV{I$pcaTJ zK%uD5ud;mXv^mh^Pjw?e3p&SXzVd%s0L^9+Y>v^1;;n_z+&Z5}PHZvE$F?n6sf}Xh z6YoWzV&e&4*dq4I1Ux$kHJl#-H)bF<#-ONHa;_nDH z{KL?*G%6P0!N+4`V8nHkP@2e0!N>#Cp6g++Gq0b0R5y-6}yG< zRnVOZMK+x^qbQpQ8&PwMib-}Jd^qY;DK05tt69_QDMcrN#KCZ1a;>Wb3O>3}+V?ZW|L zs#$)s=UkFcbv6Ivr@i;(tO=89RlRLskXej(uMK>!Q+(;wHijdFULZp6l|Gg;7frV; zT;}`V?9PAG|G3YTnhz z+M{ZAa2uFu@!I!%qjtlDa3%-sL@gn~Q`D?4ij7k6&@3l!ZBcPtwY){(JaspkG$Q{_ z1+|PiZGC(83anHw0axnJ2QR_wq#rL(d~9DQ)S6dZcVM<(yqu<{B?Qf6B&)YabmNN^ z{hyagX8_C>bVNDOjyWGdurVzhBxVJT;>EP7_L@KeMj)FP_R(~TiEw)j6Zia<5EIQd;Y@QGnU!bsLI zt!+b&Y@%QIw0a6Td_F3ajC(z$0?CvXZ+j-mDPSB+&_ulT${|rP3!-u{vg`3}v7~|Q z9DBR{iNa6dbZl2vWM~3hG89_(S#s$^2CqW)VA)*u@A=nw+BQQ~km_s%^iDj-^#yjWEaij0cJmkCYMN^Q$LXKNaQbC1ZPck50To8vN=x13Mf<=M(~l4^y3$=oEEUll^EcS z3?QMwsZiIl7lCzIiG;<BR-VE#e&Blp?<_cFNg-;oJuJN1!}MItp0sXa@vV@bDO0lcqg zj9)8V{<|rhr(yb%uwZW91ZzRh&_^__)qIzFmuO7O>gnkQ>gL@a_Ay6EjsO)SDL^0) zImFHeXUWzl_7de$6p7gKpCS`wekNbyfj!&xeL_^Y2NvGtriJHp ztVkGUJ{3+Tns=zkMJ3>&7c-xN+B_4H;Sz%_S!MW31i(z4${+;c{}%{DK* z{z>0%F;UZ0^CcLicTF4*_oym%aee>C9$poio%!w07f*J`;avBX8T>xB{}9}Bt<7_M zd1=P%L_f)=%MYW$P~hZ3g1EOW$?+2sDPXDFA9$W`CFC_Gg=U&&zSTcbm&}XZ4fn3$ z25M&?s}JxmKf~|y5409BtRS$-sieZhxBIm3i72ByEfPU$#n-mVgYl5hg3&fH8}!1~ z@pXodhM~Y0p^P7AaB98ANpw@CZ@7rdwf4K7m5kQPCC<{(DTxDbDYhZDh%A8j<-4kQ)6O}0Pi7kIP{Wp1VpK8_K6L3F0AT#^_csk35HkyE4;~F4% zg1cL=;_g!12;vpYMpGxvR6 zjU8uGnHA!9F&hns3|&A+LoU;{#XU_HbS%;~ntxeo(I$VekmH^it2rL;iVf;Fli-r8WK`aqsQmBdEFKzgUx5yEN-%Buzxmwvz&^Zw&CE@`$Qig7cL7>oNk4)NIOUNPM1>4xv}j)%fvH;+iT{s$~ltUwlwm9J09y8 zr=yH0aG7vN{B_-%h_c5%|9oKw%9 zu#SbO)G9KPHRyih5Mi|01B1K#&EOn-8ypX5asxZ~-y*}VWcf-#*SX9L=tLu!R-{4Q z#=kM+cSaOwM_S z#2mVD0o2bk3Co{Sqa|el5V*aR+~?NJYi3VH=XX#7wY>EFz4jQ8Ey!7P(puY+=dr0P ze>vovs%3kbkRV<_g~Zy}40Lej1DCt$xWL81GyTHY5R zNkIJ}(J(AynjBdMc=7O+_mzJmq+e}PlQ~ZO#YRH1+1yaVfiavA%0wy?kA_Mj^S$g% zB2!$f7CiacMgD3-#b{`D*6)J$*RMJr@gZ`2y1LyhMXg@To>Xv_+9&o%Y<<+x2oRn) zzJr;@C#kBr*t~@WS%9>e>LmZQF$@(m*_ze(k}|hE2MrEm-)+Yqcq7DuwyoCbB4KP# zF!QVE(Md+b-90yWI^Yx$CSL_e{52wkmTb>%Fs_r)0&spiq+xj%wPSV~LfOkJYE6!c z$;^G4j^q~S#Fa8wEHFJ}itF=-qK#3VcP=@!-@W(tr~9~=Mk+eBYpiZw zk@E_o@e!=SLhVlp(bn6EeQ^~)mYSTHPngkA1{P*&@A~luUiE8aV~|^u#DqC#BAMIcuzzx6&(JTKWs0KWTpMc3#f{JAC5;B{SN(aRBcXbWR65tl!gpI7&l3z zu`-5_Zdy)E^HDvKp9&)c`x`bl#@luv0m^)ukYhJ1euvw}2tWH}lza9KM(akxk3HR&8G~bpgPo zm1TX&)gif97Y9J>CdEvY2|sr&f9f^DY(Rtqisq{j9$kfC<#b#nDOv*JE0#&mD0_&k z{ea{K=E^dFvH)(uOw?E^xn!VSA+jz|>}UB^l=&hE2YwA+rOb$d4fZrE>x831O>iq& z+mz=CJ?r`+H<5{(Vo4-bweu8{$ZVLf`HuuTkabg;Zasr9>f-GnGBcg_qVCymOI_aX zOkv)kCn5TS&b2Kv8kqE+N=%K>R?h6>pj=vpdHp_Fiv{sF|yg!Mu$P68bXCe>BPLPR@_ zk#W_k0xQW-;WBOd0ofK2WHW-cTiwDI=^3i#$(KtO47KD0!awM&mU-bYzE<8a?1W)D zlizIC$(x5>1|Byo#EeAJ!M;Bc1uf;zw}n}}h|O;V>fwy>(dA|9 zY<4JKl(6_b`BYgV_fvh`Gi}zqSJ8rCE*DnRW%5SBLkpqzbo~7!gn@cgab_HeNfRK3 z97;X5&q{gb+>$m(!koR#kk5O;SVB`;i{l+1e5(NCArtc!LtwMj2rXL~oa&zWJTzs+ zu|}e#KwtyTin;#n#bLUUHUN+F|N$PkqQY$)IZssjnM(Knub(ia2H_8?*r%F&kh){=iUuQv z8(DeUNn_dhIKh^llDn-XuXu%AaM9x^RW+;nvXDN@GV3!6wdDQ>reFH6f`p(yMdS%l zs8LGIYx85V6tF2_$2;Jnq}07vNLd(^C57n5R`DjaDN&)Y`x}9cH1TRlT{8F^=pjlk z?Od1W))z4Xsv8XCQ7g6cWIzMJTDq_F4i;17U__OA_s>ZxZt1ZL-?>4%t6B=8_LT0zw;$w^KKDQ1T#Pg#F@HPH$!Yk^~NAC*<7SyLNLA%d?JUt3PKTdy+$ zds)T`2i-BL8(%`P6&totXC4LeOymcmk)yg(t;tZOCm%_dP7@+p44 z@M%~k@ov+Yl>CL5SU!idrejM7Uerd=4r4Q8)GRaAXtZZRMzRNpphHwf2ocseTb95) zWLYe6S-~%on?bdF&r;9^Sscc+>{yHecTr1F?X+*qq}1LPY*C?$d)8s0X7Nq?hKyk)a_oKRvkyv!I7z; zkpTNndAlcmMPu4wS_R-JIIG$brbFPEtoEVKTzMwR5O;ExqWz4?bKyi`3Y z`UW1WNl{i&R%!cP=79Pi=D3DZJAo|Dl_E@)4d*_h9HibVsK-}Gz*2J~ls^_yhtM4K zAT$R9@3(Z8q4+Jy<4E>+k?cA?$l3JW?~Ov7#C<;~Y8O@ODrD&^g$z{3uuItF#-Ku* zHJzmyHh`L-exx_524*Bqe92Vhcm+Juq}X{ifFh-JX&C_TQ8%KQDXt>CU_M43xc$#q z8~L|a?`VAaJF4LUARlN3==xqIaAXuM>A18Bdzf!|fL;K_NnnehJ;Dl0L>u(|f(qF@ z0XaUhR$<%N*`Yv5<^c(u@q{*n3&9%9#Hc*ShF0_eY6db>tqoP3OGxRPRs z%%yTwV%!{451`K>qL0R>>elTEikonFa@kQqgddU;&blN%QK*(`;5Z6|L+p^)_S5C_ zb`&Rs2lNCpjM_ZN_%LGa(Yj*wPh+4*jK2LA0@(SP$lwcHW*k$%-yR1QbhKW@pTL__ ztmCqN(lh7KbCM(=bTZV8a3=v7J)n;@0x_UK@^9#Ii6|Y)+6ItP^f5YMT8NbBNHE^` zkhRL+7`c^S)Ae=Id7XKPyI{8RfhW8+*&Yd|>UB=}txl*eZ?`mwBGwQ#W27rgkT>4)ly%Pyo=L;i6ApSQKX6S(j=O_C*EhcR5X{ZH0l-_M)XJ|V$1i? zW(RSp$WkRF3(Zln@Xlu_8^Xay!VOHL?;$EsCpE|8a!4KKvy}j5X>fT-YVNx5k^_mm zg5KRm6zf+Vkqk=E#lL6DZj{7hLcldaWz;SRO9tDy54R`ly*)IGNks#?a<)b29aeh5R z5|lI`>Nt{cdchbp>Fn2-T0NjBV^5%%-g`S@2SkIAaWx7!etSPPd$Dr zcSLqP8>(7L^ww+=wyCrD+{00zS5@Da5vUCedh4?N?g z)=aD%NJzD@9cBwYVIaold^|ThBQj-(8m8|7brhy$l9hFo{hnqix)?DJJG+652D)!k zqmRuh5^FehX4jB|Xg!-6G8}jiy?{x}5mhi`-^AHvL%QAON3ZnaTTu#bg_dgcDahl3 zN5f1M#Crr1MH{C)A%~qtS6vpf0Ey>l{{?8!Yj=_BRUDjG^oiwT8e|X3*dw%bIodj? z7E786gE!{2T8d9Rsm|9pBPykk=h#;lTE%i)$WW}{vQeT8r(w|;(ALmZ+a~X~VUk8O z#j?DqvM^jnxuhYgbc`M=Y37l-LSV=J!)egvuK)u6oVFblJULLfCDOmjfEi$cMFVD-jsJ|fuOp|mqQI4zm_(8|6rtjOEKD~(>b-GC?sBV{K>04vMn`@* z$y5=X>kU#kKj+Qi(BOqmzE;&T^q#K@hG(jTWMFX3_no9G2`GihgS8z_|_7>{&)Fg5G!Ie^n&MA94THn({`?I22O`( z7#(eNjlCaK02`w88A}i*$OpoIjeS)sW|oX-Q7jsS99}7ZcE$(`nLC|Eg>HomngJjzKS`^~5P@pO* z3_h)0#MH(xc4$RDLYh~GndU4bq#nzcIa3da#uiAB9C2`|-oa*t)#*PA;U;NdGX`HW zduEofbcucZc*ACGX%Ay>S;=g<<*?s*cPBy2WxwL?XVOvU?&ITAni7O*A$Zdghe zro$lco(BjL(~V1C%35-8E7l1O2l=G5yPagt5`J;Yk2kP)P=9^O@%i4=aGczZ_6CW( zE7;kCB$C)f!-T#-QfDTTAns3%3iJTdSMk)yg|R|Ttno&;YA9i6m_x2Hj;!oVzgB~h zDNYfr>QROHXFZPUXnb8oRVQrx3w!G)W+A zr0hR2%+?qqRXwI8&Vt@1VDh zK=+gN2HD|4lT*rWl#JZ%^j(R3wAGm@R9ELIf48U`ZxFY22;)F(jOQRzU(}>?U9snZ z#-&&y#eqmU!=u>&@=+jmB^ix*>@V`c6J;Kzkv-}yk(U=5(@rikD7y^H{zXLk-=W5Z z=%LuuKPnztNiv+BP2E(|CjT{8RiTvJiUjktMBc7+ziIu1GT4+m=>n}G&ARbGP#XpY zdRy&9xpPCB-U$4ML-dlFxvKFea(ON3p^Fg-qFJitCQYuW1Cs(#pk{w$G_oA0j8u}k zm|FAZxke5f_D#6u5A`)MY|tiU$7;u06ZwmfA-nADKO=_WJ}6klZywqBD{N^&Iu8{# zr994T*8b=wv5u7=O!8!uQw!d7+ynAg;A?n3Ye`IHl#!T|yx%Jl2jms*(Nw%f-Nt$Z zu`UOO_YApB)U2RI_6j@nmr?n0$yC)5j8jIk*IV6}CkT#$IM8g?pC`P!(SB!)cCf$b zGwWL8Mq?SAAgA*qwoNpAeH~z$kjqLo%2*v^(8Pn=fEBMR18|9J>biWAH&UBP6KL zP*$bL_FMMaR*~%WaQS06*{~tj6OssIltv-I(Zx%z-Xhz;wnjst!`RGxOb&US9r?Qax`Cq>tlOdR)}0v6`nsvp+kv9V87DfCDbcd0Q5>O?-W7beuTf z>>0FMnr?59&Vz`s7Hm{Z{ifQh>4{Kpw7vd8yzI z3S!?wQEG`{)J8~BFiY-KF;sB{B&WYH05@mCMS_6T`YK|P30Ai^w(resvZ?LG}u9=)1+wa2s}Pv z@r6oq)^)b$P6pF_hVl{3^NbilF7P=MP_n&iOPZFGUXw4${ej7SyGn76w}udrVL%`$ zNk6!Zvf+A6ri{N`$Qv4ZD@Nh;Dnm*SC--GeBqs=Yr*U#$Dod&l&O~lO zYBlazh1U0F!f_jW6m-fNvymWvFCZ7Ab)5k$k4dd%Xu(QTMm_e-Yu+AC@k7(lY5s1d zbk#H=?$oyq!aAyDayTsVCuk3vd^S++zde0;Z8x=6@OEc<4k34t>=_$tKiDNm_s19^vlfy7dldp7r|&417d-;utCxTd4SRL$a^bOeG5%$7waz z!S;mdk`EN~=r8-gt$P_l-5WBr(-N(gg5P!+bfV)J2xIMW)<8cf{~1N_{@YJc(KwX> zJP?x33*Ds0RY`tc+)D=P*+L%uLjSVQy`L1&)o3bAkibQuEYxYOub$GFh@87z341hT63tV0N7;}jupI}I6__4i-8#W z3hjb^e$PRzO_K0#Iw|hO8)=rN+)Hlg&}yVci~s>rlN65%VupBu>M}7Xfy9?%F&HcU zMadg_9kuR+2nQCR2wx(3q8 z_)^E7BS<0aGQ^dIcq$g*!m8Z~IS+)~Tuida+{vN_$ zO=?1gQE!dgW=oF-1U+A%s)^*Yr4(LesTjIdQx}3)*QsVNQc9J(1V+&ov@&5HT-NbJ zq~@yt=8_>UW(toODi&8(CaM{_rBPSjLZ@)Q0xtZp2s*(YnqPeEQ9B3eb^(Ns$;iVQ zaFNN;%3&sB0~4E=n~3#hgjn?We7F`rs?pXonbieVtY$L?!q?ZZTUy~LmjIba} znVITW7UHV4=I<5XG#<>~i9!JeT^~=?hW1h-OxHfBCXkev#SFGv;R7qAH@Im2tv*0~ zz{b*9!{#y?wn#Cf>|0H$x2h^N!zRDoNtR?h*azaK!P*u0p18PO8rdfuN{MdRdu<;IQ#XiL9wI? zg~If4=~4_a$8R)cUAQR+*1$kx%nC#n`iLpYnbjUqDY8js5Uu{#ErHAB_rIA zwLK9l(q@41Zck@KzrDGdv0hB!JE*U_%676m6m5JHNgGMce0iWl5~myMbY0t=nbBbq z8=44C?+Jkud{*+TkV0vSXxLE^#=!^Y8(8@MI2w%JBXe&PFiOs2a4a*T)qIQ0!Cg57 zN|wUXASs)#(iD~0Qa&}nsi!M$L%m<9u3sar8o;RZ72=U-4?D-*rR&gj`21!l#ChQf z7Y6=yGzauH*zS5N`wvmKO$u!`el8ph_AorD9Ir#`H{znoiXL+&s*FowE=sQXuz{Sx z!v|8|EI^<71T71rkCT4B);w^RN+QZq5{e@%PsSo0X-=;K65p!X^2DLCNk|aBSzEl4 z>_-S+#%~Q@l^$w0{8@%4ClCikz-b7qx+7vKCDxw1we;ABxkYf$xJVgSXO_^2lj43{ zxli^;kdP+2$7#Equn|q^6nCL~lq!PQOkh_zSDYz1lmJ<%35VzT->2VuTwVOY8u)g1 z#clVuYKpx0trY?rI2V~>=xua$y_<%?zHQZLPHp}W9g!J!l{+MGk3Uys zN0pH@x-@GlLl{T$js2~6-{?yCrm)R;^1sj0RH(V|DR>hw+In?UOzKdlk9T@t>81LR zd)f!%EYQ9pZZWgw{R8az3jQ7JhWTX&wlMEOcuNk@N9NbIguK4is1c^aZT>`4>#1T# zmc}iZjy4(>K?=msaFjK%j?KIT5a`NBhIE#mE?$tXC~(k!wd#!@&Bu2tPpYbp`dfQM zF;cT6win;{rZJ0cqrzI2sqCx)745eM4) z{To%YDo++_EvD3##}%~}bh+{-&0OO4xXlLBQsj1I*yer6)fB<@)7QDM?j0iCnJO!O z?fkzL06 zx`&e)I4{==g>&_fm@j)9)cpf&_C?8_uU-*LM!k#R&r@XqIz3$VtJQ_JXoG}zc#5^n~vaS;F90XBXs`w}f4Qut2m z&dp@;+qd9{>(m7B>p#0_knwLb-S9)6SHY2trE|cVD7cMS71gMTA4ZS%CuBg@*bYW; z;w*uZeI}aHNm5e<0rx#3pjkSuff*nWfyq5`D>#IfUoDo_wU06fxR&1rI|(Qc%lclV zP9u!(Go1+R`>0njvJqf~Y8iTa6r~ei#zXpnBn2Yt*zb!veTq9?joK3Oy?+?%)b20m zb)Sj(+Q-#LrcTl3G(iCu~5lb>qhmBJ->V-gigc!bjzgjpR^L)Fo?>(T$3yy<0>crnKt_pR1K ze)%Gq(b0#f9~*%&H8%bjUa_4@>Ni^!hI~gfyu?vkLB*@XP@ok90l!t;8C|6XLGp*& zXGyI4hBX!zH}PD$I3&;vZZNx|-AwL}j_@wWAD zYDY#EF*E3?J0Pc0$SXTfsG?H|XPSuQ7l=g&OH%O!SZ`Sli0!9F<9bC~Ps?Bpr>-wJhaqZT3$Ki+8ItjKg4E&`9}wqC|4I%|Kl@== zK@?$svEFpW5#2z8tp1xM^yUxe|KrLZ4MZhrG;U3iT9f}#Dx`6aA8USF4IL@j;WJ!f3;?CwySiPV3|6Ty z!tNzhmHEI5Bn(l9kahV8EmlOYUZZ6#BYSEyZme~9ZPF?xuCyxVv$IWX_i9i@cpcr0 zvx;bhj)3_OC-zVwqD`kYP55_hTO+={R1_1zVt{DK-0p0HmVoPtJMXu1&A|)Apdv@zZWwv@#sehh8N=ie4`f#$o4N!qBGSOFSM;nZhDO`Pt z75Du@EjOn0X4r&()~W~|{qSJ?yRJ7s(X?k4YwNPzk4n%XP3*@inIicaO;_rd#H#5C z5b(z}Vyk-Tso-$-vp+_)(ae`LsTz`;@XFaZcyWw$!lx~f>=k|!lP_d}Gx*-<+&`@f zgr4>ql2WscCfSjO0Vrf_zstw1j4%>bFc6b==SuQg9gY^WJJm$o-FTs*r2R>(iG*rK zz5*9-fE>{)H2`U=aQhCclx*g)t`3GV;G_Yb%sDAFX{uA*fh4OkCUp`vZL6hLff z7hWN7zT(K*3<&cbi)dG=cz^Rrkp%M=F*MzU;Wf(pmABjtl4~7544_gYM-PTPV->Ie zE##=bbKUNrQk@104DcFn)fc_pX;(h3*aso&g04Yks;G%1|FrWc1dyDZy2*@Z^5@Fa zGM7gR@RMfyc)&X91r%)_SpDc|h?M~pCq&;uMLv*Gsj2lwUbicV&IZM4;c~aA{8bgKuOXAXz$nxBGG2BZrUroiO}&%7djDX~NWx-FDHBO55v>J$b*Acd z{Rd5YhrQ5_-r*u1U~)3X7n}q2%OQpWI)=||&C3KC83Qp&X!GyvbGC-^N+G%55G-Mg zFw`{;cER7=vH-V}`LsFAl)6u;WFEF|H;q(OiV4O^UCWqBI%fm+=7_II3-P}jHA1Lq zWEH`8Qa2mzN05)Y(WPk~Z|GQz0HB4%tNhNPw!av^LO(1?PX+lCf$L_<2aadK0;vYV znUY4PdJeI4h)$WDL$L)}(7&tB6*wHs_+${6F853M!{yc0n?QRRbN%jQjvyez62>?O zrTd-tUH;6hr?qM&tI`(|I-A+ELf86=eF8+IqT06h4t$)0 z^Mx|PvByE7Z`DQ&Z~1KmX#95+-IP0l#PEu_Bw)wc=o9Jx)Gp^_ppbxUzp&1|um_`x zI}}JIzS&wN67u*(jm04ufo3v!Z7q>xQ$}D@pz_D=w(;19Y--|K#kOeNxj-d-&?=C9)VGXq(8K=}eTG-KK;AZE7>gOB8Qg zS)W!ro%nx#V^ZCNC2TM&JCb!>?jVu;NPvJ%g-CNz0(G`!}{<4;sp7z`ql|(qDwG7C-#VD%_q$6iSg`ZTpR5 zR1OgJ^Geb_jaFQ_{ogDuvEy{bH_Ytzvop@elZmTItO<(+f-#jH#y0Y*xFw$UGrGP` zjB&Ly#imxq6>ZS8)~pBi;9r|u{tW}|xX%Kf49u81BgpGR#*&l*T(W>R2<|J@47X7S z6iXL>85e+C70bQWo2H%^Gc+?KYlRQMo!855-@XahUwZ{mFQ$`4JD`c{Rp(g!_i}2i zQ}Ws69u0@|4UyGrTe0XUWX(MZFG|npk@naCchK#yf`pr($Ihx}-}4ZyoKgghh!3@e ziQ67~VcVvR^dXFT4Uwz%#^V z0S>6Kq#l2en7TvI9b81cL@kdyWd|B>3r7S(gmozo34SmOp(T_}V^w583wYrrX){Xi z@+F0p1WPm#;GnnIk}eJT0m&mw9oNM-GhmPA*?D3*C0bqW+z7H@N_a$@!#glltzmQu zTKK}%$mA$ANsUnGl>@t`3nM+1P@D^nT6OfG%*;<_SnoNm{i{#KZ%co_-C3Bhh1i>% zccVs@+117HB1nc-4n+B#gMUVieqvFrj0%RPmVzWyW5(#Gv zM`ywf-mrfAzR$YrI5&53nY}_b;o5oGq8{TB7V1V-r5`=?7@2H1y0X%=Lnn)0hjh>P z6%QrPBHzmhg}OS*TCGAA*X6Q3T8puDMp04KAU{bxSG*7k^*UJw;!C~|wGTQ`H1wDg zAvhe>JFP`={#-~D6nF69GDAP{c}W=;ceHIv$KHmx~$io!79O>|9?i6Tq|b8!I!~Ib<*^t?1~z!YTS!L`aCztv0DwuY`)Xwl|OH z%o$mTL^__bj*-xAA9J#hN|bEvrtbhN`S@5C*Rp=+@h{?{fWVID|9_WCC!reAPgF1n zU))1MrTm_3o4aXzq+?UdxQYCZm81W{XkWY6CG=x^oY2yi5cAmY4}v1jVAtpziLVmQ z?ODEQNtjJ5UOp{xeY;=q7fT+{%@uzl=zp5Ub!iR|5@fC20rM5}iI_4l?c(Grxvzq5mlulwR@2cHt{%FoQ78b^RDZXdx3#>uW|vm!q(#_wRGQ+kNOuyGc(mXte6P5 zr)huJwoRe3VZ~*34tXYaH<dAr|Wt^=STRKq?!;|(cN%XQKF|dUeiyF9lP)+ z(iY#bMq?vQwBN5uYy0f4K2TVmY!L+1Eox<`FYl&T6OneEW&5+^FZlBKg*Gmt@YCem zvm#5a(8YA?;?etzU+T;^N84|jjb7r09QdAWl<|F-X8U zLtj%%Ac7kahEyJ6&`)wF#eI)O2;@652ovhi;4T77LDPLt=>Iz#WsF&|onkY}$YaC6 zM-EjPUjzJQG{VDGt0gDB#>^aDFs)&cs1|e-%4e_u`Z$D7MBo|HhMyEC zrajHCfbtd$e69fkV&zs1>tiV<+ABa3h%Hwp`n+x5rVA9aHd-GgWw#ZuP}9(Wk0Lix zCF@(<>2h*@ZWMICIa)K?E;so1g1x;`$%I8&fx&|SlW3h>x5b{YO=w+-4*P;Er6W`| zLceyGQJ}CezU0b<^^4xlnw;3GAWf<5%wko`KpVHw%y_s|@89qLRl2Ki{tza~+#_C%zJb?13EJ;8TXKO+=W$39G*+HZbLH_?X;*AL--Q#B_FX(Z9$ zLG~OK8JHCOwLSPs_!bqy;#U+L+2_kBQo>|diNQ8aH^9cry076cTK9c*u|2zn+Xa%b z&LDA~#ZKkG%kQ=Qc`nDA&6|Eb#OKJG-rg6{iblW(5#uMjX!WsVW1nbb2Fd2$`8!^x zcG_qA`Qm@f>^~f-he~B+WP%x!!fw|KDHCxY{C4E9(Lda18c|LnDvkhS{PK=c@`=wr z2NH-4h1bPW0ZmajRE)AtPBcx3Zk_ zzSrOX`WG;1{0`00&EHAP@ZH_V*KS+OqG2vYkdr#dsIZSHQ^oM*lF9kLg7dnH7Rf@< zHbn(?7tSA#v@6YBHg3^79uKz=!e-0o`%8pX^xRFkFD3r?$CQ7`e*$QUpgGA8TMyB+ zPuDdF>1hqY<>S)(=N-%sTR|t1$;!NGZ!7{2#e!4su-B;gcoP2q=!Y0-%8>Z|i8Ty(I{H^9 z?XWUvX8$4Rk^Qpe9NnOjn!@_sxQ*$esrcE^NkB50#b9SjX4K zkgfJIpPJQdcb%!f;S;L^z))TPH>q;xnC{HBKq->lh1^?~A`u`4%n^y=7n4Sl>uXZi z-lf;)%O2w4)@!53mHxlUdt*{}oqj`@X>F|LLtX6t6VX`X#SH86AFym8Wu?PdiNnHZ zXqf4h-cxG*OOq0*C+l$X<$~s3X5qUIlUuFxaLB z0KwW}Pqh>&c?{mC9?z1|Gn*%Y2O1#jMU9d&MnZS!-|X7)g<+9M;eez*)9q$$% z$kl7En9op!_OJUd*C4*6{a5Z5G?r7X(z9Uhe}UJpnO?%4rY)s(pAI;uDmv}AzedM| ziXjMA61~LNk*>s9?4=-up6n^ z^TPe`Ys(YDg5Ii zx%eO|uO{9g9}n8Q5&1b1Nj2qLKx=?@u(3jDPyM5#>Z;PRbYK+ozP;wPJfl+#^OQr- zu2~yoxQ}?ncTK6uoJ04xv29SeacqYEl-X!T!;;mZ(Gs;M)+}Ja92P)=qVV;yB+Ph_X1tO~Q(7*I$Xi>mx?nygsF_FqL@W8p znA<+^{GsXO-1{;&EXuGofPn95!~3V)k8Nq1xvjSI!KM@8EnJTXa6>LHra09W`3tw@ zUbLI?#fY9I?m@O3{}S2H2XX6AG>0Z`etTAcur9E}JUOYJPgPj2$UpeI?f!Jf z;3fTV)ktjbRmsk`^_ksUza{3)rz_G6meFT}(ZQu2p+Owe-tAup&3BQnLcSI|+kg9e zO8^ePcyj*n^oYsxZ~O8lQ95X_W96mx8v{v6PoAWt6>fM#?d)rxjNPT8$L6;^$YpzjDEK+X zhb%T&HI;Dg(Fh|;a*_KrM?;iOYEwr9qA21us4(J5Cr1SEWM_B-UK^Y?N8}NlcB5sq z;Q`#b&q^d)-2GyC&r?3@kBwQF{pE58%4%a7U8p`K3DK%=|E$_(R$m1QUcCJ4Axa;F zFGL8+aJS+PK~)Mtk%pU1COJGwC(w`6;)8p;hvYBjY3qM;CcHk3?cdyn9dh2a;q(8t z&KTJHh$g(XBj{*>cV4msW_Ef z><61-Quo9m-H~?*1FW5bGC*$-J@)1*{aX@bB?i>aBkbAS8swwS|ePzsvPMH77Ecl{8q+_5sYx#E-)l7qg zsTKw7Yr9%M`(8JJ=rG_BLh$nP&$91)rUZGY>Z7taLTE7h%wDMJ;-+Z5k^}rhp2mt# zCI4aPuNjG9$l-?pU}Ja)hdpmHFZz$BDRLkC4_ij!0*2G5Pl9rLv z32G@XAJW*+jI8%X7g)B3m0JHPlG7Yd;ja}tw#%rmLG4_Z!M2_l%hwGtLHk%gf^=wXnMujGz42eXZBksXYkB1qUKT(JMjRrg~_WDySOA;>c@$6RL0j`Ct3$=f@fY8N0>f?&8f z{$j{5eNvVBBh*xByi4s|ae`ar{_ydRq$}^m6Xw~~qaUS6;%-Y6F8VY&`}!{)y}d!) zzn7es%K_85^RtC_B!Oy*F=Zks3lKfsnIEZP^>2i~{i;3g=r~Cf@#LXXYKvB+;Hf%j z$9C7uR*0yld;XF*qQfmzHTUSy>G`S>aw@Zmb7kV;@TD&={ebf=~U}t?ziSNci-PV={kA02?*(hYFCvt z^D~qGL$`7?bVkbIIpPoc7wzu0L6;x@d0H>%CVNhuRQx$7^*Q#gEo(Yh?OX83jDL|? zQArIb;No!gR&j5U&G`G>pwPexe*da+sD~NLy)7mh zdBaZku#Jhj4y5HBozk#v562WqrJ4=v@jIPqSS54R?g5o`l(uu^I10;iOz|?2#f}vV z&-Vd=3=gBJvcB?B#JR~Rx-)u_=$^g6DxnLm6HH(#6Z`PZS61fNn*H^Pap$;)DtBw( zP7}^^&zWkUThkle1p1go7z>{H`L-0Kt-=u`-}Kp=bY~>xu*)&(?}*1KtLGE;A36pF zl~)qX9=9ZTRYFr4Az;FhzmZh+;=R|z4-O8MyU>N%D{^VmGyUv|G}N%8-eLJaJZ=<2 zjQ<|Y2)sq?XqncT%TGs0OZFUK!@=xDq95G!d~h`- z*@_LW$g50+IsRP4i|He?7j=iKhK9>tGNI^qY-3?ST5Ub z45`5Wbu7cUhDONe>QOd6C%&L0>M0k(0HdSvo|(Kh(jJBhm`+1-x%?E`%rD)b<;c0# z4|_*+f*5`xcybbPSs3OyIU{i5e$z#8rQ4kVFpRdAHlTK zCTK`r!RYBkz8v+y(jU<;d!Gl1q}h#LDV}U;0ymcf`bh}Pl3$YYdh1}FBv{I&Eejr1 zpkkQEy(~mYBzB{e4qiv_Uy?+9Jmi+8s1Rz?PMGg zK005|GW?osu`y9NNaf3MNi<8vj`8dEdEwK2*?Tsh9c`RLG+`vTLPT*VY2!1ZsQ^95TQscrm21=!LHn_X zsLt%{>QC_$O^hETVysi`QoxCV`wB%jjUci1@Rvy6JzN{iVAB28d6W<9beY7HMkpT1 z8{mXf`+l5aVk?p+&-lCdTNKn_3&66C$88QKC4@sUU zO=*KyN&Y4MkC(KR-r>0WoLd2fVf&YY(OfTE_HEJ(UX~%3@1$9NUAYL zsfOG>K1ET4I|=D;jKLxlyN{;zP>dp|AOVdQq*}={z`ha%prM{?VNF_#Z1K|mJxqGK z8v6NE8SEDRB=UCH5iUK)awrO<_(kw~FOssy9Ps7;Fm)DwQH5Q*28L#+p@tqhq=rU7 z>Fy4x0coWhX<-QI7)rXk6s2K61f;v91f&INgfs7Ve&2b|zp$UZp1t;3_kGILzobRVGp~x$I!Ss}EZLvBnP>OXv0J^NnPTHz7(PM9)GNf@- zK`z&Bn=WXQC!@sq3>`X~>*DkUrApp`kj(e$Z-v+dnRMkRJgaFpQur zYbS@WvyxeL(uvI&=5N>zp^KBT;tXb`Zm2;sYnUDwRVwQ~oNZ7GttZ@(39B!nJ5rd= zCeVNFcDE0Y7bvORb!cJF22+2u@SV`gWhj- zO@Gn@|MCW9-^fq%n|Gz;Y>z#Am?*NreR;hF#gV*h=w0NN_5;(-_h0B2yiICPH{<~x zojdv}{&$+UEPZLWhj)=HM%40+uNirEAMa(U(;&LG?(AH{-U%=AACo8i^NY2&r-U)f zSRQ1k;!lq{C}SF!mFaER@nG&#XJ7?uJeO_A*Vb7$51DrMX=nA#cWRC>#IWkDk!M@H z7*9YBG@M;?01tLGXE_?wU8vJf+Um@W+NG6Ill2hxB)@NT&f$;1>)6#}2M322&CXK> zc|7&wn>8aK0;4ZG*Mt^H_lJ}QhI>C`%s$^Uw#5rgjRujB_*ufL)f&2Q zR*!2U2ai_PTaJifKntzAyV)S#bA{HWb7s0DY#Wt?sP1IEs)UtQ(_jaA`UC8E1||yl z)KTxU?hEK4iHQyp>t(UtDfN&1%qY6x2d5b_P1+6p;AnFnR7UIzQ}cY$Re~xm7|~GL zl$Swou9%UXZUsoEH?y~?V)6Iez=i0~ulNoA{H5gq;3Ij0kH%7{)=v*SC4pssr%3g% zdwEvO&1e@}b_@3A^r8?(o%)L^0^$e5VFbwI z*$jX(&>|k#D60uF9Y|UH);Y6NQnb_l^)WxC&!Tx!%M(xK0+E#$IcW;D7N`)FskhvG zK?yWZART2UOC?@{2&N0oxD90@qbu?GkNnc80K@C>q zf6B&Im5wujONx=P!iFLhWbY^jNEQ%U+=gX$(qAk!OzSp+o1XfC=_X^*@2KvQ_&cZ> zYz@gF(Pq#!KnZ=xJ_qzlk3LtlH5qXxG@z@*?D$?R=snmd#KX~M*f4bsU_FeJ!&h%J zN^Gd%^U{hk__q~-2b#gzvv7Tnh7^pt!XmYl!KmET_l%yNrLZJJJ`JGlH^vOO1hW{6 z)rt%b+rj&aEniK|p9GxQP+MCW+_#m&)eRpOIJ|>zby;^(J5+0dA6YGpL@MHYaJ{N3 zt0IOL)tkxSOXWr04t%w@{K1#!%A>abVXhM_)LHmm{L4|hZU84#`^~0x%Ek2s(|}J| zeFE8CB*qFAp!Q>ntisl2VQ83b9?y_6%wsGHd${mhJBj#9CpMEDF-xTiYFZ3f7&(wz zU4fh_njRlIhsQLp==kxyorb}dI5~-%qf}<*lc*~%(Lng5R;hBwK4}b;>Z>Mw?T|;| z_?7ksfpT0))D|!v53jP`48LUHtHp~UC}+?>8_-y@JgG<3rb|xKu%!tqescIyjUM-; zt3j%p^_Ker`05`p9kM&#)rh!1g@p-z`>xkq2SX)&YrC1*3Go51Y@~~N6<%pzu4GgW zixy#3gEE4#$SqV+fbkEiCpljau0J>B`h-T^38bqSQTR!2%cUWU)kUY$|K>sD>%9yX zWH7|xwb6cf(dYp(1xh+hU1A=IU`rnhkpfC9Nfmg41J}?juj;n|^Z|S>rA)imlLy5` zrT+#i6F+HUJ{$n|GzmWmtmUNUi%dzWCY{9PXsMyyIeK5upsXFV*B1Yfd)g?XWD+$A zELGX*da}8ryH6&`RE>f4pXT#@%FrTQEJ>sKBU;7?`o=r}kwA!^0lpUO@u5Qi58g7* zR+E_#Z$d@_&@(U&{gkri`mo)0(Cf_IHpq?F`LzKT+G$$`E>h%9gOu|v!Dz#%B93{; z0As!B8ZCU3$jDX_?8uYi8zIlPLkTW9J<*5Xp6BGLs*H($dy`hT9AB1!@5D}7!u#!y z0s`6z8xcW*37)U_=7aQ?WsTM4B91C2O~WgWFOI7!F253wZmXv@2u}3QP4vc}rthq; zrF}cS8~R+(ei*VkFAR(rniR78eW3_n(qJkN{}e$l|MxzOjF6xFXO0J7U&M|aTvpKL z-GNT=K7Km-3&>B?OT1Chb;IF*Z~hFBkrh-nE^9#cF((XVHFx z5X86o#X+P#T%J72F`8j6HAPr9LT^~w#L;I!QPL?iCgIk=HlO+es^qXRy1p5$1^ ziRx8bO2Q`R){JP^%*Vu=TFT)$EDDUXuvqPum=0Lz3A!XJc$w``C}m&Bdi{3kbH}fn zAKJm&^|_?BwXJUID$9Ycd~$sOvz(0NOh6FWPq)|CY~EeU{7Yl`439eQz9Em4E1o`NJ%)Z z;S0>Q&kO6*VPA|YtrkmxjRzCE&dAw1oN_4oXGrUFm)L!@XkL;B1^AjA3(W+=YWd-2U!=&US~}R)PxuTPYe&C?8Acr@xOKAKPzt@7;EP zdeE8^gP8OMqg{=o<*SO>WPz5R8l z^tjvafKg|Ey-(rDubz0a#k)N$iYTl^O0w1Xe*K8Bwo!nr8DR{F}z#C~2PEzrg+{MI`A ztD&qGZZVYNTEwqnewXfizl&5W%rv+z|6KW902_??mS;A~V^S*9hsMLx!eR04R@BC3 z?sW7Sz4p5YOvVMAGX3YWK>lG^deUh^Bpu7XuV`!nJI9EP+zgk!z8)#8G@F|YHdaI} zlsUPk%af)-ug#_)MF&EXGYri=vfkkH*!4YYYEe%So+qa3Mwgta*YRC)k9`h?`Du0IUKEW55T3k^Y3D3~b zn^|jU&S%wojt{nY{d*NYqK`QJT; zW$X(#M3s&Lgt-l)By?2CRHU?zuuCJp?VmYmoqVM4d4p|d@<_33YL*|jdi=G%X)qiG zGv<)v${d8dMIB)cvvH{?X8`TB9wJxKpjJYHi*y{)uo|gvv57_mW!iEXH+6`-PWMNx zUDqF}0FL^QtqTs+n(P~D#>hnoqMZ5k*MHXQ2C*+G6YbFs$EYAYK6Z@vu^%<9RG3LG z655^#Lo9tD5Yv&yM*5 z#?CMJ)4yf0TD|@lUQ-Zm^?0^~!h5g#x|f!?{l>?CzR|`W8&`pW|$q~E`K z>Cn^3$|MW)ZoJ2xSZl&3ib0%&T1#x7{)*<(?;cg2sw> z@$+C>!YX3+}TW4 zyy;Tp!2ycS$zibwfzzRlBwm+53`>PSwm0B11qB!n(S7~p-UuQ@tq$8F(-K7!8vz%bJK#O|bVywvD!?~3&= zj57asjx`gTvC;TP>3JPHsGNly3evSqIAJ43!Kw@6_)=g{;J?5#Yv~XCJP%-~S`K*| zkFu#B;*9Q?r}7I;^cqg|@`t8CuqkH*8$q{NAg|yhtsxx7hw>-^p?SLJPj}h*k`rco zRYvkED8Uo1?hbeqJluPhEglwY;CF;f5z-%gwr0JZo%KTXEvsnFE2+>auz9IbbGNkZ z(1DjjVxIILxikqmu%LSeL?}l|^*jKbk}LxibdOuX`3&EH6^IZ&3o;6^3kj`G^n~SO zk0TTR6{c?#BV2>Z(Q=}p5PP02n0*2-#@S@h7gK{Oy&o~=+?6jV0yQ*8nY7CNb8^@&W(3B0=qo?Kwbtg6$3 zl>4{y&A>EwE&!{@)oYh^w<3+5Jb4_B4{=MF-E?X|`=OXqTbh7kSi)yK*oJatxAK;) z_$Oe;jER|nswU5$*ztBGUd+$0&L#Kjf0Wm@gvDf&psH2HTW3|8GGnQP_b<89+*G^A zqyWa!0F+kjdiDe#vb&r6($e?ghWw?+dkcyEf5XcxFL5n({w+oSoku2;MWyF;MfY6u z&x*WjI9San;C%5>yzF>py?%ED_Jo78uh@d;Av*l+NG6(f=xFeFlm})v9)A=@Xi{GI zo!rHOeYcsKhj>?_ka!niVZ6ry7CJV(NzF3VXR$_nCUMh1V5Hj;~7!-=3rYm~t-J3O_>dyl^35Xar@*;TjE ztFln9&%s9Uu5@`^#)}HBznQ5&T|}`Q>Ao0cU4HGkrQ<(R2H6xPwar|0A0~ym5m-vT z2gNgYBJRHQNut3w4~W_onHQp`R3d(C;N+mJoT4_ zcP_c@j)3h&B62ADA2%={@*B+@^&RZU{edzK;h4}39f{ax%)8&vdB}Si`WPwy5aNC^S@ij5$URR}*MkQ~ zdE(%(p6im~7Lad|UYjZ1S~36K)nquJgJH$Te!=$s`ZUyaAsnzrES0%K6FkBEWAPEd zUl4FRX6pbevDjPdXTU3n^2??mM(ViJy>bNeoqw=Zgri$B=PbCd$A#tWn(}r`Tv|qF zQIBfp=O+*)1%CX>!(-EBg$m!+AjxS8z*PnUg+?zusj5G4?s9B8k>fIUU&*-s<-RFC z(XTvpt2u3Doij&=jtU`PT`us2HU`^od}B+RenW+AwAK80vzs*F^g-Qe(Cqo-x!a(} z-K%Xqnp4O8IgP%k8~G%`5i{4or?DXt5rNdJa16{ru+fTPm;03~<%ygtGs7mZpZbmW zNO8b1!6k$YIf3?OLlpb5T$?9TLzoXUqA>;d=e4&;2&I5;v2n*b$}P3$e`^p=sP zXob(m8ZkZM=9-jOEzq*Ru{H+aqB`NW5YIhJvbwCFxuzPoJn6w@#*+WHUatBmu0tQ7 zrt_mlJY@F3t`hX)k+N@D(~+6n-Slh!u%tfO(d%Vnl{VFjL48`R#65hU9?4E~!I(%i z{PaLm6?b*XLnC7{R4k$e8U=~M8HB{dhAKFGI%*ULGv|6PAYM47@>du%64r0NVff2L zq22X;V$`s?>}nihT2-&OXb8?a%#xOtcBvw-z0wSIUQg+;cs=FD68`419EB&#^&%Gz zmN6(^Hef!Ns6QFRgxu$jJmVBiQKV+w1%5)ru=*6X)z!5{3>+tTLPy0I9+&2{f*xOe z4EM|q2O(DjR<6*UBh805A76*wEMj6r+8SLE^0ndcvYma!>t>nCA!k5pkDlxOz>~7c zzyRqEg>O*uq{4owZ=!N%8F7h@nCOg({l$bo|1!VMn{7Wf6!R{1z~mW1Z1WW}!01J>kiq~F`ZOV7fj^R24|Dfig&vbOp7WPwbA z49f#pbZqdHQE$VTZwb@ACyn}UsU!n$p2jOx+732bG>s*XZ@mJrM_yw`fniehUoH}l z-?7W;4a*`-J3s&~?&rXI#dvDEGBbZ#Em-9A@K4!8>p8&)ifJ)CJmoQK z!+5scw*9^)#_3|#D~P!ik+h8K(7eEN)FCku*7c}=l?P;-nA6Xfj@~ot5x3-UmDb>X z%fcMfs>Y>{PFq!g(TzrUt0wumda%~auf66~H~Z~#)R^WNHKws2jSC)yeD-nE_~>5C`0Mfw zN#Q~eGVh1k*j&iz`QC^<>Q#!QoRR;6NczznJ!mqD{t~2UyG3d!dJjTEf}7tSn?}X6 zkFl~&C+pWKaJAss_x2O|C_?)53765JXEAD?A2KIolta6UwJwhk5XSeYdJE zqGTeTG*R?ZkFWauBSwxYg*$gtcA)c=EG!UPi+QkJW*ZrGJZ#ydu+7R>%XQ zT3WUoqK9XOVb$K*+jb$guP&z`ijyk)Z(L3h2CWdQlZ2jfJ4lD}prYo+dNWAmO%gm4 zB84&N=H99PwfF?%ik<(L&*KtjT-Sk7= z)Z6{NwBf0cBb4_{V~ z@uJxZ=Lr{Kz$!N|h8va3<|~`B1(W*Y)NzRd z0ac=S6XPZhyh)c<8DN*=(mlWWs^`K{W^9U#8diVqlJ(N)g%AXZ0);i6)=`jB*@nAs z2i4W7(nfrg4QwT>Z(VYISL9XcQ#lDNZ1lwY{@IC^0Av&ykBGpLOAsX*3-e#PQgc+N z+2?Q0GWZ>ejb^=aJ$jO~a^P z=76dBb4N_5+}O_QUC}(gyjB=ulU>2!O_mHQWMvL)Xq}KR1LppYmBi#F$e+Ev?6PYmDFEkK|Z_KtLXC&<(tRM3f72$sn3?Yp7 zx&D1o>bxvuX@wdvnu{;a8AcD;bRSC^EQv*pnf+HUR}NZ6HU|fMQl{f0|;-zJA|IGB9e|& za(jD^-Tp{GW)k;{oZ_g)IFHotJeIIc{(0hYpMJZqG?YgCrKWLjawbdrx&o{!;#0p6 z*lIQPCE}5iDhVW+>|lieGB=xi3DyE#7(dL&)7nNXOI6E#QvVGi_Sn zp9dG#*%^1;E7dUmKn<&Ff4|R`6fNnceB~^${89-kq*0`lKBe3Ms4g251Up7J+)pZf zh{Od4`6_h#av@SE{H1MWtu7wjF*`Y(^V8P9KGABubf_!X4vnSwcsU0AT8$YFJ|%{Kqji@7d#bYVin;%)p` zxlrww7MDHO2^$R;>4Fht?m3-gz1ara;OZ^B&9NN_4~w1#Yrd*8t17ICW&JQ^+GTQU^+GDmD0{I#r7_7KY{oe?vQ+uAf#*DMXlA}sriVPZsQ)nP;y3nD_OM;35I znYtX&Yeb{{Y@{HuZcU9ssMtMzthd?M#4L~@rSYM+p~Q02jo>N-E=jL9VdnM)17waEI z`(by7To-8D@MeBi*8@dj-Q~OOlv;Yp?bsK!S7%;DguDoCGB!KsBvbnJ(qG@&KU(Xs zTd5^zs95`jISQs5HT?YOm0o`rpY_s&Pe=d@8uZhwiSk+)hz-95-1Ij#i1gT#{GHqg zG=R(gQP@A5_&8tPef56lO^HhU^l#ve zj4kNMcengy$xE9lWfXr;*evYoJ(i>W``%G9EQAD`CUSt_<@Ek{;_GgrjeRqR!d!(E zD=iXcm@DBYV`Jld6GIAc?2vq-{J^5IqFgSg;y!)2#8yhM(`}PWPZln5D)bj!`(hZ_ zmY|~?!tP*}HTwMfLcpAmP84E>_G3uAdq>;GsK=;_(n+ti6|oY?1ss*a=dJ(u$5BBx zr9K+$Rin}_0iKKoc}R5~fTJ8q)nkKr=NgGkeDbONx0ILOlfl z;n7eEC3#1y5EvW3ct_HqwnQDZy&Ul`sof=Ov zpnn@LrxAfr-)y&!cenaHV5>1@-)rAXd9}&H&4UDKSF5D)Hcxz-)%h}5jbBIK$dh*< zT{$fcu>KIOH_}q?SiUcxXIY4GS-$_*(LkMm2Rj`-xSF=#_QMtda=+Qg>+R99By@Y+ zwjf+XwyZOwR6;Ij%c})tYW2H6`|tkc8N`0jjJIS08vlahHDqIuPKACcuwkLzVhPYs zqUI)UwuLc`xzXz`5ep1GR<$g}jLb&2PN2j7!!`w0FiZ!-HArFp%mLP9^qPxmo71wJ zB5_usf@%pO{ia(cJpPfdHVr$jPoFLb4Zg;ABIo~vCr-WKG`h*K7NWoD3%2j|y$0PT%R`b}~PFqL1FzA$xce+NIX!RgC*1WL#^g0SrO*3NTQ6Q77 z%{-8dBT($<(lxPjjgr!?51TTVptUy%Qt%9kFT{OO7)JbC z#H2I{m!uXnG`PjFT>b)mXL_Tut0M!H?LvqC{P#8jJjQ;+$-|{tmTX>kToZ4K)+oi$ zVUJm&a=Y4|=)*)i^V3Q8$4TPJhCn(cw%ssx1Ej+k1 z6&86_IF%0E^t0m>Y#@P_>VS}JRpXV67n9!5MR*aLQ?3fF-PXZD{)$Fq)S#Vwl}09N zPKg@sU!Qz=^TjE7Wqm!-YFW?#w~`qc!p2jYi&`&>eNvn!cO(D97_BXYwUs zG8usG4CrF4WERFX?<^3e0eUT$`6a53HU0}GYFWi&;?4!ZPUwSq>`#+6_kz>2x9SZQ znWwdBya063(JWZ>Vl1?G87rHxCHq*bUt8-#wVq=D;NY|O+ z-tW&#+%aRFO8ee8zNB0SEKX)qx5X4|kQ!;YUbt$OmwB;keH{Ufz|~xS(St=an0m$s6N4Z zO9pefqZU(sxwrUMC!PEWBf1xM#-Zp43^`O^RwKzC)xefjI)D*c0Cr8*zcar5*!oII za!_Vv7RlgJDKI-fU#E-nwb#aRUffCVFRSk>4Dj1cfkky87w2R9EEO!R0wEw0 zNDwAr`}>-h;Z#({bEuOp$il_z!v+9nTRb-m;Uc=~%hZB6H(|TwetJ*se~$B+%i@Yb zx|JSeyTyWAvXXNnDLzK_6ONABX5jp(sOSjsq|Ermlamc_%KI&N~k)+qwyoD z@&%h__LGlOTp&N^03kW{FDfW|u`P_CooFcaz33&22pV*ei!L3%y)P5zv%w{v%%Fcr`^3Ja@Ent%T^ze9 z;AI=UjK*D_|MJ6&qbf9JUiKg{9E#6YO+HeJ01GEsf}PYZWQmn;YQqugIZBFs#-`ZF zzDyW^#ZJSKxkPm{qwP(&mbYC7^&c!4)0aknU_1J-HL2-LxXRCy7Z&p=QY5!2aA7P$ zwzDuj{vU&tub^^y;ikNw(oz&1x5=gl%#%%=YcA98PeMITnvHSeO-7N9pHnb|h zkGAbesI>b&rD?r5m29O}>RznCzBg-)E*6OJI?mx%-@lwX`XcNk%Cw0e8>bPpwO`Fo z=UEnD$f>SEHKs34<%Va~OFls?$8HkKoxU!TaK7)lKLFSbNwHEg33B=)%(zPFz%pKK zt6{Cfn#ZkQ#F?YOhpn>9*umgN`ubuCatlaP+DQ*JKI%k50dU!~f04%y3lUI*#G>5f zL07^)mIqc(T$AS5w`iEPT9W!La+|z@>7(+keXp4D&Oyu?2z3>aZcuItC##Rn)rTmB z_&wB;KRq7XdumH$zBqMFEOz>-uY$c z8QBKI(|U+SH_2Gtz+`_6j6ro9K@Vn7RWStltqmw2|DC7&)x2`|cxV827}#_yr-ZSS z^2BLX<+@_4ODvNA=i|JeLUt}7NQRNss()p9h-++%TPqe5a{$R0R7-tw+rqCwvTYuL zfcFaJE`?$c!Oz!lbZk?#xghNAM8C&3)SX*)4v6`}dz7<01LYp_$C;!jC=5t5Cx#6+ z4F3s7B>-LN)bi)^AemV-J-P)Wfu_MkZN~7;Rq^iz_%)og?-hrZTqxP1WMiCM1^#r9 zQ${9i!vlpBd9joJ6Q6ocC2+d&@*Q@FKP#l%@8Yn*^a2$nH+mAfg{KzvGJN{}*e&>Q z1vTQ&th11fW6jk2xi4O`l<1fY_(8#Z?zDrCVZFTg5{&^3$ypsWQtU)te~5YvKmqyS zQ$LSa1kgqG9lkZ(c=X^gciei@Z|8t!mlBrv{4100*4A z|CK7`D6%1uOFyb1(J^v`+?||VB3Jh4isI&YapdeDUBY8iJKwjVGy(F3cw)X0VB+D* z*Do{koj3#2uPkoXL+=(?tgKM^oj%x>0q&?sMwc+e_UOrze5+pI7VQSX4x1gAhwVXi z_n8EVEl(4k4em26&5SZCLn@G1LH(>duf&o+7;YPd(M5uI^m-E{V?e~JQnE_A? z=(mDvU(hotGy$Gc(U8~%yj5`G-y-xvQL zT&_fmYT7748|V3_!OH4fovPRTLcD@{4XUYhZ(Lrhw)k?8Az3YDSZTp%Ym=Sf!Q#Rh zf0^)jn!z%xmL=7Z(bIsRhP#G;=Ys0;F>i}PfO=Yz-tu12KO%>C%rt7)z9hJBnwwF21SW}w4{%m=LXE(zgNsGmp?YarI0H?2>b?To6@LG{XO^J)HP$rpS;t|Ke_;a)TQW^fxllhTWeF0LfK#FKwnJz)VjPrrrE_Jt1rnl=Ok?zw0$j^FX|mSRH1 zYpBIo9+?Lfcz@1zeW2;CyQJW($7N^)cYa-_#~wWZGQaS1Z3_1d7qWT6<&Pb_`8uMZ zlXd#ythWryi!YYn25K6hayOy46W>Aidqa8EEc#pDGST_W6^Ie=h?)kA(J zP4pmg)UKBr7R>TiS-CCXLz{`}Fy}|kLOHY~5|*{;07GSo^ZlygAStum2)k8z*k5B> z6GvsXlPE+vIaSMRD=o;4wiUze-Qy*7`(CdSll}J@w|C?`*pCs&nySCYZcO(tWGVZ| z{IaFdVog6`a1BAk%wkPU_~vQf3zyN-2wDTKhf9-*+i^1W!0LM7=wNI(-m&pP@m^pb z22Xi$RcU^DG{r!G!mdy+ zFvRR@wFlUy-xNMtk{iWLyJR68Rrq zB3^!9z^L4yW?X}=*wBKiSG!H)z4OQecK>izV`T&q7Ya6)1ODp!T#0G{vryGt!JicT z?&%J=dUw*r29JF^FUInXgt!C}`OdqCXScqi_?G8~7VIxN^sh=y#crC7V^OYiFlQ=_ zTSQr@jgT8uP9qFxphS;ti^mNU`8jMfT@(emK#NEi;eWx_#8LPi!_Y>rFTem+Dgew# zJ2S7!Qc$%zT%5CJ)ucqrwujj+hk>hI^~Cbvk{M*LWcK+gJFTNth97y?zpIL}=Bhpj zQdA@O-!^09w;h&B?F5Q@RDk%w%hs~9L-TTqn9lgJvhke@+3P7F4fI}fJbkqhK z*WsV^HW497p4~AS5-^zH(z*1_SkHW1b_#qEjw>De9IuoICrK4Il1ha|+0jJ9m7fIQ zYR&TAZF$|bn3zOJnE=oBcLy=aZu|)W5}{_zr;kP`d6xD_W{2@ARib>$a4kEZq+kc_{p~IkfWL`~}dB5D< zzfTFTlucDWV$eO#mX3Pg*5QJZiB4NKff|d(YW+O9xhr!m;ffn0VFfCi6#K)%mPXWrnZT-O%5XO;JyGGH z_q_fcs-Z}q1tA;V>z37Ld+1n|7FGK-(=Q0an10f@fo!@O!BXl1IqF~QGTwHo&y#~o zF3Df8wZ}w*V&kK0!o>l6m9XQNhg501y9zv5cr-Rv5UXHrVwCXgEU7svTFhjYIoztuq(=UkR` zf>%$?U@}m&A@s8cAI!TW12~?hgxn8X{J5{#<$tgIWG*+J*|+~?*{B#Ld*8Jr?85!F zURVm7L1% zPZ8nIOcDa-hLBRSH}p5m%eVqR?}jYq{oxV*k=8(+8HYENw50o=m=t5JDY7JAx6^*3 zeyKlaEU(It#);P?;10e5zsnOB{*tNqO(Yx{eY(W~vTdxE$-1-5~EcOoz)cQER(;0-V)~#sB=MSyy2L;2LS;s~MSD|`1&=Alygy62acNzj zr~KgMZB0r8??i8p4fb1Al9`$!OyovY_aSXnA|QQN(pm$d8QS|?E~d|`bWz+X?Gm^W)FSK_!Q_ zi!hru-99?W*f7~V{Z^6WGo2WF)(oUj;t-PU0L3H5nV?b79)cZJFGLQa%w|D9dNxtV zz>GSEzd((E^!2;%pV27t=EYM~XeJ#~XICj~px?4Wh*}G8h@9C!q{>V>_)`h7NX}^jRC`Sy3^%_Sr@fTiS?eYLi%{>gX3mx|;F``;mx}hY-fr&< zufO@rj33x?#wDouUi(c6=Pu;K?Nie=d!nJy-kqd|R0+9=2mN$Qs!OZC_TWX!}{H8{EoAKIWp~V;DYG0cqP^-tTE=s!l zo}Myj?MuOZ_I?p&d{HC60~LvUofWTyV}jF)K(V_8URWMC19$T?S}t#_58*NBP%|U{ zVNP1o)!Iy{GHYlrP!vKXSkd}`+RxMoA`=eFQut3s#$-~1R`&W~VF(ECJVuZCFJqxt zIu#7tOyAZ^l(T;^SyVP*Zb#$wM>>jATsTy#uE3vyDVj7a%#bOEgeWa%I-XByhW%HD zFh&)AD&L$f{G3f3J1Cappj$?xJu6~x-&GHd(n=i735%O6Fy}qkBteUn`Ami~en)uE3F?~Ig8EJA+qKSN|CPM-pIbHYQ1<_L4}UucUN5e$oY#0k>s?;Q5RnS@zGlWy<%bAndZa z|J4F8ul|ry(IlORh&5$un%lAcM8JV>H%VmTMsNr%X-#M9-{`_A)!{r*x5eFHngN*% z+0+z=S6(H91K~7094I2CEl4&3+z&hBZkwH6X~J-5TU!FparUs9=T_MDi%fL^Milal zk`cH^SQCyuI>3`{y7$jUFPJ+x*{5=3UbcDoDFD0-+dHUjo|zJB_hPP@g*+W_|FQ&@ zQEy+zr!??P^ipJp>+&j5mh{&A^+csva`(h_oguKuOPQZi>ZgRsoJv?&pCRlWN%NBC zU3Lo(Q!cA2X^cqy!>+N2Kk<~~LNR}k#(_>1cIur8;$Nh%BW()>fsUHhEG)ga{O5@R zZ8xqr83LZsX54=q6h*2JUW|wtWRWn-2LtJ_;Y@gX6(ZjW5t38mta?K4!CJ#QwAgrS zm2yZt9ITeMuql**Q_oQ8q+fX;+s@Yk|AusnCgw%xscQs+cpQ}(78gu#p*3^?%yWSD z5QbAJ+@@fs83xfS+}A5b7ZDs=r>!aEM4NYfE#7k#x6w19A&Jb#M4D9c9q@(mC2R=G zC5&6L>eEYxL!F`A-C@epFn4z8(hZkFx71*kb>pzx@IT$mV|m$)g{8ZVJ)U0^lkGH5 zO*KloN%hJTdbjZoG#pU+a%<#!`~g|KQgj2{OIvNapiGI?W@c5qC`GqaELv6}PsF5u zQ;L+8b&58?ITZ{kZ@o%FhaUUoOZW}=KRWNYj0(B4*;^-R9bTn1BbbpWmQ(~(FNfn; zB9YCv2$RRvtATIOX>JOaFhYsgTl(!22aFgeV7@ocbcA&5_H4~65S*Y^PTZ2FrEzoV$`IAo@d;Q zyp-rbz=&kVJ~1X9o+@>>qm;ka*b##|mqe7dbP1KsId>bnBTU?q$pzjBH3RxJixgXx z4(5G~fHC2CQOTv3cavnRs(|#c>EX#zG;|&1j3C)42^1BYYe!`upx7>hDIkugsMSPt z7w4tFFp%wtEq)mMix!vskB~D5Sd`~#2oqW~tw+=nMo`tAjna8lm=;7pZoLssqCNPCtJF;(Jndnk6V+4iqs3eVubYBY`cuQbC15k(4DjY1yM}2Fh)8N_d zez#X{5&jh387~Fc4#3VlmVnZ%slOUa3dQIj%cZ&u8q5iZ`He3z;ok9HTH46QMwshT zP>HjHH(pkgjVs&41PNR*(`U>Q!~^1L4AaxFbr!Keqp=$)aUmT`eyG1 z+CqZGwlu{9iZJT6j7xVv5E#Zs`c!}F%jXXV`3j@jVLm_?+F%_>i>L26ydQN zhaG>IOozg4{?fl=3c_CLHc?wz|1{tCDLF`=N@Z1~-j;`@u&n2OEj|8Dj+`|MDNhAl z)Vs*c*;~_2&8KV5KERczD=%YgZRS z4{B#}oyE!RSpLec=SA(+%f{pNc2%p+~#Cm%Saz(990kM5$`FlZBP*%o;LNIS+o{m^B|@mW-F z{6c`tPRl78Jdza0jy%Y2Kt?3~{htk`F2%LpiMP-R?;@1=`cd?TntC^ZhICh;+_L zkLk--SV#_ptyTxsZK7#IMsxNhgUGoO=arUl@PIC8cH zd;034)FXp*L#NBb#=fuZH;Ue<#>bv-fWXTf|HKd0r_h=^9Gt|{8dLXOrkDQ@dtd$3 zX4q|u1`BS%U5XTfw^(p5P@uR4cPQ?`LxG~D6n7}aDeex%r9g3q0>xc#zBBjCJ^#X; zIlpC+$t3T)pZD3%UVE>#{3`UvAi&od@E=8Ah<*^`Pib>DYM{7uwWw87eytz3Kha+k zAf1{Z;fkD>wzKlZ;Tx_Bmt%I*gehe)BwrO$qV`p5LV!PL74Um7eewupxj4P_i*({LY&2rUoALiy*Nav94C%-Ki}_DrLZ%?%D0jfM97a)?D;Gzh}MCBEu-)|pO zRF7A8AX`khorkI2zc4d*`3;5@?k8-?C=U6n0ZvSui23hcf1 zctd-SHz|n~d?o!!4PB!?dNsE4SIBsJF$W2lT+K2PGupxrOV`I{n3u_?FiBi3r8> zXAXuF*3+Nl0zbUj~|V*WMMRA{{jj}kSiMgUd(o%C4+U+jE= z8w#8^#3IeI3;3WAV;7ze(VB&#r0qvDl5V|CDk2xJT9Fm9-W4RU07rT8Rk-i3_!v{% zwNy?5xgMUIPuU}8?v+~EBI;#rh~G8@sv^i@LmeOTllp$v<7MQ^zH^UAy!Z4-p3^bX zHG5UJ;84}m9cF+XTb*7XrvZVaSgyqKg~G79Y<6$Bd0F~Mp2X(${gla=e8F7D@+ZwW z6UiaZp(+;pZ>f<>JQHvP40+Nt3y8oj=LU&T>WYQBcW<;L&Viwu9vu zKIX#Pa6)W=P$UYD6^c0OFMiEvn{aUg9s(i74$I(wU58c063U`NLZ*2yQEeHB#Owh` zT}cBL!P0C+%>aeIN**?b?MQD1u35uqw)L3?f8q%X3f6nQXG3NH{QjE0>{ZORrV-xV z(seVk7Mup4h6#kgKB)=T*A=-ZZ0+C^&l_nmU>ziX#=9{ zv`{;YkbFrc9Za46{2VW^n}r0HQ5v?AG=gLJ7~2IZ#VtwxSlaVGiBRrCcq)-D7~4TQ zR{lM9|DReTxc=qP^El_lOTtZ(jalY+SFJ-3USDQxQ<`^BAmCHFV7zd6C+2+8M}5RAiGjenKk*b;f_ zPA-+K5z>Dc#apqT3YvE1#0ramMX!vZP=|-7}1n? zO61t?3XDC`0#JaO3)dB#`E~A%-t8~0QWywnq6e3k*9v4dkYJuM9{qMv1?zQ9GUFgb zwA^omNqY1V*HEIJ?*-qN#}_d07x-A-xffT$v}S#5x_WmtW$4oSPw3f>H-vlY&%FZ4 zaeYWq*c_^{o-%G$ZuL?W)-d)73yZ6sAU z@0A()&xkY=`T_Gq6SQ?pHuPL((eETm;rQSl(Z0P+^wx1a)yh^ZM4)F3l-X;^Y~awH zAWSqRx7Th0^nmWKNSmkez0gATPt6E_^OSAq5wj023~NC3=DoH9^%vWf--dI5zUBIz z+y4<3n=eso2(PdHHktOcC1+Bro*G$CS6F1G;{8u0sH0s4J!+!)<(1%8&v$--Vh!`Z z%`L;EsFh9!jIt}QFb2j|A>kM8kU~Dxl=y`<3tTSi(C^&PhBY*J{pQ9Fd`J8Jk}%?q7mhS9H)bG9AT6v|pyf}W(0fAQhb^Z^L5WNZ;s z*32l75_+g>C`dJ1)*_s&+iLE&DPX`zD;$JdaEj(OvUkbS-0Sn3#YH>{GaCG;KK2J< zF)r=8&xRhbf6s1A{El5hR>g@|o-!13*36cis@R#-uQ=2ciS)+n z$9>(4EM#z6W!%_-3v3v_AS`x(uSE`_szuaRmhL@wnDP=NF7x@BWZ8>W8 z!#esZG*DNWWt4*PWh(TH2rYb=y#%GrDY*}%;|0&#r%XkJZXqY~q$%2+{Py!j^0Q~Y z&fDP0v{HGdd^<;ON^9`!+Tvc;&@_NIaJ zd@aEnu~W5;cWGP(f#)BVoi6UYKtYyrr@ zFaki(dOi_zHOYm7{zQ`zSmVWqM$6)IaP)`sE724CZH6O}$$@Sd`bg-o1x%v7l2Bh- zyXH*&xuizZ>-H-D-^!o=GUji?9XXwne328h7q|AjF-J#^Zu$-QKK2+f6^0Lk6%xDjA>R$KyBqAzbVT8>I&=ktlE z=Cq_D*Pkv3whrdWRU42FwfGnon^M#+YEFgPqE3mpSck&WwnXfoGeM5(9d3R7}yP4Hb`Z>KgUNTu%L<;uRk*XT15uOR-fj3e(-{dC;Bq}4+s7&M}L&`o^f|2cAf%c??c25Ad{gh>U_TM#vp`x7;Ev# z2Tv!b#7(JE%B1z;v>Ifv?@zuJ!Hmi?d;LYoivKcOO@Ax_34+w$S6`aKQ9xjx%gA-( zGjYWuY_<||!g`z|A$=;jBUHmA~(%nw{LP z?lzi?Kxh8E(fuas??Hc}XEZk%7b~zv!%l=7Q{y9Dv!pGMi7}x3g7-H}lEcm5zB@U; zL-k*?F+#>COXzMV)BL;8}S%*}>3BDH}@hFTgv#A!-sTb}o-)Hca>852DKwz5zyq!C#F z5xfW674jj2VV|O+r+l8YkE%67Hj8S6Md)p=? zUYU&{G`ZwL7P1E$8yl--^;WE_LV$9X)*9^8TEohC*j0H^?B=E6n52+cKTMI3w8b?d z6ppHh4aPngCo5M7Z{7nm9>yLgt;%J82WWAE#Oig0af}w6Dym4E@x{W38yp=kNnsU< zS#YN|^Ft&C2ca>%qr@>cb{twv^dpv!g{M$AwK9mR&?rD_^niCWK@T1y8XEguSx3K_ zTT0a$fmApkkc!VXW~G0R^Ya8=cuv~f4!IkbLu)L1JV`tWpw8KiBnZm7El??MjFw|9 znhQ6q@4@T)D6`hEp6Oe1^GbqBGV2%>{t7>eSdvKC3*}m6KC!{<$4QOaGdRxbL0h^~ zSy^30!pL9*&0KwVH!>p(N6vPi#?X?s=hMOzV)mhkO`p$)#i@L6m^NXWehlGpAe*wl z^13n=LWn1z9EbMW9fN}{L*>;ky+g6;kwyPZvgxr&jW_+34NfZ%6l5;z3z6rK+bRf{ z`wxG$W9h}NH=gYNiqbUw%PBo7{7qTjB{9xzk{fQ*5Y*Ke6?{SFHTkFIdwqR9_jzUO zBA`H<)Gkqbg1ZhyI*n&h0iw*v8<`A8rWEz~34k_LF$61#vj4jIBv7o*Pt=#v13`gy z0R>V>Hh2P&n+(eNbbfxLlnHdB!t1K=VHE2>g%=&^+pa(TohIDLhGBc< zkX{EzPH_0G$9zvXYj~~^;glfPg{$ve;e-djn$bzqozutfR zsYOKY7Q)&4i&^>|mL%`40zFF1^MKxs1Ua-1t)aLGeiP&chZthY;et@Z8SeU=yUNVK zL8?94%cgoZA-0*Q>zhl;?Yl}+KFd4Qi+KB7NsS;ai&EnxbK4Q-h>h>g4(bh`3J9vU znn$VAl`-9Xce=Kns^rgBN1+2Z=R>;Qh!~UuWbB?O`78bc?$){SC2pfqFz%A~3oSj> zqJb=@WaTDLHBg|Bv}V-nCY;D=vzc6^nYy0^!;m%P`EtccpY{(#BB5Ig>?Vn_aLsG> z!95_K2=Hf^$9g5eeAjFgj&3fBj8%=-PwYhPe0hv9<+^|o@>`i(Zbm@|ftt!<5D zb4<>+-YfzpUF_tTd9JhJCCi`@lkhaO*RbeH`%)ZFmwb*0WFJ;fzS)#F$oR)IL2utd z*@vOK*?$85ykPiZAar+ky3!`c7=3i3DzZzLv7E$PSq1!@G1UNIyybfP(>D z=fmW~8PYUpL6VoTMz%TyU|_sz{3Bqb)(p}|k7=OpmTT@$PccJMk^I|%1x2GXQoaoY z+J%{5@)A)ji>2PIQ!4LcQ)0K_nP1I?QKS&ZH!`8b~J8#v~`Mb#eQ>zb}Tg z({E~~_@eCO9VD0!T!;k*^1Zn?P$C%>EscgB|EbgS3K$C$sTlez&?DIr%`0-Ty0Y4J zRFjEMZND*0k?Q2<Zp<M4oGwn}yiq{`_(%n@#`!&B{BzJZ9a zEK}%xxR_Xa=IF~bs@<*kepU(Z)@vDC5JfZf%UTZPUv=n9YmM&hZDelHnE9IDp zgEjVbzf}kxn@UuilrA?y&|%db-aqk6_KVe2h6VHR8CY1EujclO6P0ICHMa2h6R$?z zb1qj$bgx_NmGMoLl9crww$hY>zzifQUNTF)=%l+a*t5_w_`fQeL%tF}L*j35EM zVgeGXGHzF=hsKslelAV4E<{xhJurWNfEg_sOsUv~Q!1acvU+guUd772JC^nJ!8AcK z$Hq)-qO111DfQDuSu;pk`dj^@gr8x&T77VS$^L*A=|KQkyye4RmSxM`k; z-kX8hb9iu2=e-1BDVCKzktQ+vE1!C)8^VeVwgzo@WPf`1Bg)qP?h5JsK{#WcX0;Mo zoTmra2)K*NEnCdta2d+W!ZgN0N+|$E65cgsh4!XCa^xvGO5^8SlTyeZ6Pc#O4y}t{ zTk|;PeV<$0)JCT{Risoxjo3ZdC2W!T(~Axd;s55LriH3wW?K5gwpim`FMEuy`-so8 z-+#4EoB5IYmhblj<;cR8e`LwN-mYi_ZK=H7cIq2^1f5JD{7zFf!&!8(B)64Iq;Do+ zol*N)g>DItHJ4j#$%ZW)GGK?V|A_mr(PVB_Vg}L`8Od&=qebrznG`7diiDOX042Cq zd$UjUr82Y{CiEVNV~PddH3|j1_O19f>`3{=9@7q41cu5B5ENNRsl_3q9NN(;jb%eh z4mnf|vhNSFbp-wQEC6>`!Do}C)n4PWhx;<6X3D=#WEQb{sU3ZJAv855Rd%4-i&8=X)2x*gXma(Tc3DFW>txtp9PN@ia{mi9ZFa1ckPvsB~S0C)85xsqYd6 z=fOZM^PS3%?}tl^b9L*kgS;#>ww;(v8c7V5xTW9o85CLcP_h#3AcnJ{xQ<{9h!c}| z&nUvtCUrNkyzC=ceM$(j?Vn=Gut;NaE)t_@l@LnuPAmI>9BvXVG=aNFo&~TF8r{0` zDG`)9gy)oER9H;Wk&998-`WDx1FL7I?8Jd}en4qBQ=&O4Jut#Mylnk<;MMOeO!bN- zqCT#>ksn)khyOL_V>JO8lZ=1%9ZT~1nWhu`TxI%lIbZn7oI~G8>!kkqaNiHQn6$+P ziA9Cofq@v`0k~;sVd&zirS?s!`yii)K$8&sZM=iX`G}%!zAplOW^NAC)ooIk^?0V} zk>QLGg(?qTY|pP53rk&=aUdcRdA$u;!gxhi4rghv-vY#13pxpL^we^2tUFyJ%@`$2 z;sL6vG`9Y3dy5gin9xPS)=DT^xKyjNeXgQh&c-i+xgE4XV!({iijq@i$9Qq~+}!6l zWUv-rpV752?}=IF1Z0FO8sH*suUsf66vNW%6!ei( z@GP8$_C;ih;wR->(=9uL1tB;szsTsX+4SzCNwc2S4F+WZQg@cl4NSu1@Q&$HI$&?CO~0>7F4Bgv?ydq!_D5ty8+4dY{iQ-DT;Scz?fZ;s$s#fRCXU0bq)Z zi;cZ(iSjYdP?FdB5OczIjjBSZajC^-OcAG$__fPyw2(uaP6`(l=&ZfM8T$RwtHEoX z^{@*=y`Q_9D1*zKLgCev2BouLTJzrN6!+m?x_$d~{n-=xuakYa!2mcCiJy7 zoo%n`>5wi6rw_)HCQB(RrQ1a!_6Hv-<@?~^4x|@CLyBr9sU3|!71385$aJvZz{PLG zQ?Ux|F#Elqndio=;*oAkunEwEBv4t(#wav`X%G4k{TjWybZ(Ccc@uQ#r13T}6jPHc z7da=HOMj8yi<1b6SUVZ%`?gFqsNN#X3i!hs%qPlI*8LKWc7n=^6D)|l%cA;!*J5Z zFAzwqeXM<%C6U!+_FoEpaYsj0BP4*T7Iz!{w=Qp2P~s&fxEGhu8KEl8k*~%=1#QOR zon>)3Ruhn^MFU`g18BJcG3@lL`Tw9*8`EAVQ(8hsMmkRnXD}vGQl^hs_n#a#Hqhxh+{~VpivM+GY&~%%RUx<=R-;|DRyu=?k5*XB zyW8oVN0DhTUdj8KkH-~$sePc_olaLl@!R#P7o0*u2Uk&w+#7mAKOioP!L-5BR}nEj zELqS82`+goIY+DpA~IZ8dcV@AMgNYDc=H<+X%A1X@7>UmeThx?vB0ZxciFFuZ7|-0 z7U@{gFTLS}s6$=$NT48$a8TMiGlWm1E%>RHxq^QU_?L~g*I`{YH-^sTxUIpx>4*O- zT=FIoXllQ5bWDqjOH*BQtvM?0aIOe;pDjDh?TD3X@Utxf*Of#axsP}8O@BtMPU|#d z4*`WQY$&$iX8i5W;TSig24nt8?t%$4qD`U=b@{#TVczJ}l%h6_)?16T{s+=Fm_%x3 ze!eFj2T*{%AOGGaz;-2#q6x1+t4TZonl106F*+fghcO6*{WgwEPXG5W4{E8J0OFNG zA~K)#RVmBxXQI_j_)e_ofv>5Ct-MXU@`|vBQXZ;J9iydEBOrgnft}Yp8^*3ikm4JK z&(kF}C-5{%{9UEr zKN>-h$gsMzsNbPeXTLXzA5RmJ06?OEQijhsQeNM}G=ERMl{3Y{uLnT4XAycSx2G3Pu& zlC0W6^0HvYc~Bn;BqL$yLD2?ZxlQ~B87QTk;rF)=YZ+`#s%OJEn z_fM^AK>^iNO&1`ohe&t;eT-F;P(OkIm2&+#&*L>0APa>TM}^gi1W1 zu6qOM1O48_+{Ppe+b2r>Y8g3LC}J1XEW@B|l}7&f71;2O007rlWNp^1%Z;kd3v+7l z=uW*LIcveM_=pN^0Q?V9hYKe3L?Hcao@*O`2qKoHjSqQ+@n7$I z*1KeYOdDC3T;*A?G!1_&TLx50Yr<BJAE>e_0NieH&U?!S_ohV z%;vz(aCjhrVy0mZp%S$8Ax%RQ{%GUM2L2Hml#1xg0jTYaMNYPU(_Q#qh$UCSyTj}v z_LuFNH_fGkLqKNxTLmZKc|VzDMt6eHFZKrSfGI&O{{NIRq$=+(s0ct0cnerb5EDgg zFHN7MpPzrG2R&fCiM1sr^a+ObFC@=lZ%P9PlC%L1SPT|=-%?-;a}9W*R{IC?GbsD2 z;s(5PK+v>d1#S^p!3v`sGI1eou9VzxEORwXz*1ZN;@z%2JS4zr+++_I1bVJK5hk&BZc-RfXAcq=MP zfqK!EiNPIjqtw=k3Pu<mBfIgj zE>Ca}bhIljrz3~nx;JO7>xf~3&;pBrTzg9Sp65yFpp7uOM84oV2~XkM&1z80WBzTi z)UF^YEuOa-jVB62-!Gzgmrs@+ri_+eO*1fx+}uK1DP4GCcy61(#AKuFtt5mX&l66c zi*x*!Vk{TKZk!<1q%JE@a-jSa$tSlBr&cvEAKaCa32%2tt6^_5yW(}vw%i2aA#EYTEsj|zx7X}8R$$%&m*MdI zt&6*isw7n;32`C&5tRv4xNQ{&b~wht=LRve+n*V zw;t!rcz#?>BH#QKw6@N*KVL{}#+bNc$8wpCp8D8&w=XK!EG#qX{kXdmua-d3bav}N z6`t07_;ODVKy*iWQEM^5FeSzI_hedMn?g2j4-l4}(&|ROA6HivKLjjH%+#z8XSfX^ zaRQI9IkwQ_5KM=^KP5^5Zs1tLRLNpx*+XRTKD$pcybk@N(L?mdA-;nLN_dl0idDUL zv}r{c@|&z)wMhc`Z6sBuF-W2u_kf6*UF;CiC;St=WAwvvinBjy9YiK<)B|}lEjav& zQ3Cl_(?w~@m%8huuKg%rOt1w)+cI+$$~uHH{MEOa-*xLOP+Ilj@yhV?K^=fKw3q!L zvNpq6HVsDZ?EHJCaAt86ZxR&LO|F%JMx&y$q8fhGBlL?gjjt(Xke#v?^ntH>8mBL} zCRR~V6(uy6nfLFHct(xB?Qhjt`=3Ne25<=`VMWOY`tOr z_*>X8>yS;3%>84aHTdfT>1Yn!8sZwrt16QEME7RulQ!zm`h zKEWhNRt4h~nyO5_i3C~6BUKnIR>z3wCzbx)3ayl#V3(sJaq5I(&CBNaHj zG=h}`Tw(>%!^l z*TMMp$ncRM$dbxYTt(p1&(o0U$m;?6EDd-;L5CzeOmRu+)=^J%V>SPB*!cw^+gir*;5y-!;=biI|`3dOPCY_pW>pqP^l*on=#gM!40u%4+FKv%mIJcr|g_s<(1_#{=^1IVwnZJ33P;y-!{)L^C8(V05ScA6$ zBeoA)M=6?)`EiS`lilY#FC3&zoyC<&F@75v&kXc+na9RXeP`|~{FUCf3`V0tlHYW)K;?#Yi+JjHnRgKwjh(Lz@CQsv)QSnGctw9gV4$EWR%ki;+KbW4O@k#1NrV8AL>Hvi1aFHn!t$@6 z^i$Dz0fkm6;$%nLANi{^P*!qHZPjjfa~{ts@BuLhK|Aj->YEs5)AgOvt_jL;g!;m< zDTam_x}3GA=4pLW*mV*Y04p-VG&B%g;By^iSd$davZ{C<%OhE;6+NfoJ;Rq&WM?1J zn5HbB&hG!SW?fS+BwC8TSY@xl1JK2bu$!Z!#G@{%=j3Ae$NWB=w-hCM;l2CtYqxcx zE~Z-#vMuOnLLcXfgJql@`fUQDS^aHoRwJyD+zffn^y{6U3{&)gW zCA8={GE~F8+<#AAE0kB}14t>hQ&k4jF9DRCJElfiz?$@aoCHWu_d(64YYuj}a&JP4gu#6#q0~h?{_$ zG2z4f=S1gqoKA5SyVN)yipUw|aUs``h#4EJl?a-)LjO0kf($@RG@XvwlyW67<$79va6LgT;AEsiM$qzHDShGPom4Rt|syB?ZV+Fmj8)ypPk? zUkQ1(-ah=R2=>{kI(+3TX7y{)Nblmm8)NqG{+Sj1OtyQ{WhQ@|{KYdnY3a)U2^{hY zZRoZP&nXg@NhTuX_Ec7(;mR_02q#mDQ>P!&4VkzFIlQu@*tG5j_`(_ZLFy@KOpX9& zX=?7rz9QPyE!q~+XmBllz_L%|ePk=Ua$`cN$=gJjO5Y+qEz`D;nI?se%r8%#(<#W| z5)ogXvY(Pn87I~dgYas=oDcKk6w65ZTx1gKM-|P_BHS1}@A>k|qhk zsABj`SaWilIVm#-c zoj6OQee3dx>GNY#P6$oZ6S&RrD06Z|%WmcU%5DCy~N^rHp=wts4 z38M%1U)gr6wRK4YW#(gxlRLikE=X6CVvUA&9y&n3jF>hFUvl^7h0_QwgnyGY2Q5$a zJ^r$*j?uQm_xAo+A6`~?IaNiI(2VYw3F}iclTWmhW!ZKI*D@|meZJq+VBS!;Ju0!P*i|Dwwb`iB3 zZ(Fx;#xp%HHiaYUFXnYGgLO5{dIpu&kt5^`Zi*j+^q1r;fHDhhgosyP zhekafAt2XnKc#_35Qx#h2lYpw`nGn*RtlHNbwn86-pzPJn*FiEM1tT+kEMfOo&MU-Q1NwU!JPndm|U;qW>WmyAF7Uk+~b)*5%C zk)ml&xAxC(uX(d%DWhZ8dvN(;i-|EUVu5_$BgzEg2`n(VHl(C!JSqOMNS|T)Fm2+p zTI_DT7hLU4Ne}5p0`ChEWn~wMhYi!HRVE^L_npamA@eyAP)@T;W&26PDoCWHVWd8& z(3W&X^XU@VYSpT&O=UkPEn|WR_}-RQ_?G!MmV#H}<_qstZ_cqUgW9%J<0c;KG!Y)2H z1HtWQrc`tRr~6@@;(nL=$#jv%9{gTOX!3)xl@zwPT!2_}@i3Oyh!uN2Yvc%&Fn+8X zaD#S69EE5L+)YYWQ{h!wavYW=YlxIznha(eMD9^Y&^SZ!vm0+MXe;y;(~PKe2?@1I z_~rXGVh<^Lp}w@ZxZ~eXP8w#1^o;KD-QLO_l3-#4i~nb_PmdbB8#Y$aNd3f#V61lC z8J@J4|Cyj0=jT1PSsw|r;VugPIDB7U)qef8v)s7#x+~-g{Gr0MlR?}d*zDgTLa;mL z?Cbm|{OOsdCw|mz-#y&H0aF(-zsp{HNgx;i^PPrf`PopbSDM&sk|kqvKZXO{L2Yhn z&bcTv?F5&9X&q6ZEv*MK@K@jD3E{GOT_A^jdG>4qi{J0$i9N63l`;-e`8A5gdPILQ zt^_RXSv}$j^ZW{KQRyhDWrGx%n3SpO8mFfkY!=>aO1K%QR(gSC-7|RX{B{-kFIy= zhNj0VcK-QsG3QAwEM|jyZRe`~aBov16fua_oLOc1e1w)3qL3qr-ly6v`tkg5V7{Z} z@3vAM~i^EEbjvN^p_uJ~{t_7s%?B|gTo9lo6FHgELu(~_k z;Ok!4^`MW%i*@zp(~6C$_`|{6?Hf<~kyj>*NzTG9tD{~eGo51@jhTyq*GC=vHmhQ1 z2vULr-J5D^lm_#sC#qcYo56|5mp2RfBIA;u$VIMNVFm#8C*ijXR6OMdjh`ClxxfvL zfyX29YOoWXbS+D;KEvJN&1i&-|kQuV|7}9yKI8Dg*_PSQWW`f-W)GjdY z<%s$Y{M09BQoYw?B%IN@zvIZR29rzTIjgl^pE7-I+GkJ9toO0fZ!YkRt-{qLMmR>; zOl@7sz_z??s{Y;+srN0A;GHpO6{^TSk0Nt8A{S zCKQCPB@{>VcX(FZ^^MDQ3p6qWUoD)f8}XEJw^Qc$8-LPa*>PfEVkpOtvB=v3xwYCQKwATm_kaXcK{L! zt(X{&QC(8Q#FAUXWmiJXYUdT>o0ZN?3yEqAj834~-=Uu8*f<&o-=~nhZ2#lWd&le4 zo%g*XrWE*Mr%1ZILOuse_*|xq&O7`!9rav$`s(4NNmXYbZPusAgWa!=zNrU3Po4P= zV!<-JFOo^Tm==ycoKx9Z(cHale1iL|WW>|G^nhxb zPn=M9US|1pRnFKT&6uwGs{_(To(^^<)C(zm_HA_9=S>_k`guz2&1!^E_0@#=O7>65 ziKUY`{(BZ6Y+i`mnf>sD$K~!hZf5UsJSdPxK}FsiwdWYmk_t#eqZG&7;@OO`JTl7dD0X z;`bT;LGCr8O-;Sq73aX%2MRqeW3^yoo^N4eVNrYHSe2uO1af4HZ=H(t<|X&i>5SZ0 zWF-Cf876la<_us%jibNzlSrJWi(k($?xQV=oxR@5uA)#EJIh#WyP7lPIlmyQzRX|) zEkEr>uaQWezlME`rwhDUVO#Y(oFYfBjrvr|Mh17qe>zH^=4hEPIPZSPHs-k_Q|HpQ zYqN$+`}$VfY`@VcAV_oqk{wbt+9fkT#*y`_w0z(3Fpt`3ZwO-buM4s>`^MdR;+rQ; zHBs1vQT1F$ZPZH}+eqru5r%H?8~@Vc;^Lyt2K$3ihoIBR0u)PHU%)x=v1$V8Xge<| z$m{ATZ;?vg8C3d%qx~KO-*_+BDbOE?niuO zMX(O>gYH>4(`TIs&AMWlqC*h**K?QjytXAV)E9q#foxUf(`wDE=LUYKc8*??;HPnKmLDQ4v%bzt{zDDc65192H)6wtbF?XSIDP> z@wv*%xw%NhAlkud(!uz_!9hpIy|kR1TwY;eesfiadsAIqa-*`}As`@5v$T||lvCSV z=<@gc&6Obe0mq0+)pPd*Ep%|rwQ_{^zFTnq@rYqH@Uo&Y=%TOnX8EE-Qv7AmwEcYH zU*pU1|IK)k7o(M=F2SyY?xG(gHuZdi#7>v9CMxyLVzx*`7xI6b6 zcfK?MQRm+D-LCq3eO@8Ct6e4F-P?yU6-b&LM9DZB)>{hDljk_#@ELQH2~8VM9PbRg zoQRirx}2GiQ1K6Zx>BcY)kQ->y`^|qLCoScxGy!(JglgECO7ffFdsnlSf9`NTfHiL zuK$Rhv~7LHp!G4^VH!akRbCIav>vy(cq|9MoPXh@^I303r15n;p@4P$YU_Fa*6cw4 z`7NHu^E(B$Q*TyNzwD5hoDhZJixR|bWgEEY^xIkWzd3s2eY7wzgE;3e5B0RU9<4Nd zt=SvuZuf7facu1G4YRN~kyYc5;^;_%FG0^jHPRsDl+kS6%tVBIW zwDDi>zopLoyB_cY#sY6TVt6&`hl0F(nK=&=FDXXVOGQUjOI7oUOI8;_Uy(j9CH3=? zWV|cU;O8ufryd+px>YP|$CVa``Hn{2He7^cb+`vk=#d_lq<+U^&_Lk&P>W{_Igd$S znxt?X%javaAPd!R?*k?!B66--RCdRA{=EXpx^H3r_J_>KcO^73pHL9 zLW3X4ggQq8M@3GDm>lMh7tStc*q+aKzs+B_Pb{=Q{N~P}dAR%2_HsFJdzL-l!22$4 z<#t^sCui~e;79A4&Sz!)4rJV$-ctbz zgnE5(n%c-(MB$GUOI01+b=NGZm#u5f9b z=)Bm7zHc9%&$3zHL{vO6Jj;#y!R0dKl`oY?Yfmq3X_wNuvR(b4Vk}8rYB6YuX>*9i zn{bgge>OeA3HI`XW&M)^WvbK{rcKVe$&>p7s(inBI3Mnge|~VmK+aZwX?EIr&Z??Zd#nt+qanV^NUjo{=#m@js?D3BL+kt5NVnjZ zir#XiBdtemIB}km18VhQ%g$Qy^jdrEJUtUeCwhlTYg=w=XOY{2dN|fBUN6-sk_od+5c2 z(f!Ux`-5Wg_Ve1c{(^$v#-11W%Z#86sC#3y3ljn`Ad13%>o=*LKx7?&po~6$7ee*smgGji2xRpW+t+7Ws2N|BfD& z{j1{Qry1mjcMFRjXBOw@-)U%lQ2Q{iU3=ZH&aVz>tMaX(xA)ED%aBQU$=`1O?!Qhy z_y+3hV_*OF9ntW-b<z0NPln1*f|*sDZ+yMI_W{;0+k2+`|GWm* zL;O?74riC|z5Tca4+{!jlf zpB!^cfR@xH(|-R$0eJXN`r2x&f9Dm@629ARU31J+J97-ZcZ>O%(gHtCccGI3zcw4$TS*JUx znLaSlH&}LQi1m8s7bry6{j*>6g8=T`%epXFrJOc_M^6v{0V)E;pZBfXw5|&GiDbno{26wTG{t8zYd*G>}gLi=_rB~I) zyh-8T^nuJ6oSObDVCc9Y5R>Q|7-txoGbrV?%IM4=EcKw5K9=8`6!^C!x&heHdV_F3 zbb{o^jzk=a%I_xiTYOEo8U7LYrqaW8eVJ9??L2mqqVI74Z-3l2{a)901=PK1s2b>b zQ@!bv;atY~!{D;!Pqy`g++X(pQOL8i+I!sD%tN3|+3>#0h_0Mii^%Ae@l5sC@7JCy zU9CKFq#g5Z+A;sVD-J{*z5Tu)BrLM;oEX2l(*7(X)#KqX>##xySH)fP-Ip(=e5HOK zy%ia*xnGhbN}Zyy3rIGqab+EAf}!bHb1o|0`ewn_675eeq#|{{f8`!Rj_U+^lX5NY z+SuC200McV8)XC=;S~7rmXCLcL-8@Q#j960haWzys9=3XbK<7yY`+4y8|DA-j?ArY zN@{Gq-4Cz;;l&)wpUcR%$TNBH@SvghHg;PKb7V`#Nis{Z-IX^Ay{f$SBH7AW1ykH9 zcO)Ky6?PvqU{vQ+4rT_<>QLD#REz17BIPr&K!9R^iNyZY=g0NAYYLVg!ouOE60Lt5 z(q9kwc%}@VTdM}E!0gHp4UT#i4!3w*p}Vr7F#O=Q_v6xGdNl**{0~r|35Z#lq_bh6 zdFhcN?{zt@Q7ZHK zG%`#%Zq>!vTQfRyS9eqWF9;xY$NKd11Z7HLOYB8ZLT9E9&70msG-2OCOnRtS>Q4OB?OJ9NIaJ-Gb@sg@hh{KFg4Yoh-?ZG$ytST zBs!|SLpQf5SQMP5S!NPRzJL>e*cW{TG}EIT;Mf|*cagQkY!(|oSw4-&XT|Q=z)^LE zfe%bnN&+43>53}?yz;Ou>F*ClKUDTx%lQbafqh*NpE_tVy>PDg=0e%u@Kn)*U#!== z)w^-h20AjDUxxY&zDky1&GMogQ7CTO_No+JgJ|o zu=CaR$X!$kGNJiywZ-sH-PqH&1_f0Lr4@96yZS1Yj|o8QfM^&0gojUUWH=6qGA63K z`QG;6-!hLvf+b$3+08Z|<}90Vgm8{ZMA!1Bz7pctEUa`vCf&0MKHs6wb2@x{%B<=lrssNvzC zjS?QL6;F#ZP&np(Q#jOu-&Q^W+2@eNKK6`82Bm!qJfjt#Dk+$AHn9_XG5cOwVAtU zuF>Hc1j3<&V&#lU%Mwg^wUSUcN{`RffM2YI)qX27Mu@{w_?kGb#O(+@%ZA0Q?+Fsf zp)fyeZmDeG6&}f(7WTq0PVq>)RB48l3Jthv zwbFjQD$|77g3&X7U@AL02YCLcs7i%2no9AN8^AzdYk5VgxddFqbCUG?= zBN!bY;v(BMH}$w)^u9t8HeVt45`USdBF@)W*10|g3tlhDMCwD|ju=;Rq<@Zl>%H1p zAz$%C;kW0;Z-odApTL!)4V&`kK9d^EZr5UC*)=3dgRMJz;tllqgUhOl8@5j|DdY_~ z$L>g0xol5XYNTps7iv$^g#kAF`KGlmCdp@oQ9u@LVbr;+7@4a1q5Jcj7tL}AW9LTm zJt~8+kCwN!urYU_nABjZ!a<7x@$JO@mm5#p1{H}{wCQn3DQ^B>4gG2Qpfn(^xk0Qe zvf-`!^^Xb_-d{w)FF5m;mX=5_GQZC3Y?KV*+6G<4Y}scUPSayQyq$MAQTU(7%VLRE z&(3LA7MIDzpCQaKZzGniFyDtN)50ya5)sVYClNu2@!T{IL=tPx%#NF;Ha~V6t__W5 z2_PzfV^?`;8@3}mEVJVQFMXsGuy96=J3h*s{MKU5x$%Z9Kqoy%&PWwzlo;LRC{GsN zbxW%PXWL($eam@w$KImZov#eUw~AwT=~Te^UFFv@kgbiTWbS>2`!lyLEVp(t~X72 z4EUdUyN%h>eb0Grmot+3(f*Md9TjtnqsGyl0v9x{337v;O8+PD-%A#hE0#lK-7S|{ z-8&b7hz6jnOX>ueYNq{{@As@8a1{ zp4~q2slLG{| z!YxMQTL-7-KaXVb$(}IRPo2i5w6=@BvALdL=4lA^bV%@Dx}t9p7r~^{e^LZsy$l#$ z)c{&@#@TM8;NoBC+DKTos_0=G(%>JUL9ATCrEpJt)x@UhnEw6HWJSKw~sm8P8d2GzXPTm-s&mDa;^p%8iyFuI*2*q-793H~p19rQ3wp(x`b6-*^J!d3D zEK*pXP=G3U&DCRM+0t(n_Ng8ftf}F><9E|@DdMGU7v7z{Yv=L425DP2Vv$1>*t17myGiOVA``cO_A{mjPdYjxVvpXri@_MY!E zPLplOr-!{?2aZt~#b8Zz4y@E=N-}BUuz@Q9T$vb9JQ8NN9sV__q_^rsVAq_ad?n|l zk+#8)kwMIO7L4mP&-|Q#V!doKei3RX*u3s5ZsV7u)?dFS&|)L zU|+uz#7^!jpGOn8@dgQ*_7i?{OCk^Nee0NlITEeT57dcC<1)4+$woXobARd!uBXO8 zkfL;k-fd@t@a$(+B%mLf%)hD2GzmgmEaH?_ZtTI#@cuP5SzylwcJCyo?0lH8M%jNrx#`^$&%Nzp#{b5n*4AeLbk}BC~uMT0#g5X7+G8trZ2~;wPTAq<`yl9wezPFlrU#khCD^XWf7F|)#Fv1AA1Sxs3^7{GrT`6U5rYH@Mb-O>q9{CE}KiBVw(4K?Os5Ya2~(sg$;*{Ui2+3T#b!p`Fh1Cmi%8(BKtK=_9B<|_iXN97lM)W~(>YMw&+MLnvG`);$0f!SELV`lv?pB0 zfpZ;?X%tu50#<7qPD$Q;e>ln&2{yijWz>imyFpJawlJT(Stro!W6Ai_6On#i<9uA5 zTj#A=n3|HU*{-J7w6&*5wx5S=yyXHp z_fi9O*(+=A3aMRWNA)vguS}%Vi&?*kq$IE1(pHTw8%m(}9)riDdo~P$!#;=eD)~$i4K^*TD%6E%_4VqI12{JMa{zrH< zW`>tQzo-Lb`y`n3dx$o~!TyW8-}3IjeeGAaf-#39%J|IG9@R%&a)OP%d}8D1mJaZ$ z@_VxS%;@Za{^mtF!h`9HVrQhKw2Jn#fy)k6RZ94>ZEuVSbi{s)v}m~>cI67EorHt& zdmvgLnqdZL{O@J;4Y&U^TARw>*#6DBBr5z{ur?H*7tf@kL5Etk&YJ#2uUdWXdF0RZ zqWbqgyagonyTunJZey3JHFNUUzTip%L<>|4>rDDDYS_zyA4~Wri7?>)A?W~l6s;`p z__$bois^5OjOJVE!7!gN=fl_b7p#p~Ftl+(0U`UMGl|~lHeKn{!;4=Z+DbCfzp8o{ zpsw5WRxUn_ezZ7JX|2!c`27ER0XX5c6?GrE|B24L?BwWb^-i6f7=~YOy(E=R=H6sm zdSU{?4M_()l+U*bt7gI|j;M8)HqOxEko&%8j*k0r77)hZH#A@3EJTB3AGHd~CiSXz zkx#RwS7_s$=t_b)nV|PAOQ`;o@z;exUi5b4>F(#WuxUI+=hL5Ce-b^W5l}eSr1Qro zt=D#^e{L!UA)EO-$U#ijbJ6_;9SSD@R)!M}WXr~w9-9tS6!J64@!pmN@A6()k!Qro zxTWESdhTV2j(9`HnxGlQ|F&PMtV&yO2wvWdBLH*%CJ;J(^#7y2Ug+rISg27$*=15`5YDkybrCsU7+JN z3RA}AsIWIf7rYZ1aQ!;@%yV5{RQOJjsFJg#$fzaD$({UQY}YGYKb`i714l8GCjU04 zteM<^4}+0M6wtb1m<;q-Q#lw-MTUheGw!|}`4$_p{6idLJVt1-LqeG!H7l!3-3dXB zPGFLz)SW&DWtJh|Whn&AtU*pHChpt|T;U8@IX!|I!e3k#rr>YI#Yrkm4p<54#ka{m zhIB^dO7qsPG-1(Xk0p%KOnY`0T0+e`=go}n0kYfu^97q&;wS)RfVSwB;(@eIU&(Ev zA8TyX$L;_8Hhql&vhHa-sY9*4gkr)vTQ=AXN494NsUXiF9H4xy6KSf~l1m=fGyj3(aB$vwew$mybN0c!f}zwyg#3@%o=+n>r(dlc=4Bs z4NjT$6n4xRol^RF3i73@s60q@|1#Zo(kY+!66if4q(SR&;zTijhvLa_r;FodM<8Xi z$f0i8RD_x=p4W-FcPuC7Bvj9rYBk1J#@@8ZT2_Fd@w2!te+_Lffex6fST=9rtL<&0 zb!nA8X_D4s#)B(wowZSM8p-d3c$vGocR8v0x(L9w#Lop}ZY1j%b6{r1wCHH@dY-{T z$uJE-!bJN5J{|Y7x2tW?pa4Q3S9V2Lm=UYKu^usn^A=jpmm<@hAm=}{1Bbv4OaIzdYrWKnb*pbcCt5vd9nL+xC zqE>tKDBD~hHya`#C#C(*&O=jX;BkFJF}hqv8Hj5Aj4UGE8O->WeRA)#&-nI7i}u@7 z*JgVQa%8^I@oUIceF5ISzk<}g;%w)%_{cr1N8Pm0Lh`_Lxlvy{%-O<-`FPV~+VI{F zHQg;sG&G#0{b%cECl6r=>_G750!Ca@?#Q;4j|j4)L-;NK`J&zAL9G8>@K%` zGXHk@;*P-O?TIwq)*2Yi~$G2 zvE!&~R{&Ok;?OX?l}A?wprjuY3+?1tV}$WAd&O?U6i(@9cIlJ*jjH)wB`zCAr9Xg#kiuPT}2hV>Rdt>XN>hpkhSWm@d5V+N~eT5FVO z`A+kf=k5K9MtLc(-;%E>4AIIr!QM(Uj2(HO%*xRz&@F4MK$a=brDapKakV}>uScT8 ziAp39=vuh!8ND2UrgM&n-?aOa^TC#k1$cKog01L@z|@B`4A+ErzJ*pH5`5Bm^Ycec zb)cfkOnO+ASly^A3<~XysbgHfS_+Em;IA_UR(l>T>`=R>*Br^U_dsXEAl?Le#bS`U zTKY95)+3Di4j-<5)!j?q3uD2Mo6V;bcUoKuOc6Bl-A8y!C^_~X*iPmUPoO; zpCMfTlz|g3VFL`y2dzpzDHM))9vCZ9ZO{j60q~dH6{E)E(T|?XPVW)9IIk|Tp2d98 zMMB5aNLm2@8w`r#z5&!h^kuqM?wkBt#f^d2#S8j}EDD~HG|yEHA;~ed72<-Zhp?zd zad(@-+8fdvArpLmg#&2#PdIjr)jBj>unPq7eVSQbKD^z=p+9-JfX6}RT#0SJSr`6f zbC}a<$MYNekSo6mA{)hTgF|ZiXeq7Giz%s0;m)!TsNb;69RdJ-_t}!1zbT((5yq2X zUIqv3Sx-*!!XCo7Nhas!`xWz)%vX%Y3elh>hNyyZCjV)kvSOHcR`sbyT%6BM8%Op- zzf&J^!jJT?4mCnNY~t@^_^&-MG;3Y0MjrX=Pqhk0g|l1o`MeCB=`u;o%+91{$9?vB zePlv&tXA=BMabL~ZJTE6c>X+fYcc$xM;CE{W0)?WM2ZyU(&?GebfEt>RP~mAUIB;G zRr{h@)l2+*h5gK7UVh@nYlOc`OfG19NBu8AoJ=x<)&bo(LJE&4De3LdEfyV#f0kK1 zm&2LNNnIL-bj`dG<`_&Sv#*z{>lmX<1>2uTCiPeV&FP!e;08|90Z@ohy%t1!zR-FI7K9aC#HZcEP7i2^# z7@3Z%Q%3}>4&AKf~vB5(#wK)8Io-KQGDS^RkJ_B+}NIny9a~OX- zG+b#_yL1V=b47ouYu$~Vp8DZ;Md0OIv{eNnnLy+Gy8HIS zt9>Oirs%r$(?nf3$n7%%6^noHX{G_Q3=UTylZ9f`AXEY8w^>G_F;<_2o4@5vQ#iqUnm!#0Y1CbvXyxb63V^U4v=t z!|Vswwj%sYhh}uwibtfh9{tB>27clm!6D|kk5MQ(&#wIV%jR+Ea;V~>GP5h1=L@_X zQpaU~Mf9Ev88+RFN+&}eTO1lC|K^7m-T15pZDc|Uhks;wTnw&llk$=7VX$uhCiy<& z5Y>L?b%09yT+KI@P)Rx$gor*A@3+R0D+pw}WYly_7l|Lfhyag(<(rY7MXzS0 z5MaZLS<<~7$UzIE1IYvy%9`F)I2sx;v-lEkOCBFFH4_8|EjIaNQU6Pl?~G!ShIlL!h`^#>fJ$I+GSaDizXu?x`5?y8!TM&1Cp-yn$(`J^&d4 z_2%v9aPC`hb%lgQHKiTT69}^Ijo=gRduZhjbdI1DBaC}^xax4p@s&aN0pN~3*(o20 zQyW^6kK~P@Q&C82f~~3p%nxl&0q*O5Uw5Vy6WMw+=2MZc(ga~yC1FG*v2dBkr#Jhs z=MtP;Iq4bs@J;xUMEGoJ$km;*8uIW!V?y86Q_M->M(C94!N)-FoRK}Rj~^G)w1HhR zzc>fpqn0E%twSaEb!^lSviUrw7B|0i4+cswq|o(7hROUoDD>Q*N;+>1!WBZsaDm$j zbpA_G(kiGG@r)?gm~Be35RHprEsTTQGhi$^ohhi6D1yjJg*7(%_@*(+jkK3tEQ7|) zrZc;Mxl_i1K64~8j>azMvQ5d_JKq)}M_+fmR#m?l#7iI#DIXlxw@Hc^TlOs%*K*?U zUG0KTzQ3>Hjd7wiIR8FQ-oFP^%}0!Ge_9v*7!I)DYF7T|F@$>uzT18?(%MbRU9X$7 zH7a&3ho(*Q#G@g<@*WB=vvKdVC>K-WlRU(;ZY+Vxsh=|za?KeHCwxflTlq_LNd3!x zNLvIj`w1SfVnV7ejyx$GlHe?uc3Tc!lS9HA*#JZdcjG6^$R5%b%i+eVc7NiYP8a;o z`^4MjrlzkyKq3y|&K7Fg1^pyt6#>&6bWU@QWJ>@Suc6-~4OhYdByIgnBS_|BcQiW5 z{LpBN|Kzo*wI3>!wjh{!rFK(4mYi#pslx(8T6+u7r*k^OZDJ!~XI>AsKNVi?o_8Dy zG~(zRlB^SQoSH6~(kXqtl9OVN*iR9CT##g(v%^9%+dOdpWh;UJql=R^dE)e(ZbD+f zfP(5qR=%RGpWcvHnmASvkt`uP`Kt@H^hDwHPou* zF{jVT_N1VSvr=sBiH$53?K_Z9<;;5m;Y#bcC2oP35}2X3`92eT;qaR%---(Mdzdm z{W)7mEK6IDXe%7~@E?VGQohkbI|ClHeu8(d))lpsrq1zLe!D{8pxYzqDqda!U=A*3|X~l)7CjT9!8~OuQ`T>r;vy0{qLz??tzI8jWdfMs=DqHePxB zXZilKnXb6C+9Jj-0<_RBtblqBTZ;lc5$$UHLy}3F?Qr(aJ6&L7N0&-iDWyc6NOKj1 zaoouvuT3tfu2^88c4L~+q6=}43yMA4%w`|Ke3=L1ygrfYF^V|c_u1tk9PI(T{qFwn z1F@VykD`vi5~XtoT|9{JBvY+YE(g(k28(Hq+($A(FJJc5&fK$`Xlxe7^q z$B+l~tV0SV5|azJ#QAl&1c921F~IA1vY0T70vBr7QSAJ+#8o(7A69;XZeY69UP`x^ zFQ?v5+Q56jzJMcnFM_{bXv3-&cJzVxr)MMkm1^XKDsmL3Arc`hkx-S<1;iVCbj%ri zH)tS{y1JMmU)?FNma^UQNvBGO#h!TH63lZT7QB6TQ0b%!j)t+o#V_NfT9fxvglw_~ z5gw9vO`k}St`g^i!USWv>iMApYa0b}&4G(UtM=eEVvYb0;ydOGe-a{T zAMXdxC!l8X`EC>gUalpvTR^iqhn1=e3^*aALXwj>_GJZYZ?BfopbEaBbMOzhSnhd! zXB?c__#>q7VQ@@gdH1W)7Vb>!5AJ&qb*T+c4sZb1CXRHVXrIUJGIe-SYVob4S2#@% zt{^;C8~=Nxs$=h(n}pGVd`2~P^FZ5;x;3X4s`Yi0wvS8yV_b3gzu7c zKK`Tw$&+6?D)@!GX*`jlQ38wggI4(Z4b+Hm;^zazV?$PC6`EC&xo>*c5&v~$RIa6K z!hjP;y@<*TPrUo}(NE{ds;sQLL9{5|AFCV&9H_?bqSR;RSIrY=YMb~{@6DT3D~@wW zj7Gc0om4fakF%M=xPZti=;lySpzH|?Y@HpK6Jo*Q{r1Y^^1^S@i*UXo(Jk8-kqKv+ z8XyQx%%mxo!ZGhD^mgI#2bby67J61H&rqVjJV{<5nJ;lZjWErGDlk;M!IAEMx?+(j z+N%^LJPy+H+dSL(^J%F<-U~B0%jsY&D&;4@NtO`77aNy4;2J*)a*tk#QUNfYGoms; z!7{-jk_C6VBOGEruJ(% z?CA>-(>ZU8UE5|kAvRt$x+USqOBb9oYZN%BvD%F>(}EpFMjYjA?ABO#5h_?x<}low zf%SoZjqic&$_<5eM%g9MLCk+_pQHo?@B`)mn@dJlnQHSFV&OhWlO!`EIQH= zr3NOY+#O&?c$YtI@L^31tAjc=&5jl%AMoyGccq4~BOzck=~K-vN6K$13z9+F)@FnO zHe@9SVIbxG06u}?Fx7O8)B*d54Jn!FS#qLUX`xQHFZxVNKzX$S?3N%s&Sv8dsra91%K(0;ilwqx<0mWF#MV89>0=SfuuS?>)4mQ-AW+F|jY< zn^}V~C#kl=@M}vaL-tTzBJMgJn@rZvGnJEgkMa*~U5> z3Rx1k^zmhg8@7qpP?_#3=>-b{Xz|)NCofwe!+v~JU^jK{Mb)pLF`-=96R;RFuP1#! zsCNlpu20|^0I2sDDR2Qce#dMp0?qS4-F;%i#NwH5r#! zC<5SpQAtkTClYii95B3eFED1J;#mC+*sPV=O&|;$vZjh0%rs zzkTS%Q`mo)yGI4K7lmf7{*-}u3$%UfiayEV7su)^EQEon?LJ|uVabR^g7;hM*~<-intU&-8d*6K=4GnR zxF?|wI|2P^m8mwX^BHOu$&7cOCRF}Zb7vvhJaz~w8{GY-xFfmiB+d+Cx?01>uZ34K z6_%M@#(*`=?~(ZWty~QXT4_)VX!=bnLD6BDu%pg!^~n7RCe%dfnpUP71JzqVw#Bq{ z{1z^wk{6pNBmSB0rUIZ9P#cxLLqGNdBY_|6sqt;=p2hZ)#TXJ0YL51-;=6wO(#Hp>nukjbmrNv{D zW`I|Bzb+785v>*EwxQxz;Z-10)UU{EMO7HW!H(e^uxuwchKXXBj50K{0D3_u&EZ@j zQx=IZ=l7k=q_PVNQifAhH`UWDnsY(P8}%_(7*X-Ky9H=gLa@kMEd&@>^H}Ly-)$4{ zqNYD%Ci!e0xoekT;}mdG7iUmpo3cw? z$Tsu4f;qd_^Dmq`*#8)5!WdtZ8q~Mi4{`h~o*`kbvi6}p2oZ+^1!vQx`lnf=vwYoa#ne!)$H&sFHUkqMH zPnj-ByDE^4lB5iv9}KrBH$-1RY3A1I60+Y4ZCk(jY245l1#h_k%bH323p2JeyAX{G z&g$(xlb4k(LV&X{Ny70%{15|pIFatF#_x3wt6H80u1r-_k0t^PolOZLy|j0HF&sNo z=X-y?&ydO!FzriUFsogskoL@8tspD<(SfgYz1*|+CYd8$dcP0nTb9*OlIfn|L#eX98>>V6Jwc!8h^rmVBaR{bH4DDbb)3Q#|Jr5ym!gMa;`#vr ztS@tSKBNsjcra}J5*8y%o3nhQ%~|v+uDf1W-YXr2@%kc!ubFh+^j{qU=SQRP5&}Tf zFaE0c{C{8L$sNp}AQ7r9+6XX18f97Lz_zL~MJ@f~Y+cjDpP15b7^G-q{gX;5Iad!- zKL>w?r!D%P(sp&%SJO*Yg=?Y3k=B)d%~2L|#L0Msv#aHh&>K9wV%O)nhoB5s!344? zh$}9Ba5YWXLq#?(EbSmDmgb|3=ADPnwFG)7zCK9N;Cg}13C=$`(t8(==ptYAtjwn^ z+s*u+WjiHgF`jI&ClQi7Y_dXI%M^BfthJVqLgo-1{U91D-L8{)V5H#FbS3>!&=-um zGEIZKnj=?i5OE;B+9b8csxpIFm6vn($QEE>)-M*mc2VvBdI7qwPdkyCzor$K<|FuM zhtBz&upgl!aF=ubFHF%TZ2Aj5RptYQq>w+dnlL1MCd-XiPRLeLQDvsv0Kf0OvGvMr zdhVmKJ2Z&cnj`6G^vyHa!goG5Gx9kC*{MLo4LqW2htMasf^c$dye<|r%k#g6O;+h` z=(%jojm+%jzW#@2EZHG+DgkOZ;p+JgXO!VoV!HHGDNzLsg@Vg@x{wuBHLiaN83B;k zrgv?Z03S7^gebA4`q(GU_>{YXaQSG`)BKi!gbTNHzeip-X{kYKWgYc5 zCxx&s+{g&Qa#8E1KjCIB>Qn$wx@GDnFlOTFOFc`4hD(N1^d6e09mzW|a&Qo=ikvv91C3o0JS@H1BzILDYr@n=jFV#A$d)Jsy(BW$j=umT+2PIGG8;Nda zB*HK}ee8LYsNYA5$yqk+=#Y56xRFi!g3qW%5_pG0B$mr>(Z9Fz9LWjg^MNE^m?uvw zK?6}aY0S0;s`I#%NpJYiJ5IqWE*JTz-nr6I#(zr}*r|1ZTPMV76mbOr5Rwl$PJ!*n zaJ*&wL^1c1Lo?ryZ%Mssk=_Bf-Gj|iCFy=FnI_HVO3tr1jD^@fKzU_i%TuI;i))JZ zhlbHpuQYvS<0O};sN3&*vraA+<{h{j`f^h7s?~qM^){q3)j%mX25O}3h1`(;<#HZ7 zDMo0aXd;10@WsbZl*TkH>m9k56Q5<@w6G3yh@R2n_U-m@9^5dsGG15+CqA>E)Txgy zKE;^j<}y6Gz|Z((HE#4TE`dXWv1lefm~H~v6)w=`v;oBFidY?*dd$K>585;5uc4md z`2?wS%G*-~{QOtzC7=(EesIA}L-cr?RY2~Yt&@u}9`i@FA=|5!^(&CDU?SykTBXI|^h2h39-X51WCVNFYsrVEa)j*@j1+YVlY?epDMV1D!XH!^QS zM-!+E2F%tjIvG&`g1(Ue6laU}{LsD#tl>E$$%QqWpBj2q)|yIINny&o?$f2_dTEq& zkwUwlh4SdylZ^`>n-j=Qi;Q3HT^3%zc@CU3y>{E;CzJjs9DG`OegAa(e9BcqCwFVH zHJOxFHY4T5rBGYX`BF(nFD4x^J%nN6w%NSAQx_x zf1`+3RkD+u`84QI-RtH5=ExVW!G4xIuB}$W6>j1Da@?|`$x0?~`=*8(ohkH3<8Uv} z;S~JHfwZT*@n$#R(KJMnif1)?$ROr>V`qhTg{5(ErnI~n*8SkG#AuL~WP*`{ivVc+ zfK*+*p-46o%AM_e?igtdLLaSqlLq?Z7tLCYFZa+}!OetWYVDoA)ge=}m6cbYznR@N z^UzL-m$U4xteh>vz}38rr{RUn4Px^a5k4$ok}4undB(p39{j9NT0ZRIiUMavfByiw zt0!@+M7#OCtxUVb!mHrin~%^gP5OfLIi-v+%@fr>MI4t^$K{Aop~W*cBIcRJMhvdp zOV*eZn7LM@nY5~rf9nTJk$J>c_OI+~{9}~CoMT^Ub;M|+Uh~?i3slwDr#)?{C0X8K zlXMeAg&K@T)49W!BGg8uLODr4?2_&YA3JKUcJJ?cGAXamzT^EBD>FKEu`hDaM=;*$ z>v6ysy=;ujrk`Aa-oZ`3PxDELO*gJ+Mrv1nC9!~L<}cvqGE-Yjb3?nUo|e;^*?-3t zkIBP=7jRuqHzrnHn4WFB^d29qiuCnglOL3@aW+eoZ*h;)ygIbX(q(^WFUwt$9&JCm z($r=uJ=CC5Ocb`LJ-?TtTq&|_5o*UYiFtTH2j-?2{sVHSM|%81n3x%;tXQle6{2PU zx<0ogfBCZDiiV=wE2gTs7oYkv5|`C>Y<8{gP~$|$6`T{v+cbb5#BRw>r7GF#vV@nR zuR_3KiF0blpE}8`aHPZO}s@k?0q&a4J0u1X#<*XP+^>ITMDWmXc z&5ZJXb%aH6)}Zc2VF#}&@GW*=qk3ytoPg<31lL#5`tN};{Z$ilmis$_Xxp(a*VZR45qFK&Oji%5s# zlCW^REB>T#OVJrX^=9uu-_I{w>mb7YB=o7=z!7-Ocjy6Yp6#r!fSFfEwK^2sCx3if zXqiSQz5Zullil(ufBf!d31_kk)Kg+NpmXo%ag~=)fWrLxT;LjobxXHpP~RgUaweUFhhg)FdzOAz`I-A-wrvJoX3#KvJ8F=X%>K*5y zO%ES@$L6W~G2D*+ub9FRV+OJ0s}h#RaSLBuI`kvy&7p^nUo)6-eoF zWS|-FEYE!Rk=T-?+~?K8h6CZ_G%w3~0KaK&TPQX)yFClt6Q$E}3UIYJE4+ANfO`7+ z?iYTtx9Y+CI=ciZ;b#zgDd#3H(wnL8o9npUzjH?F!C0k{kfZGZ-@n~;FT&)(d(&*p z9=w%w;8~;vAQJtFjG3Hq1O_pyh!uO((1l)u@mykqi+ekVIwxz>Vp3mF>CR45$RI)D zicjSCX}#QxiNCwh!VgTy4)I?>90DKh_KI<86%~F`K0jA!QM&JRcf=k?2GwH>ojDm2`?0jkM;>YlAyxPet&i;U0}n5rbLt94U8jiv$6_Y<@b0TX{d zn!M1@uHL8%zV!6QwDN{3c%?u-2n#FeO>L$)GTExGdB&wQzAb(C?y$N^H$5x}n)X3p zD#cahPnz%!Ykqp2bY%*PNi{^(pa6dXz1ez>Te+$MI(tAe+8&Rq9 z@@HEFxMOU+XUM-j5DF?bBL-(B8L+aF24jk!PU4N&^RKFfG0kl99uQvT2m47>BpF#l zhGn9J4|!{e^sD~~K^kfXYX2FuXCHuj@k}R0%o09BEjT?ilv`d_7m?FPvZqg4uft4? z*C~yj1WWx?m`}~sW_q#1jl;l~_+B6+!81Z8SW#F&z|m68iX($lgbIpInKwS(?q52p8rziYRzpP$-=OS;e(f6W2@8`C7Z{b~MLT~(DdC)T*fxGQ(B&+Ij z4f_$jKZ*Yz0AfL%zHzNHsVj!tsl~uFz=T9>7e59~__vKB(XC{n5yf3V1DOCEgqoNV znhJ9auydd>^psSv#cUFa#HZ*V4L;S~gq5b;tL76#1}<@v`ITcFhFmHLP>eoOxiN*J zYy{!F3Q7+747WD!ruZI0O)-#AE=F(bQW#9=x}m*-R293C}|KJXGolV&U%3chzJW^HAIM^cuI>3 zuf7=L(lnG1PTU9}k#vNe12AY8Rg9QOAh^_lAK(IjW!94h6c!I_7h8wwEs!8>C!+5N z^Xo6~*A#Mpz!Xxl5EB8#<|t80#uI`Z=|iGOXCJ<-R48~5B1U-_Lt=Ej6Ui&)=!{2; zA*z_dz4W~;Nm>pxroS>E2B}v-;Vx=~>szA9EW?7D31Sp|M47#t!%%8}_N58=t;rXi zXW*h|;GP!}i&+JWp-__n{Ky#+j6z9$#H*11T#ZqI+>4E(^`f6AYO7F=5+964#GFzf z#ziQe2qZ;_fgli#XYOQR2$m8U!*8Gth+trfi2+a&i3=~&_#R0HfMNY(BylvAW~1-` zEijA_Ir`QMG44r%Q(}cq>WxFU8mI_LB#eVp%T{{B!Cb(Yow2Teyr&4t%jve+MM;)k0hEirR7yUiU8&236D6*I(LW~|I@WdvH zQNkhGf4M*l?A4;m3CTy{f|#Z1X8X2PzVeBl>41NZ#$PPLf!RqyY|nTy&>v`T}qw-#A} z7hoyTOsUtZ2P!1W7r`YkkEoWd6~PE5!`fGk)v{5pO;98Y!K2+@21+Q&5>XeXR0Ra4 zw^uSFDG0~`Rj_>62urC5G2&F2<;eMz+)0E1$%y_7U$$=oF(JW7UW6F5B)L~>1Ex?@ z$3mqTEF~j;zsWsNl78HOCoy;lZKd`2(t~Vll30KkKqzgz@V;~X%+$&;C5F99r zxs%vGk{I39yb|TV`4q3{C^s1~2#!axA0(z##R#WNvXe2wG@BD*z#KecJ){f}(o51~ zeV@TFWEa>Xk|ZkrMKcz#!x&|p)@eY@xUN8#)M%Dcc>JJhS9y7p!I-*2(P^Do%miLK z`O+_L2F4)f{ryV^S)p_Usiun>@`j?XwW6$wV3QKdENI!30Wk!VlwwX`PnefX=qn2l z2U8#nyalrcyN18|x|P5jTrs8|flru6>_HGJDlA0f3p%6L5CkEfvkSNiK*M%;w}V2( zK0z3dQaqCCF^QFwuCr9HCQ@e~m4^wr;~sxlR~uy;tguDSKwoE<&9o^L!4(C@;Ls8Y zm8_={d8grLG7>_zlCLRBMOq{F=(er`WC;ADUFF_lTuk;TUEJ3!Z#8je;N9Qdxdcn8 zebv7GWCvAj69Yx}<6+6vHU0V%v%l$W$;Ofl2TJ!7#y!hEzb1TQv7k-;R(T z%3I;S*7r_mZxfx9)M6G2o)}PoXK*QSjfR$B8sJ72q!bKnfr=#oduV3lS_gt^Gl4N= zVogm(8YeutqI!(QWQe(_uUXz`;?4jNBa4}`;kAu~j3{Q<23qm7tAhx*AepD zWfyAgCcM`GNR7*I)b}!LcB6s@h6Mb=Ohug5k$A0f6Wl|(V9*?i0bwN}?^vT3!V(lF zd6e8zr<4@N1`N2Oi>7e4mjf-E z+UU(TZyqWWad^Ow@a4d88zGi26eCCsK542^X&}{HU(<-n6y8FKPyanD8j=+qjfqHHs_{THjfZ>lcWzml8%266zp{J#+<0AuAzZ zDEEeu#NT-gCH}@I!wBM1Mo=84QWd2SWC>6Y?29r>Qfg#rI8k}GSOy%UC5$A^CQKog zFj2dvKZ7vB4dM+ZmacN##Zko<8WCnz$T<;9V|^LZk?@BRm<+_=1OsB=G+mSfk3yO# z*<^SI#6(mMpCf;2vaCokMuRBZAuyn%Ot zFpvTuhD0PfEK#2-WELTYWehDLPg2IfI<|5Zg!ar=sZm^EkK zSZa|2JTC-~^bMQP(>5F>Gw z5EH?8Tx!ZA=M2z(a9}kwZ68g8%!X24LwN@NpEK~A+gHrhX}#vnH>ek5Nn3%0#Yydh zHpCc>rfadD2*qR7MyC@3)-;n0yfZ{C!OZNLHG&J45{s5Q*h)YSHV_yS(u%$5Ei1zi zVswqy8w+PLBtyuEfE7T;_9aR-0E+A;b_b6Tu%J3d*RVBM;}$x#DHcO@yKZX#a=KfWg|>8Ahd@(bU&7}(AzWB#aJFEXaelBY22UfibGkmJh?Eg%2rV>_(8Kjc z)!{KMCTCjzKfhl2%{&8d-M*^`F`I1#(h)R<4rf3Nz2$NAMx?K41bD1j*iwwLen^ZU z6BH&1q7*%d3cgT}a0US-+8^3Fb(0fBluu=`hG$!dfvxn?@Kpub4%Fx=0E^kyk`jH( ztY}3Y8nGpW60{&h(hoKchyjK|#UY2FbC@y>WKcJwBMUKLqbib_kYVGY2M=pN6+(-_ zf&%~pWH6K1BZy`*1y492h7&bL20BBg1S+sXFDL0~QmeCRuvp9?XIkeKlxN^uX5g)R zpGgq&^c!DTfO2qfu&V)Kql=D1)N(?BF{BNM!Nbh3;x|e=u@KRGA9)Q4MfWyEiE?1uZ765D*54QINsCU4$6m#UV`sc|x!8 zJVYFyR+Lc70jnsiA=RA{m1%?|kcYZjM8$|U4c75gi@5>8Sajl_^&!k32Xp!<;t43i zW(br4V$fy`T5f5%UOy87%3z^!!PR{jjm0#`T)X#MzFzt5JOeL2_RM^}){CCrVn?%X zs={?Qxm>#s&olI%cs7I#u)r>80WvH~5MyYFgyab8Esd&8f(~k_L?g)>dV}RLE@f#? z1h&~I#EfMtG?479^kdl;3snVqfg<2^24Z*y#w6a5>?A3M5Ce^oOcW6&o?~RyBapPV z4TonMs?}^`76=!izQdHDqPMIW5xxOaQo`XP48KW&^bPdIzM-NLOAJqYoV^wu?W?D% z&LB_Y+p3GqCU#mfQcYvry}3MiUORaPE@}o|eC6f2Ld=>STP!_EdE13T41xDFYD)#< zXlh27Z$OM|p4C}P5~Oz0obbCqVJJxji_vo}4M5e^XmZ6G>Whj|j$tJs!0`mcg!P0? z)M+p=odDE%17adGO7?*fr9V1`wW)MRjaoKBjNWR4g3*z!c?DbO5Nl%g$ll9N&%%pIc)NP8H@}G@}vsQ6n-e>~Pz>B|nc@YqEa?RQ;#E<|mQC^c0w?@TU1%W|(YG42Zhu)Iwx5W|jWI*IQK&H?g7>NOZy-<)U|#{wr4 z74jfp4T<5n$rHqInh+Q>3L1mL1iDdCV#J~mBcc=umko3vAoPxgvyV^U?@qq-JOdXo z126tDAZE(^wOf`FLb7lnUM2grbsV;JA_;`(F{CZSEPA062F;;k^kXH3Cn-gb5SNC0 z(P&XB`nNG)F7O$&6L0~DX=x#!X}009Y#6@mP%CNL;121;tVrGNHku@=N6k9i z;~W4S5Ro3oJ&$!XPH5X7<(B%ueDdlC4z8cCoseo0>~*@XpbNPV~<6@ zB&{JG%ZdD`>nQJ9S`Wt-yoQiHy1$7`;0Sxfvo3={hJnfugr{4Hw@6s37a~T8((C1D zuqL3Tq~xYBmj+aPYpv9v?+cGSfN9!*2?fO4MF^nWM0R|*_QI#R_I(n#}&)^ShfG%0)f&HS{1{aAM zG{n=u%p7IF9>?qi%T`JYd*($+N~$f#w4&R=py%qr4%rI4>BS102)_Esb$>~`JSXl64XSQB9zCt6v}cH!;Oi$} z{EV_78v zzJ&*@pEh)*Gc^FYrnm?)ya6`-PWY~Y7--UYh8pp}$Nk zVAp6nvG!3~?DT}gn|#d~wwE+n9Q*)56la=DiXb={S%%kzAqNCU65}8bb26qHL@Cs1 z(;(*voP-hvtcA5EQUXDBg@Fp~uI-~NCPU1`UOxHizkLRl{o;Xum^J&39`8YWp)M6; zu%qn@B4bEXqAv*XCIsPPgTP`a1w&FIMfzvsCAvn4(I0J4jDBlGnQ$3V8P0{tT|i7^ z0AMBwGT=gmwh)M-bQ-M1(!3f+6)gP79w-5VKo4yspoE_GVvM#@Q4SG*Sn#llA667* zfFocE9ED$8OO&MYVZ_2<8yPyNBE!Rg9Wt$WP#+j%5U|cHdf1ZXfT@H>DQfsyJ0`3o zvM~qfZ^>~Z2&cmEAWBCZeXJBH_z%TAtCySZ?=DF<_x;2F$dRn)& z^(>|TP*aoP_k_i$cS<5Olp3R0Q!3sI#8}xOS}KJP2K6HFg{>)=AW&d_DE|f-35W@= zPIAr!kqBmi2HY&i09`C1&Tv&T_#F6D-ZE8Tr%th0+M`iJ8O|`ak`*M%@Oj+SRB`}S zXqrpb5;gm1Xeq_PYQpK%*C&HXRVw&^nvLyrsUU1N0UoUwxi|Z=ZqNpS>#}<}VxP4N_f&z!-{A4YpF?sV&N^;Phe1>Ut^D z3yrTRJW5H62|*^RIz-)=U@IzU4Slodyh$G-l zEPU~Ucz$l6KzfnkDmapjvMrygJF9Hx(a={Xe&5hvwOS+; zXu3qYU@Ju@kRiVZ?4=b#NQ=H{L=@fhPMUFtFU*sGeM`8uHeLSt_Dd1?r5|$EB(n;PDcm`48xz%s1 zNNgh%-a;l;4rV*$Y*41Z{2!|(P1^K=+=*it2P5Wj3s~y*D%1~;8A=aix%bp0J^)^blH8ZTZ1=4zm+6h7#iRDo~4#mXw|wkE!B0W+-KdneYoJPr$d$z+=xW zPb_BhQ8JVa?KO{}ixLQ}6v4xiVD(}{2r23Y?y&_DXv4MF`S1-#g}tKkGC#PWkM*M?SN+->v72)^t{OhRg*07UGG+(g&} zQZEQo({kp}q)9ud!*CN8SlD0ej3_!Zorth0@*vb15rpi7RP9_l%;Y3)Ibvr6$Fx%c z=b%Al>Lg%FL7e6S?NfxdtM;A@jDd@J06}adiALa}@q(?}M-8P6G2iz6%I{D38F=jF zfSC5DH*Y7-&OXpois@$EQ8Xq>QnFZ^M?U-L;AaOvIr!NppYZ$1dq(#PF*vTT3#6f^ z(wx%9p%#N-V?=Wk^9OsYKRQCGP8U4}5p)7F!>^#A90Ele`R9=%pB@2ZI-7CZU`Dah zKdBR9G*%E{=xI-CV$Jm{K$y9&Cwjz=^r4&S1RvpviY)@NW(}eX2m9xuLx;9w2^nb@ z^vFYkD707N>TE{MuzeevJx*h_f=8}XL@rG)*%RvUVWZRQd+GCvD#NPG+4u-N+AK7%soo_lhe@%?J z?d_W;od97H#6-M}B`&wJpF?{><3WVs5Jbgjh)Is>DhzP3>?cD*si9#roA2$!KMnQ3 z*x|I;nwsHsTjD~6m|kkk;FRYX!jn3Xu{eTEZS5|uanmu*pFlq$hK`uw8CNW(LsN#B zZ~0c`xAP2)%>XP$h*<)QG3-vC5@ln!rD%)^O2hT2pWim_fBE+}nl~7sy)1uLrs^m( zV4$$~>py(x0KCN@xW2Prx50AlB#k8Maq6oY8af7KOxhJzm^f+blA$Au*s1a!mbCv@-;0PM$*4ZH>cX9~(V-=)mVd^c;4oIxBX}5( z_?^CSj4W=`2$XvTF*u75LzWQ{!TOT0hd`cY@ZeL9_$u))WGld8tT00cqe$X0bypMo z+fZL^^e+{JJr7MTwnRlD9ce&QY0@dd+B{`2%&*KCYUC-x7Lm(bAZuJJODH18Y(nMG$# ze^PrDT_w$FYKhj2Ld={!V$_bI>syEumcdL0Vp3N~fPqJLW)e#blM83K>fabX)%%Zo(+E64P` z>Fb*|69gQ-YQRM+DFz2Bo%xdQzfHpBkfAsFh5#5WpAveng(Sl(C_5Br(8XkRyH$rK z?I2(-B8Fi%0!q{dX1ftp7f+4Xb)DlSf~p8HN;U=9!G5ndt!H7f4ZARzwTX!~qp4p!*)- zFsEQH90OlAup^ME>84NdVU4*^oPiipvk5Q+V$um<>fuWY8ncQ|Hnf_v)kTXbdSu!p zyL;ZorvqXhdG>;t%n$Pn2-BF<-qNjpas`n$QJ=Hlm|Iv3#bQur%K~dSLV}pyxUUx<_KrkE zv9%$>Vyf@FHqxv?9dJmDq6C(Xb54O9z=v$|+Mg5NOHy@R-AG*VX5;f{T_?n}Eri4@ z1!9hGd|E?k$|HAv&5Y)k@(kn|xL^i~EC!F#(RoX4LXcPt3Mi4V2B;;787Oj)Lz@VB zHQF{1#?n;c%xuF*9E%$pYszseLt=mreaf0yKnwvZBPy^lPBu}{TZ={WrMmjlHN3j& z2%0R;BJ33Hu*6|fQ|X%DYlt0s9gB$onVJ?5EP0{fAt@eML=##>8O4=qJ>l(P5fPVX z@QfG}GzJ^08DW?>?2Rfk>o835e&gzsQBkOa7C4Y%XgG@j1B3vHRLc=U5!?@(77RPbrzvSN$}fJ-N+#EdmGbYOFA5 z5{Cd?fSJ>~ zYGN_^_SWh43Md=E8B8o2D;oo*zP?@_Q_^={@ZGDu(u=v$+_#TUZ90ZAGXQ&tGQXAq zE@ii+^j<=i8G4*8CY|K9(nhhTkycIClF_kE95L`hjuJp7FN!D^ETt`cVsG8F5!K{g z&qLN?tZ$#zlhj6N!jS9bJY+LC!BJv3aquzmBZ$!{4}9nd1@i3sVo;)K=)?_;LClG- zo6`JRo`F0A=V#!R@F>Y*J|w7&-bo80bAY0nYMiZvtq^3=T&;)3v1Ia9bYw+$#gi08 z@8-;zNtd=!EqKx?D(qsr04))s!s^9Yj9aR?T9UCg?PSuVeL9?gn2K1&hfXW5$Q~lM zTIMoyc7hn(*Ha@&>N$W+W<$G!#uiFr5g$i&tV(f73rEYx=oSL}iP|0h08A>3%+MhX zX)#7mu=AiwFtQjR2G&#ox_Gi2o~$adg(?)7N$9=2@KIPwuaaKS)Ge}rGU3$!qUUJx zDBYhS=KMD)Kgu)kwKI@dj2@+JYMFLV3NePrJEHFhk4q72dT1OwuDYrvg5fOZV9C2^ z%=%t>liL@nG&6K3vv^}oQ-Ka9WVS%>$Y}W9q$#Q&toFK{uHv0hTt@yt(g3w#KoUIF z+DbK~5$uVb@1zZE4W29=<}C#0QCbf?QXifik}?<)SpkuA)CA{RJ2FFv(TAi9+EbEJ z0c#E+2D=Cbq}vM;qmgFJon@|wP7an+XTaa24aCh1Ybi-$x);i0fS6T!l>&dl_&#fv`hs< z4C}MR)pUw!_E&}2d*~mObKpJnU+V)S+0fUP76fK3mdJ;YU50IELey~AAX3bvvlu{z z-2}t{C_gj~SiYhkO2%aOHLRt;97}E)R15_h(EX(_rGNgzPb zop3XBJ$6YNi*fg8Vz7{Ds5XtLyLvmlbt-rO1IZ8UrjJC_|2c)+U8!LS9LDP74B1Pu zHXYSIKwaDk#wfzUWix?l}6U-KVD9wessH zHNTo?AkV<)47~EVa&P;R9pos%V)R;5Uy}lxtW*ogG#QvyKPttvv$R_pftb=ch%gMT znZ}m$QjDd+qa3(6qq179I-;ore;~p))D1D_2oxd;Se_v15mpj6Rpcc_;(#|THP-_t zHJ`Zkqz`Ch>x(+Av8KR+fEZYe4c_ob11}BX`N195jr(g;Yo|viqu_>U9H;UU8Vj~j z#Z4SsvnU{jB715uAdEt9)B~0q0Wr0;Lg1mbC_E@ra=T)D?ygoE%=dW)@(g_a z42&8|Xff&x7)epWm#TNHDQfvbK?r>vjhfr>b7OnMQktW;dM5bN*f?e<&980IDT5Xx zH>j|{WiN_rXMHkJ3eD9AMlojJ4Rs%BHa+q=!mW#&<&8(Fir8R0RuC4$d*w7~=R0j! zJ5`|>h-nEX6Q~5~FiXH51SC8VeoKbc!fvBtu1!jH$~!Xr4%ncvP~2ZiL_G(paR&v$Ydtazzc6CRScLDPxrNUb^RW&82zar(fhp9LRXC)vhp2To zU3s@=>h))0=LbcVa`P7Grxf6WN&`3vF(z_DwI~wP)qR+2SbC0+ylP!LtTQMTo+3*E zhw)?BE*TM~Q>Sh$a2yRa8Z`+qRs?4gAxNio#lATBIUt6}JJKMj*+t>eo>7Qdw|s0K z^MgDCc?Q0A24FE^Ca?*mi#~~tD2T6iaibPgIZy(IsP`Cv zN5)g+CTxP(AeGQ@n!^Uck>XT|3E&p)@Mc=Jbv87$?caA`4V8fzCpYXnMwZk--3UeO zKrj5za26}gFf@x)cgfmDash0tf8|R8q|PNi0wPu?_I7p{jR)+Fn#Poj>FGK8TCkXP z_kZo2e%BY5J^I#fo_P1&ckf}ujSt4gQ-6B?SFgPC*uD4Oe)}(e@w?ys?w7y&CBMJ> z-7kJ|`|Y>i%XsYkc;%H>e)X$A{_*+e|Mb*T_q_YWyH7mv#Bbhu@zG`9^~^5ybITrm z@zEDwe3aYxjVCW&I38vEubs`Mo_*f_iq62Op_DvI{DEG8>$=-=cQLFc**Sc?Xx^M0 z0X_OPVPrA#iJ_tC2dB8A8E2-tP|GU;6F30wVBEyjHe#!%(W{=|LT`OvA|-6C%(3L4 z-LADyU>f1isijVgqHho-gZld2Zqf!|MKM?v_Csq@^MCl5ub zaX;c{KXU}27{KualHetptRMrx;5{lDXC@4g+8vGHIIu0O^)z`($iB^?_a54TjNGyC z3)8GAb3sj=?hp5^*HBu#;ZH7Nma#Y9f(?u(e)BJbCH~FhT|W1x=b!)MAHfgM0s#5C z0jRw6!ov?g{`kw!JhNiOvv=Nk=N<9;?At4LJ@d@VjK|N9hZ!%t@X{||`sFX#mpc`O z9(xSnDULrfo(F^e=lB!jDX+?l8Ur}5N|*vPzA_Rh1|V`3aT$O7<4@3q3`YqhiHJY>bR0%H2)+fc;`9q4pBui-DF>vGHDm6&B^K zrvb@kbDjRjIB|r&lHdx7OqJo|4p6bmxE>{-1RE_*+s4^M4cprwAO<@Lj0u2SGl&+m zuzR616CVAJ5BD7qV%98r=9$MIXEn2)0xj~*m&-_ z2Oe1YO=CIZ{`>B`@2>mS-L*KzqD6}r^Sf@{y1VYWi+5t&f1exOcR#~VtX!V<_rL=W zJa@+(pi+!ypMCc2w^yuKv1=Fb^p)|lXa!a!kb2>zm$)JaY>CSP7J?Wh=h$G$4j7$a;hF$(bILVtTPW zfC3hKBQ%0m(=DHbPkGXzL#M*RshQr=k4woev#=J^p7A7ARFqAI#lR#gDyEI)8cf=B z?xvr!%&Gl=Z3U4Dh{0+BNyrjVcNuEAerJHjGXXIv=nqGEAPkBPrdmst`fPpY{tXFW zHm%()Af7#awum^JPK#VZM}Il?n39h%Fz7yEE+O#NQsD+E#+KQ1vP7Bj4U8%(+r7 zjQR2Fqx8V%G3L%)vSf*EVp6l1DON;{;cL9ZyQ8;D=Ej&mckcYL-31seUY8(g6ovwa z#G=tr#3UifYq|rn6u|WCvmg?5NviZPKj}tjeEaRUK>$z$cw7#$-FFwD2L^H^e!gME zX|UaeHeu$uTNxCMkT*j;)5zSwjp zA}~H{1R9eg)o9>3I=H8*FV_{0tc^1~w06sw8iABJN_P z7ni$BeF@8&Uxo{OZv5~thD+Z!M}K(=Xar9DpWOV*q5tJnMju|EZ+daBays9%;gaut54g^-|D9pqKMjod!{Gn(HxA!Q8;kof zWX@^CAF%XS4B#)eYI|<;-a!@*YA=hZgG6h@Q;IndA=}(+HGfBYVTL8Nt?8oZQhspP z++_CLe~k4?OpC4_C;@9$Z?Ldpa6f@4tXB12K&P+uyx<$5DF&kOmQEannSdCpI3T{1 zxAga~^uULX`6dt(A`Apagelc@0+iTwsvdmk#1V>kH#Nbzmdv2xZ1u>I4e{x%>^BDV z1Y=HM<8+PSleJKS3L!ZRF)bxdqKy3lJ^T*ra|e@NrH})@B>mx5{%hmZ001BWNklhXnVy<{#J$?qs) z2CWMCNH}t(j`^MU)Be5ht;?`~xv+2P`|mKm={s=8I(LTCdT$#+cl@meVLAp0#fQYu z&7L6q>QUmcYBS>nes`YQy6eP-P4sYdtT|mp+`XB`uJDT(vo5^)bMgSVtKNy7+k|2hF8`b0TbP#q|t^=#3<@%b&u*aY| z{c?}~%7gP`hX+2IVTFihYsE}D6~I<;L*0=uWk}j4V}s{K&?$bg_&lq5ZA>=iU;#Tn#y|ix_#fx?pRG&hz@h~1wmlywv z&wTZwM(pJLp3-M{j)|6LoP(twPBi`tylbC37Z&rs4>1|`zu}v4;mhrhoZ1GuP>o86 zArF!!N=*dzcGh?H788^X9a^(y5smHVx1T&&6nW|Ue40X=VTOP%4)6gE0O%m4s+TJA zCihbGo35MuS#r_{9gB!n(U78#fYwQs0k&8$tbT|}Bt6dA<93JU!->pMOke=AM6OaC z?qIuHU>OnWXOM5NoNJ0;W)Z52y3Y~~I;bhcj;ny0h_h2O0%71y0WqGu2m{1u>D5k+ zMDE)DbFud&eWY389c!TL3y$~B)(>|lEv9{J36Fw7$YZXl3w}a7^CtONF1+Y9xEV5 znp0l>UUGJ=`Wti!h^Yr+lw#DHff#b8KacY~wDo!cgpU9*{Z$8d-M{J3p_6xg@Ir-Z zkd_|%64sJ1On9OB34qYSKq#`5`X~%xUC!Qsm{CJ%zTt4^Bi>lnv8JC*tU_iHUSFd+ zz7p^8_S-&X?d##*^~~cBiyOwBJZ4z#uOcXo2sUEae)Y#!cv^hHh!27tjDjP&F9rA! zx?2o^xaX-q-D5h@Jc~1qP=OofP0#jAx0cm*NevdP3Dpfl@lA1E)rz zYQ>#;*Inhy6AXbyD_7oerwFzy!f75RE+|DCN4T*uK^Km|MS+p=4PinlOpx33`!8D& zfb+`$P(gHb7?ku9PhJpXUkHy9m@^9b-e=esxGxU&FN76T-;*c5LHhls*Dw71S0A@8 z-*>KK9&MCJ#i5~x;6mm7;f4liOi_wCbXJI&0mLYnl$R9?h9BCeMw>)aOVZIH0O>cv zXN3joRU)($oz~z9?w+Db%!3m*4A4VbbU_zEhed5o5ph9f5J$>i2rOEzV>|X^J6Mp6 zFyAOwRsKP|e`t?>E0h>mjGXHfT5S}wBhJ_Zq8MRxp%=GERX(}k95$UDsX%pB_yxFh zV+AJz#eAW^_OrBq6FM0)Y~6y_3N0oXN{gN{sQ;A|Wfy^VEDF{EVYP&;xnAQwRYN5-x!Ke ziUS{#ZH#g6Z~P0h8O_hZrqabUu(Zc4paxj!?_ql^fn~F8Z`RJZ0Ja6ByDEJB1+McVl?39l2QlTjeGz{ z8PubQ#!xiGZi2-)ZSxm@*L6>1`gi~6|LrHw=MRwd^dFdL1Pon(kj7VM*uPlVf8woC z(ihC{!oU~|;bL5*0p{liCbhrIwe)35X-IZ?T^oDdy89Ld$lUkA#_oABC>KMamhd>ncvCg-e6Bt19bo-GrTm)H?<-8ct!cB#2pgm5v{25nz;@+CoebfF|u@ z4-tU_$TXuSuLb{Zh>Dqbp3kIX(df zFjJKZ{ZS%(_ldX6svjLMzID$%fBGZou=hT8`!DWT>}px}94uz_YEZ@`NYoerMnR^j z>**pMyh_ohVI&Filp&##Cwv_MQ35Cg_UeQ@<& zi#!o+Ha`~Gq)F!noABAvwgl^g$TS&4@tsw*Azvtt05O^!SUbumW*q_)I-9|WsMNdl zCS&q6m}1;vdZK9qe2UL-t1c1{!zU}tQ*`YPNKFxQFrJK_gJjGcDzc~@fo4%ks;;0E zb8ZGDdW9IZrL}=QYyNp&bw!A=Webru zFt|!Yp6cUgBhz}(edG3PmM<*Nz!jQ-7oUGSv6wqHHZA!3%|gsl>Vvm7;G(5@K(O&_X07AgB&`YL?3HS)m5B9is`GS zc^kvVNdKMAag!noBOvR6Pso2#QLepeMZCSLlDtmdM-!&a0q3ux#EI0F6_TNJ#Fi`- z11QQBs!G+{qh3t=;wxK{>I(gr=H28O_)nSvSxhpN&Ru(W_013&tD*=oM3^DTMBcLN za4prb$&NIfO>;((rRdL@)Goxx3(^RPVZ9gao(M1@!bIcfL`28bmHj-S1FvlTInlhT z#4KqODdS$0f>v--WHH)I;bBrv2E-^B0~#cTvFSZY6M)9eKm`)+THRhD4#R_rvd{f3 zEz>DAGxSJ6#$Cv}vY5)+y&438Nn%i0A-(@;VTAsn7bNSDlfl(H7*N$_2J@al}z53&M^HwkDj;eP}P1Is~IxVtEuLi_4 zlR7<_wH#*9sp4B}ga$Cc#ZR6OYm)_!0E3;vrU5av|BVbg=@BRpiUuM{aphCb&V&Jp z11OT}ep^z(9SSkUaxu%bp4dOJExg468ma0zRHQ;12I7o35ZcM#LW+@WB)Pa4I5TNi zi|wCkYKjhc1l~}LYHQo$8g^QoMu#dZD_$x1y|I_%M$9>JQ&s zCB)qKz<=gcy@gksPt-MvyGsZj+$Fe`;_mK+;O;KP3GNWwDeeV|OK@m$Z;=9}6o*0! zl;4+k-Syt@-ap`3Yi7=Q=E&@`_j?!VMk&<)#0B|rz`sgkCc?r*QDsl~P1U*$-D=QB z5xHY~KdOtoU^O&3(YjxkvqP4ik4VOZ8ZQ!aQ#e<*j3fuUs_JDBziAEsidb{JSB6nm z?B|rK#z5&Mqtrx|+q6GHm8y>4`!*_6V=)w!ND*8VvT@hXP*dxILT#Ci?p0k88x38P zZ~AFK`9!X$wDtsf4wAKX-t-?_wF>w%934TDOsM$Bs7-)niz1`qViKf4)ps4b{49 zw+fuyy#9FgePy~UK=>8HB)E7rXTgYgsQfmBQpL$`?p*6Su6 zBq%NFs6shBRl7GWW%6_D?hVY7aJZQk`syAK^OgiwWQW>choDKLzkOqbYP$t|it9vm zSDZc`RQ&R02NQ&kfyK1B8zX1r9oefLKbRM2McQS>y0{Wfo)mFQ69iXO$@!{=|G1{0 z*4O@Z{OQB*_a{9PWoz#j|A*;nM~PtXUsah@@T1G_x)5IUlL=ef5j8X+n<22BV$A z8IAm+VVR^%h(5OcV>5SR;2U6`*0M9Jd#wRKIzyeRe6z+h3AUQr;O&P7v(oVxOsCE4Z8g6*f|`b}5W9X%w>AB9l`Wad9mZzy4> zs4N!#QnCo-ydeFq&N0KcUMn1O%8g#I9q+w%J@wX( zqbX?=Lv*-|KU-`{bMRU`clmA$) z14sO!UR>?>xvL4V2urkViDZ#gr?PfsZBUpGhc~nBB$Dt|6xN3}INsr%%*1rTr+*>Y z8PL|U2)E$phUQbnLf=RYaTt8FK|NGN$kC-s{}7)RVj(B6Dzf?xcg&B3oa_J^KK0m| z8Z<%M|H|~A_MPf6V2(7-UWN6vj=3IUT!hPHxhL{dYWw^4C9CVD5*BxepYgkU|(eNGnl#;7e*G z>Ms0-P!~u;ASZ^4K_<~Gee?QCv0OmgkJBAnG^NBjD;WAVp_HhvD!op{PYah`FNdlD zMVq#;3S7-JIDC9(&5<1ec3fZUbXX`=)kl9IkPgQ3%mR1EIN-t5>6*4Q_T(lx;pFeSZGvFev9G=lKIEgUX7XDoXB$Y7|{A8jl>>S5nUGXb|Zf= z$U&uhjPF@JSOGI82DE|mCUY4rg#62e5I`@Alhit;CSWHsY0;Sh+@-AIaq)xkoL3gF zhoRTHL)9+JXvIo`8kz~;&!dU~Ru>nM=xQF2{D1b4$M+iXn0*T?x*DQ1ukVkcD!QVuIg-(r=elS%oeavErij!E6G-CEPGdRC z1jVx?eRhHPiDl2aM!TI?qa-7ZAz5A15iVF{V!^9bzu-If%217&FBt8o7frru!F40p zFd2ec>c;Eta}0;_U9!vMg4cNn&n=SrDJ_nVEr8 zcIVXN+o-Al_6(&zz8! zG$wwGjrCP#32jOgo0d`pm~GKu)=9UTP@6P#w8tvHy3Upi>``k#@ad3QhfL}7VBe?+ zwfaNJtLRJmk>v>`&{z-&uHbiN8F>CL47Mq$k0pH)KMTH(v*2f)(4nLT$RAO1#0Qjm z)Q3v}+C-J5`OMzJ6as76#n<%4y<=ehlf@L;d??#9E|U9Nn6z zAWlAv$@30u=H6Q9I21+D-XHr&r1@aTd8Ip{(?|WDwWHN+58f z-TSxYG)1=K{vJOnAHZ}z+zG7tCZVcyd`e*tSs>+KyBZtqwvft$45=#m8WT`WRz&)3 z(YNmpf~y5i9$jfjR!B0vBYMdA4OTk%rZggHT-4NYU^1R|^<*EOngFIerMF!m#=U*i zk*IC0Ly0exFNDN>bPQq`g`TDpDqbn_jy#>^-z4$31r0>r|C-VrMi_yyuE8(~Y1 za%xK?H6-~1cK5TlV=-Mmn70zXZ|k_!nPVf~6#04c3p>oWpepf{<~1VgUBcx3VaepE zuE`2P$5?V&8Bk`-BE8M!fd&ae_RhfP0!wmx%AxFUc44;1 zF5v1M!PbRefTJO>4>Fz}bVJ-@Y8t|HJqD9EMirP=^(jXeSqk0#khU%9fCbhyUorkQ zD{_eoEf^M-pYJup`wMxc6$HT}`SmaRe9bNOdxTj3B(ryhj1IJsnjAg@0v65cqvF{N z1a%hCWwQzxk-``sBPo#Bi@qh7lj~C@JnT}^L|TjG1&#s#!soX-{TT=sq+tV!n*!7= zdZiONB*v8+RY};PXzD061o#UK_gQP;0pT%3937d!F?sbPIovwF3Z9@sx$M|KqwvqkvPwc~# zU*&Hiz>rjSGyrH01Fo_5#E3e=mPfcz6st}t+Z{dR#v)o1u%4ag_C}Ar7#;V$bnurg z!;(`jynx8hl4__45C<4m!~aE}V$0bN_l77Ypio{vyT>Ct90?T=4xj#Xch*e6A!m zzbhZ)S&M@DQ~STagcD2*@fHgICb%Cw#YSdSjL_^e>=%8g6yt9L-VVzrPPLgcLFNf% zgxV*6bQL{d;2|ZduXh}0p`J@Dx*wNv7Lv8mHy(i*gO{zTHQMSITi$a+I-B>(nZ0rDc&I{6%soJGkt-%l}|~X?Lh32ynq-IS>Di=UpAYgjDku1X3&zNP(C5R3Z1|pci8I?PHD!>-|g|{_wAPB=YjB(`E|1{a?Z7i ztyAvp*`oT)u@+0m;INbV&X*=JC)UcztQ<^5KyG)#u^(tk_BR=j>{`$GQC`s$#9AJ& zw?8G_n*k`uou8x|Y%?(K_jkeba^Bbb z>&Cy|Tkk_!H87Ect>f8Lbef)^SLfJ~^Bc_VTOwg>+wco&zfQ+9u7(6RGu+??f*+zBy)l;os3JAfyE9u8w->V2C z(|_a=Gq7@8fmL4fZU_8lfEJ^>x9d0%Y9S985SFc3+_sNR-{}25m_0ZYz{9IYy1?V@ z5Cj;ei_i>GBa~N`J8EtdXJf9dL6)$=#B9k5-q{Idi}XsmajTw0hX+MBYdWClOD)_s z0gY!GwKrK_0@$ z)8E{kNj(c4^l>n?HQ|c=Go(!Psp%T_m}=FWM=a4q#Ai_4tmaS(Y)y8rp!Or4;6sN1y_?G{48xr3pu+9fZ@uz7= z6?+-_F*yzG_sd^ft9Cv=Zj|t#TfNk?GEqHF!VkF8SZ05^#5=7$&p&Z;i@|XMg(fsE+lU>9JM# z$fLCeP3weH7SXu)k``B2g*0{qpbpuQjRm*@a4ZU2MF5B>4Ov=k3vxs)_R@uMk(O#xgi5 zf)~6H5>&Ca9NUu^pgdbT=!(`N`Yzc1s&Q6+Bn|i=g&jHvwa`z&J_g@14;i!u%i4t= z2M%Z`dh$u@M@S_uZEQNis2?@g@5(XUiMRxR&{5F8{4}g0%#Bqp4z|YIs`6t9c4*BCFh`S1d zXHt)|d|H5&{R@O~>5qm0Z^d~W{qDo&4=#f+1bg7`GfYyueQfZOJ!@&=4#nR$^u$^n z5hEvq9DfP$*+C}{%?ara0KvTn`G~jg`u=AZvRy!`2@`w#J6SXtV-dqk>p#KLNRM@;RxG8Hu~%coUqd4FF8EpPo}&kl952gYy1 zK*=BQYrjM8Ub53RjL<(6B}XVc>_}K7f^(*;KK?n|(*aeI$+;O4>WVOIWeyyS`y4sE zdODox#Bh3if%n&xDk8XGJbMkImAP6^?#1~NG$P+rGtCfQ_EPST?q9E$S4YxFaZ9ki zoD!NNr*%y$8M)cK`4s&W1=2v~{VDf&-u>gs=$6669iKV*wPcWdknJ<2?snhvDg6I; z!Igq4?XXnES@}<-qRt+epDJf`oW3d!lNB0QdhT`9~BaLuwBfDI77U@(=#mpVP|0TN_?Zm*g}L_1j<*W;J&W)xLMo0l#m(- zIvSlPl2-!y{HGnwf3ZNn)SW+MdOAe@yDP1IcKT9pl}2naaopQMzS)1m2Q~e1;wc+C zHKS0sO`)9gw{t6uR#3LE9E{cwNl|5pHluwGfIM79AUOB(U!&$Ri#-8YRpv1ruq3a7uO4$^fv8fc>SQ?67ljP=joM2<54ulL-kb-gyijrW^8YIUS z!AoMzE?j+-@iB}XSoIwZg#{{`a$qc0smE2p^pO@kT18xM_Qz43JmQ*usHNFLCH6pL z^D;y&PK&KWh-rf6-Bh`S!Io7qW#um-t}i*$%W^c5Uz%EOuhzA{J}7fCL;-7#GxB0# zAn^Ma5m|2j3Db-}4m>>NR0h1V8V=w)cfq4aeH>gYuu{$g-CNg!-+4R)4E)b&Nv`26 zN+qZK;%?ow`FJ_6-$Ib$N^se{oT&Y5iBa0@69?r|koR`d zR$9fedJOpK&=wsjRF}1q-TDW`>T#ayu-OoaJ3G;&7I_*2*4{ZZ$`gd)nG*EI`1G&x z$UrR?_{X<-?pm_4nXvg_`zUc}@H4mI_9-4g!j|&SkzfQF3dxXOXvNoC-rVvRmnWt8 z8zv_V=|DVWVaBfmKEXTOa07{ifE$Q@(z{RbjpT0{ru$_tlJ9XxR)5@dcd<*)W-3Xbb^n8hR+kZW=XXjeKL3;p%TT zQ6Q@9MxTw_`l!D_G!2+%=6Ciw=d9inz<= zeN~6OYq?}Vcx_|X?=LF7vwQ$4!M`61q=1u>!h$jjO)&2l7Qv$su8iQ!&(0oRY+-AXEXEr z?65_*s9?LOt@7XB^c^|gugahOqDIic+q@!;=U`x}UMr^mb{C2@susqjgmH_pUn&%Hr6$QglYEq$<@cv4z!>a> z@E1tTEX~Eg|2FO`OGRw0Vpwo~IjMf;@Dxztb(FjFnY{3Te}vF6>ralKf@Q+{Kb9Ke zb=0q6x+N$isd47!?-j7g6UF!Ee6&~%tx342{yyI+A-O;Dt5E#L!4jC9xyh3HR;k!Y zd;2p0qrW~iYGlO$v%xYsltbWy6R`m>Th+Mr}RK=;?Z>jpp zL-bwbg#P#10ia+}X`a1hC(0aM3D9XX?lQEsPDDvYc^8yx@3OHkfDVV<(FmI`ux#uv3Z4Jy za#>L#-lT>`6S7S#tZ2@-*-BMb*0oaKy4YiRa+p(sNoWg;kRq`IoizHsCyD6JDmC}&&deIblO4cO^HnwlDq3yNyUz(1V0k6%13+t!C@GQCn0nUpkCxrG0kpR;j54NaQ9xZ6lub!nzf zXZ=Y$3NeFuEj`U}Wr$=aNphlc6R6FQ9812qKhe+X*y;^+0|P2#VCF)t)Ar%N+)wFg zsHZ44<=|h;W+e-6L!Vcv?e;0n94m?xvfpVDF+x1>u~xRtc#L?=k~-0{oofz#X3&sU z;&r;h46DCo!feshhx~rp@8yb*PKyWJS;9aVUz$6*vA~4%w7d)SEcC+W)~_bk1P}tP z_et}TUUV$At)A+u1ParI0yPLN8QS!EnHAB-_ke8;WT^LeVF4dA5;zO>rO1q!DUr`7 z)|yie<s&2qMxn^y%Ql1){EHqu|7%Sj&+E+ZUMS>!_I4J5ajW9Qb@^J)hlGCRihC zqY-5Q9O~~cDq<_bbuOgIrq(1vtAR2j8Yc3Z*g-Y&UKD(NMRy6_Ys5sDkg#AcC7bCS zS*Qk=qQ-q=)-W@a*fzSGI0sYCGYeG-YhDfGIGMLK|ynug4rPX8x0+2r_-_kqEowQ$4 zQSfE2hyJAc`{uxcV=(qZo}Ihw2Oq|E*gr!0g?|vWyL!aGq6~m#hiZ>PLN;4ZZkLBD zFjFZ;R6ANXyp$#Sm)=sDtL(7-m!<%$&111aO+iK?S8h z*hYn)Z+Qu#x1dw4JpOI?=!!c{GNJ1B2P#B90sKS)ec;9W{w^sByf3YolF{kHr;~DjT}b2NGBS{WE&uD`Iem2wJ_|ruzIQe zpQE`KE0UJMoa#>s2H$=bSNWYe9ZNkiAN6GM=#b#f%g*2Y9J&iqx)7DgrxsZuvucVG znzp+Sv9oLYnxT30iBU^|u26Dqp1jBB#Z&u+v4A%ZqY2%3vmeTrI0*`B`WA_Unn`Rc z0-D3(l}?b!HpJ*I6Da2nZWqio6{s7oW56?uiQUf)kGTEx<5eafs7{$-$2x_Jgv-G9 zU9GLaVbuzRF=z~3Ld?EIIV%R>6FZ&Gy=U@{MA<~&gNJj>VKDr%>-(Rx zBhFp{TlU#BY3{)rv)1rK@X@!llD%2(T4qGtUqrB0}C2wM`qcZR0 zGz@r_uszG5f{~A_cyOIrjTls>aW$$-F?}CYYXGleQdGjeH)slrt}$;94~m_xT4F4& zM8E_`oBYFF!TRy{vB@<)+4lOnu=i0U-$3EEnkt&a-E!z9(l@t*<>h7mt=+e(!SaL} z4#iZ{mr8vTutar(#Q31dxk}D$qZ`4fa-vQ@27jdSKbniptdL(zovb-PU!G zNP);SJU5puO=0oLzyZwiN8v>Nvmoxkf2SLwW*EUoB~|B!J30*IBo#{cENl6NH48=Q zH2_1@dz=LJMdsqyLN{+`6iHqaOb>M2QkyF^k>*sI`6O&(RasF+byg}F_gOCu!qo~c|ZXl(SK+47v_%x)%;6V zM3kj96^git{NA~~B7=%V;OEbAKzU=$vvK+7s7WsrDYbza8HvboYFubLC$gNOW%yx{ z-26AkR>Loy+VT;STPTRSG2(t?<123ueS~L2zi(_9%>R#COauQ$4-)^B$Q~{{g;pMi z;6Ccu4{)ut*^dp`9a2qH95RtgNgn_2-_gu0(Gi%#gN(RFqyqvqR(8Q_NT~I+`xefnuFy z6+7J3)_|jmvCaaAl4bxqydX%p$ovgWvN?Wu^t46Sa{1p+(F}wG$|sb zd@;)l9lj^Dlim;O97!L#YwDAmI-vOA!S6N_zYq39O3e>O^8$jD809UIqf`E@5WrXW zyr)vaZ8zJk@r1@Nwa<5;-*kj{&=aXp;J_Ps=qJ}>A9*#02Q?cbT(L$*zmifL5wD}a zNxJG@$}*gp=oZ8iD3IR4=~^7!+So(tpWuraqnH&7n3o>kx9q!IBnnntHha-t%u$dR zBjcA+-$-bhY1c<*pRvRrG}m=BWIeIKmTAZc+fUNu9@F4M2AjW$j=l=cL+%ML5kq0P zFVBHP-k};wmXB+)Z~X z2MaveWXZgFz*8}~PZ5{gWs|;vMis_U3QBA*PfTL{zJBgLHD1ZoIFFXdVf1!OYVxyh zxki^esL9}z*)BC-;YMavnQ{3Z<9%YV`tOM*3&e~5*mpL{;9`fASX2YA94{zIL)}$8 z(sx4o>&qOE0Wmozr>UL}SOwpIgjwk@9{yqO>$|IP*L=jn6O^ai{69#N{pFwTXMoe} z44?u8m8|Ie(UxJ+-oN5`PZ;C57?V{MP>J^Y%vUKr8o=(>IBw`rWEG=jojX?9YADBr zINJNnMKn0#lgh*HT75C1m~=annLn!vJhzx8wn(NW@Il`B5hF4?s=^)ex}Q{4&(+Iw z8Yaq0%K;k!{?gPIk#URS>I|PeDlD&I^$KVltRg%nOK^_H%k^5Bj~gU#q&IRYa-_jB zOH9$C#U^-W8fokctzR?tG_esI*^}ai@AAS^w&G@W{F}nfnfV`|QujmOoVAVuC8qc_ zryaU$_lb>@s8G7yDyfm8m;gM5tnJP0oxuDw^lgQZc{&rk&6sPh7o8AV!bJ+To3-~? z0^ZDAPR?o7m+7bY+@;9aNgGI zB?+*AFy3QRZg#!<4P*BdI4xlX*UxVjtU%MDog*7<33L1${+}%>G}IiS=zSwieU(XS zP*q3ACxV4PWVKNVoQ|E5jKvpdb;sbrRAXZ|5(`Sac#3=#MWCc?3Lh|}-9IBpYoh#j zy{l<5$APjSeMp4K{_iX4rn0VI`#;kU_>kuF!k^RJG2Y#$|M|gK>Q{QJB1{Dbn!CvX z$JE<56CwyuG!8L7mrnH%12qOnHT~io7*1*(1zl{lY6#Ch}!FTwyD!^1oC z{X6MprIlZ4+3%e9{Qu(eE)TL!wE1P%eRKdI15wjCbg*K#b+z+`ehyA%I1EyK+}dW9 zVYt1l=7rajhsG5Zm8(SJXR^%Yc+lx(=w`}hgZok$-R3aK3%o2NfrgMYbO&K?w*V=Z z6ztdf`j$5#Gy5Oy$}6M49Y?-vqa?ztIB_N7CJn=9HianAU@K&L>6%f_;TB_!YY4BrpS`A>w6K!dyl>q3xyKw!q+!sr~5O(_4ChEice)CU(8>6K9 zwx|3Xv_2@FTVYrK9!XV6Ad4YA_e+OS9j<(^?e*#NwUCEPjc6DgcQ*qdg8~Mj+Qrs1 zlBMbCS;xY1u9H9b`Hq*$hsw}0U;xI+>0)2pwqrq^cxlL91>1b^47P!8j#W|>EG*kn z97?}1dCk*fS4O;g1p3VGeGEZ%L+jA;Mw6P_Oq2#3Lm|VbUbBPan#c=fO8~L}CJqWB zi)Ti7guo1i9BSnZq#8`zwSH`7krP@rOv^~Qs!w(9$zL=Fq)@2ero z3Jrm~@82KtLx;m3c9~a??nU%$S^KG6IO~4fkd8wZS??t^@`Qa`5`*+)@Ot<6m6up} z6*Jjc_=%McI~>0-TnQdf_;K@c!ZZgOVGCZu*CC4YgQ}u1Z-~Br{O1kuaFrv=aKlfAB8SOIM=AfvLV!llxJ@`V-0(jxE$z)_vuP1?XXU%OU!W4hYV2w1dosb{qhT~tc zV+&-uNELl8x`Uj|@J@SH#R7uvspaM`e!UfwjFU&a+>zjDOoP3B_W%qS%FY>#s@r-W zS1i(8%6XOg8oXgPV;<<3e_H7;Z6wT@5g8m(GNT5ugI7TkGpqk*b^bKzw5UCS#ZYKe^>V(y!C&1@h zt_LDz#@AE^mYJD;aj~LUK#Fm^j&2wnPM%~vxJRSmViq>tvfvjsXRwej!lOtcgzhSS zB%ss%`6(I)OO?U%Q~cmG2RK}fZ_*8xrEz7@yr>D{@DKI!A{JbBQF$XPV?R!r1@4KB zO98hxtsN-1bDdJyW~lr{|1y0%tw_K8KB)-^ov)Dh0)AI-4ChRbyY67L;PHqfL5=ek zzTrDGnq^s9&L14U_b9F|_(s`__X(UTqaj&Z{NaPxoY^@)tF4lC#U`e>&l<0)bap{_ zo?K=Kg~3!~h|wQ|U0cDXy1^s<@f1S=0rb8FrJR=V(1*&%&kr$}W>*akp=HFojf=(up}>)tmw~vLjP0KR zy9|vc&DB)$n}u>Hb}&8!1<`lUIEBZtfmC8uCEm{7mQT)+q;a5*e7(Zh^ zFw5ufqP+2$Sz$|Kf~#;c^M`#H=!Y8s<;p*F&9vz;g1LT2p-9jFKsPt4_`A(hyhvi7 z`D7qrWRax%xh}P4KNJ^^L~w5j1>jC*!=!&5RXgb(JJl#n8ZCB^dqU@X8v|1VCcS&1=9|Yj@>6#gPiX1%G zBii(R6S`xD9Y@3qq7gK<^^5!_iR%aVqvP*7;>-J~d1`Co*R{onCPQkl6`?lYw?F3d zcM35Z$)qeEpf>e3ulI-j#(1fIa|+f$gu*hW-!}0@MBjO6d1`=+TM}xTIP5rcq(a*k zSg|@7s(A$Vsv_IxJ>lZ0JBxN2(yT9?IZ4X#Ls604Jn1ps>_DSxBHvw^Ry5Z88iuzR zXu3ZWM{+GMt7Tt?^za5SatJRU_AZhwV>DU; zvc&^U2u|cp8a$wvN+|w^(lm7nahrv+-FLL+86_e)laHp_Z z!NmWbdj?HSS}MJUb|PO6^8pnym{?B&W7X>i7^iI}vEqBlPwUnbyUZyR z?W4p!{`Zl6WIA1)f_|_3=uc1yMJUJF@G_+%XC{42f3?Lpdj5#kymDfKA}vcnBo9c5 zU|jL2n|;#Y{xez}1NCB=hBU(+ff_2j{P(O~WO~J{u-f7wb=&ddHavm*18XIj3W^`u z8 zASK=HJ3VWxLYs~?nL9N*qpRV2fG157yNaVcb(z?=v>GBWlMZrzWd=_USdrS7JE_hP zga=jTaTkdLvKbtt&!b-G)LalgV~~suK!rp3r&IEL zTz@EamV=dScT14LDh&)J3ca5$co|sg#?@L_j}rO)*hilftG_04xqwmd{aCYZvv|iz zq3*x9iIdfcI-?aRH&Bv`)BYC=fU=KljQw#VkyW^>yf3D+9hID8$kMOjaQ?DgY^FTJ z4DYq*$00I$$}=A=0OVK)6YHqfdtQ>m&dGYiC0mK8W*FX z+N$goM{qFxVCH#MkH0yhGLG9LBbViX{p(8lej^(&RGg z(ac^Fw80vzigYqJ)vfTB7d7w~AlErizJhIaRLy(yB>Y%xQWXE}`w6KMazFkJZ4_rt z3c|fqWpdxf1ouQt)`Mr$UWKxx92|`z%x{IBD8px|OcH9Ld(wrb^HQ5Ae|d6NQL1Ki zaR9caBr6!x2|ssy@Sw;x*M)WF5CdwntNm1egv(ASI7W!;!vr6JM1PpJCb$sy(+`|65#fQSTC>UQQ#Pv3CC9K5 zj2{?h$a4ppsU>KKS2>-4Qf=Z%xZ@{>iob3^P0Yiq*)UVv-F99>av}srsU#}LkE_wB zEx{x>uX3FjZ@3ukx>D;_qZ+ET5+9XyS>3(l2+jJ-e}D00<~g~jB4_#c{V2u}cODgY zUNMJP8=EseTjk`dXg6i#lKNqM+`6a)W$)%pEQ?-P9I$_8E7iruZ-A-Pu5>$Nq3&Ke zDKbLvdheXVPN`ERTSs*0mUN`j#>*Kp`vMo1c_-u z4v%{hL_!$^O4hVJ<)Kj{hQ~7ZO^gR565Awkc22P%9lt%u`V~2|{h$4@}ATbL}9fb2UkaMs*C2?r* zSt%0G_n?O&E=`wu#rU;(_P={?#myKCxRpq8tYj9b7N5;7>KN4v$OSvi++qHFtxXpF zfh;t}+&BDm<7AI=OoWo~V{9?y;zT>UmBLLF5FJj`Rq3kWN=ws_Wc_hv%S4!cn9SV# zgWc%wk|4ESsZyg1n94bNznEwyJ}Vj@NsHT;Y2g(0)SxxRES~#zJF0NI+z+T$ik~)Wt#ItKd)rWK26;`_<#SJ zmd1LMX5*AuoW7py!Z6#W_>0VNt3L`2614z462gYWQf_Hv{v@-kAcE8xqBua7KHv!0 zKD82!<3m%fzFjJUhffTJ%p3pb<XJ!hK6%hi0_D9+D z7N2h8(7*=L(Yz1U2nn=S&1*aGeWL95lA|%&U9m0Kb?jyKa+0q_^T|<|85FhwZ}Ca; zOlLIuDbyJ^%)XwFOu*TK;&+PC)eop+8Fnrg=aE$_?a3BQq0fKAa)SCwX3fNzuM3{^}~hp zvpF+Z*54MRLVk(WD+%f&*l0tWS#-_Dfv+7zLa-;J^SY{`z=j={46tCGkR?n<{?JyFX z!I#t}19d)TG{GBTh(5*3BqaT)CbPg`xW{gWVsVIj%p4b4C{-HMv32&@CtD00mItY~ z(zAVXo^Z@*EEUf^;}=?mC*oG*OTA%Gx-rqg{gh8?026s9)(#}b9ZsThg(#<(+$JdC zr65-ZF`Z4g6BVMjM&y~yi|$E&>dJXv7dE)U1lel0HKUBc0Q#x zoA0}<1KU{;`$b8dgmio1d;+es6bo4(CSbmdf`DHVc zpNBH7EAmWU`*S9f;r(%ZP1#Od#S+N^u^O16EdP$ppfXc|CPoxi|B(oegIi(BD2Z8S zu2*Q($sOd8*U;i%u^Ppq0xVlJ&XGH0m~&krR|l)I7KLzNGX9?^m9HZ0)&8 zFe|GUIkFPKLY~I%J5zlJfp|>M3Q!@(KQevhF%g-A1keWG*u}$0B18~%S{ypTzr%|` zC$Ph#R{bbiB6a}>|JA<3=-jz}dETO`Ra58;y_$2Wc5#L&2yRb$+AM zkwCe_4*HR$>t3ro^-A_FSr7cfAdwGTIXQcUIcb-4|+51lM%1SGP&sfcE|T_s(7c8-O& z@3L@>@%W;w)>!x_=ko0V;2=u`T5{$jqF#_N!U6a3jiyK9nrI9hjd3!>&v*lj^gHcl z!R)sFtUoX&3R(1NAS;&0PDljI4xf&9_wkf9iBOTVN5$67e%GkV93&QZe|gN4WheLm zV1kF;O}L8p_r%hFMs$*_qn6}{#XJ;L0iCvj`kD%`P+K28djE909sGxslzYGK9kuM& z*KB-;lPOjQdSiovoymANa!bZ%I$rB)*0?!E9ou*R1aZ2@8e5_$hh ziK~UWBn|t_`kctAAR`*3dZ1^c>IP=I{g_98K#FXX?tUs!{`8MsWRLG~WXcK3t$kFs zY+&}*q(<@%5!2B$VG|mK4fw$wdTFSl&Z&l7Gy(*%eoYb!+)3(VOcuXQJ!fA?K%Bq4 zD$n&QO>#vbpBbLz6`9@X#*V1WJ0ONk9T{R;fkc&0l{s#3U>VO|oDIZ4Qt-obu>RV%8B#41cEY~;OVVOs2Lx`62 z=e#@5TaR!yFP95AO>*#+oz@`Ne{VAOWSx1uPK^Mhe+O3OwtE8Ag*>eBW>F{opwde_sdzL{9;mfN3%% z^>^xhCYf!cBt}s+v08|_pEv(6kDqU*X%+Gu_Q3&3F??cQQqDtP`w0o<>Bf8TCV>yp zr_Y{weAs?{+QjinSp}9P1qwEH!04z!x-bI^to3L!Zl){(hLgn}dv>xDnBTJbunr$~ z;6jefl2Y)r+OG}9sxfe) z^ZQ4cVyYgdu-aqJKQ_>Clv`AmnYG{FneQ0QiR>&qlecGN{SI0?dB2=bklsMt$WY<@ z%O4N4cB?B-)Q<`QyX%CL^9m7%!on<2RSPC?x_xv^AW=zFk^-7(rqZY}1UaKxi+7gK zLYdLob*Gwbr8_LUqiq|vf|la#%&B>MmUw$WEvae~Kn5#%A(C$-W$rM#`j3%*>Cuf} ze$!reYiXQLIeu&MaLs_LuN8=+PMa1=($T@qO(QVZGVwXljH~tSfAXB5@@0v9*}VJj z1%y_w0HC`%5h-zvt?u8t9))=-oI4I?2kQWWYD2X+Rot99=N19|_w_5)se7xPxm)LT zwcRPY&(@xY)CE3-mCRSH;OJT;?1$!ovD%E=AzzkTK@@Y*3US$VMm2oMBp-3ESGK>BDY@< zgP??#Hd5gmos0$ELcp~xGE5+W7Zw)cc%PU-@Kxilqj*Xu6{eo-WBZmw&&U70 zFR3!yWqM#ELfx${wg^rkrn)-OV%{NAMqo*;G6LlH*P^hYQMNMDCVvDC7|7D+DwtFi z2@{y}uD_hNB@&@EZC;|Ec7BPipp{;zLM2dte<2?%KekTB+7%C`kn1XG50ENGP7wg#mk5iBEl-*WECI~U-EHV{)~rMwS&+cMeW{`r z5&LAeL7WZ(J{bMD>Gyxy`^v61gSJ~N!Gc2w?ykYDxVyHv1TAhY6n70y3$#!iN?V)) z#U;UMu@)#UMT)z_$@8r9u66#xS?kUHC13L4p2^JYx%R&H7MMt}H&7rhUDG~efdXCo zchg6uwd@^~4JgoQviNc3EpZbjH8AYek&-8Ks-|O)9Kwj~2k?+rQ4<(q^>Ba%rQ1uh zk!>t^T$Mgt39A+Ux?4RT5IXvbIvNw|Fp$2MT#AJd5fc}a`0>6emkPUNvV8?jS1^Gy zdB(^vZA~uxmDOFt#6it4&au!)-CN`LbJJB?Y@DzMzw>YQXEdd%ZxhMGF{hc~#4Nic zuvWlxZ{BH3FmL3Gxg72vwsv&USTnKiR)db8aaJ9`*A}+1LVohv#!4zxY-DS;mc`rV zuxbdITEg%5$AUkEo}ZRyhhYqWmwjL@#ElpAAZYnR$X01iCxGymm>$DQFxTetD0W5j zik@^l*Mm69l4CO_40ZkgytSd%SR#;wNUo zx7#~|uxKrwDcG01VZTOM@65kzf+T33W+JKp>dg0~JS9r^){AR1^Ra~5hOT1&K%oj5 zu^Fg@gRhBYw83tt?YI-^*(CP)vj{h{V#NICCS@Z&TU3HIw$E5%1Q*vvHIC8euFF4r z)sjB?;Kq|;GOxGCX<0-CeEN^zxyC@-+tp<)x|ZooJTPXLJ1WeDm*hEK5xQgZK21@A zt#=)n2Jjh>x&PmhSC!(fsAxqO9x{ij44QKpCR(&fpJ)}O?LwQn@Xf@{XR)%1tFbD36%)*+5CX$hoQe(9 zhVu~l#t|VLGIT#>2Rj^i{ofQ^(Z>dELY_A1gm1K$)_*4iUylFG|3ifMx)Lm< zqxG=xGFhHr*!`a(+`96<)LPdF2fzBls&fbDzivDGig3k1XGMAv}BprXOBK z%WRTG6%{qI2A--{kdZ26BCkKMnn%#at32dM-o2I|`ysCT?zA>54K)jwV3!Y6xw2hP zq+z7ITX3}gq^*F|59QGU8`WtZl3o&tQR*T#c+47oZUS@b-BB8~@EF$afR`qyU}it! zjjsHJ@h@nYv@xTY5n%jGv8`-p@EvWu3XR5&3A393; z+Yk$K=%IAaImJ-V6(-Cqw-%|x3-v~3_*=#)U`-{FwW|CJj{qvdtxk6|*qSNwaB6Xk zO88Q2-(lO0UNCR?_0rW*3N> zX*)ge>$iOM7cm{=Hz0exck>jK+{BXn>smt{kwU!`C5*TMaW$`x^X2Imd4G|MU6Io4 zt#i5zgpGlStTN1a>mNDbImMbk3&RPK2n+KIiE<)?3b) zx>!&=Amsh=P#{O#FmCo&4b z-RE-QzvKNTcE(?QhIy^w+Bv@T!wBYT0ASO)XYCeaYX=}Wqk5#hok2L_Tz3t;;!R^} z35oNnE+U3_yD@Zjb0;v+BdLTSHuTWVQ-o{z(^B(u^X39ZRkZpREzO4Lu;T=Gwbv|J zr>`V2>3C}@a3lqqEfaiT7MTfXMQm}EW{FW|?vBNVeOfQ!+ugr~{qLs`7#+240!y@3zbQz=h?JIh=`lXH4szc40H;6O7-`F&Zm@hKfy`EaaL8WfXU3{d4+IO1!_y>NlnMnV^2DgBP% zrfQi2^PQMqjfo@)Q@H$F0`$bhn6IM*#sR7=^F&`2mVXS-nxxauasa4@#imlMLn-yzQh$e2(Fc+~b>}>_ie^{vTJo_v`NL=6eyj z@!r`|zimQWV!{hTcHARRTjUR}w6S zBLm;o6bib=dMpqgt4v4*t#~x6;>x{@`3RK<dL56LECIbw64Q_xA$Pd>9Hz~>TSSMQbga0mkCw8DlVH~2UG+Vr z2;TWa2dTl*n(PRAD^enPlVuBSw?_45Wf%So**|URQJ#G_x;=FGt)89OZ?y+Kq?~Jy z@d)5VyP!HJmCtI$W-bkSEi~WuU7xc_ZRu6OU0~Da65fWAoJ5XnV9Z@fA+s9^EWe8N zWd`D_U5O|$%W#pmh8*YZF13hxa84iw(3?(N6T^Wy$<1Skr%k;FtCVARf)9~S)5tqR zS-63(La$@2c!Pn1_|zd~yC^`)gr;J-xR9Z!mT!U6+cMq%MRgS#|I_LDYBE=sYzN{x zS6izNv&og`<+b-IhgzRO&{5v$6KFFaoljp8U)%ox6QxR~W6;JF{5s3eI7nP83+$V) z%sRK`0@1Sb`((c_0L|+ZjvsDq`2@#bfttmoGwQ<(?rV>_MBYt1=xU?I(#Y%pwJ}^0 zBm`IOJ8%R^OvI>k*Tv>Jq;wR4=q_O~IS#M2?%!uHOYQCU)s@(Y$Aj}WwU8UJ0pNrI zNi=@huQP63>@kB%HIDlcz09bHWI+RQDxophdkY0S{VW2DJMLfUH56bGZy~a=a<^(r znU0-J8nxHO$o-&`Jkm#>)8aduXRHStT07&xq$F1RXjyziRMA|Z$CcD8D>N)w67Sy)iC2;zR- z-vKab4mh!VD`Dl@kZQW=tKFK@XHSKCzO6TgC}j~ICEMjFvrs%4_>;KVAEQ3@j6sHD*y6Y zThd4zV4twfTY6ERcUQkb$-7ZOoaLgLl}c<&I#g5|!~GxqKUR-Oq!F5dKGh8Z26H;vI~x@RmlL9WmYiJ=Fdq~T_jM>W2NC;i^@uTU^`XnK zNf{czLgBhy=P8m-T&%?XIOZq~g=@Ad&_M(fv#FPc0hQO}bml;C0CS*l|D%bOlWsxI zZ$7-}ywToChQN{C+$6h#z5oQF=Oj92$3K7H0Qqax$qQBWc5!1d1Z_h~2=Uz0&Ah34 zY$abAyf#?YNuCwF`Dtk*ADa^whsMK9GW#pa#5XC$aa}z^t-wmuR ztXMUxb#PBCDVH56RCoE*Q$bI9(LzOSZ=-YB{*lxY8Jhoiq{k>&54t5jBxF@%M01(D zLqji$LX0ZLMta5M#MmnXy+m4s4z=%5vdAd4g>&xgx?i!FPO_i>R@&42j}{=u_`|}U z!UkLDe6i+zd24iz-Az;nYwOmyC_3bP)X$73y$Q048D(go5RS(&H&rvO24Fsky(FAO zCEx7uiPk~B{LMj~bT;@isYk884$pXl4crjl+JkYN|GX*l}BBow6Cs%eXEU=17XB~$#TZUz1d#Q@lfe&&8h zjr4Rri?7T!He0OlcK+lQgGT^xtT$}aV5mZ|mX3n@;LOBXo*je!A8DlOgvm$I)1?u~ za^OIF33Z@S+sBzW%8KzZYRtV~iQjrmR&Ao-pH!6E!Auq0<0XEtJ?eE#I@muAQ#s>O3moT(aDs zEaHw9Fiw>n(M5oNXHn7StZT0VuCi9NPU*h8WppOjZt7O9XzuBYx-jdTa*fO8*yk1} ze`$!5#rxMA$)iz1kTxLOCc)2s771oH63thNsmgs>^(nJA0o_s}laGYPgd)q&h!N*= z6V_WWXY@B^D$-s~Yn!sFSK#IeV{zp#G=!r2JOG~0UR5vi?4+`VEqn5Ir1uj%EGGxPJ$_O>F2XW=? zXwff2@7bvc=Y(H(dSS6Qrn=kQ#qD8UW!hUPZ_!r1JvG-xP+Ko=Azxb zx_pSmOfq_H0xuVmlPva%{QK(+hiw6g1dWc8R}B36l(8R0`5bO0aMhSu?5V9|`lO8v zruC;+^rvHwXP)6h85|P09x6q;6(uc-F1k_KY}$jj5s>$WYg|;{Q+3x!y5Ef@h)lev zBez@70Xp@2G=!fNT=qHwfkEyDzphOh?8_iyZve9C(mOO=#$BsoZ$%J&_*3PPbjOz8 z2#)}9tD=*)g`>9Q-r#szURvv&Bcme0enO7qKvf}h?upDrOf)W9?jcp;RAxlXJx|RJ zXD{4R%Im&PSM%YwGk?RkHxvm#hw%tOm)Y?Yk*XbWtGwPe8Kw7_(J!lZOT=}U3Wjw1SB*mo4pE?3a#6{d(~gVO);$Z z+h5++J~%LA2aZ;jZBCBm=msurWbJErQY{kFvES3xNbTULVR2)0qIt&@ZiYsX*w~Zt z6z+V-I!ut*X&d2hzmm?`djXmnNHz6+CY!jIXd z^*YLv3Wa>Xx=h`u)cU{cX8`=E-RFG$`M2DZ_}ay*KW>5${+_o73#Hlej&WZ6%3z^0 zYw2TZL{!`{9ZXT)<;go!~5Ec{b zqzq=qpECs`Y=RYbYSX^0c!WQB6k%w@4e#)?VliylEinH6lgyAz$YcGI$GpU2Q4YvHv0l&&e?9yAy5-Da|ZEX5PymqOaEL$eg7Kt$A-& zIJ@PWQEf}MO{W9rDpXJ957=_^uh&G0ffT^a)^O>Asv@4Rch_BM_+j~yECUhG*0k8t z6);q<$}`}vw9flJLOUhhZ5+C>iT)rqQ^gr_WESY zd0XUuOzFVG@zG)>QHrAkuI&6R%FGMfg~za4r+Si-7_3Whwr4mmvLbf!%y4@23ZUD? zJ=qZJ;fQQJjT}zosE%%Gtvy1~nZrYg!rIl=Fru7MRhOQ%vakYqP!RnLQyz|br5}z7 zTpMZOvKN^aw*E~Q)w@K$M`6Fiy#X&0s(wqq#zI)4!Ia7D{(^A&f6jl2(DBYcaM+1d zWgUTE5WppnI^#LzEe;_XRG9JDBCBeoFV}VZbrr`7P$np#w}?il-*Y}y;s}cv8!QB4 zSh{B^=@(&gn3lteBr9P=v4A9wz7IAIi`jajqV_S`6OW8isJhLCSUzJ7 zL>Ce^F%cFO!HY$J1lv${`c70@FH&Ulh>h%21z>)1FhLLAA6KC=p}Gn4uMP_`pE6GI zQT2y0|6cfU<aDYCO(+k(Trw5JMO zuTF2|eXeOa6Y4X(AG7>RkPC4R!hx=F7TguVpKfnvP$!IMp)Y`8xIFZ(^)jkYb^haI0i&&W0lyYYB`e_^igoqq?ZON8b6(_=-W z0?^4d=t4aP1M%)STAm>xCBzxB%^qVmwZ^N0rF3iIiere+g&c!S^g2Kyd5BR~HKsO=USpXOY&Ip+K~B4withdr*41?yNcIJEG_clcxeEL_vcQ4-y&V1&aygGt{;kJluV**f^X-yVDhG70VLd^0rD5`>6Ycp{a> z8|>X&4?#Z%wL=fVupSz-SYoo9fL~2NVv$8;n2fXl&9XXsOLHH!=P|RtcwFm)Fkxe^ zK9PLM+Mh|}Gq>6D)}+{U+dOE~!#f!>y(ykD`+o!a(4f)AnG0d~3aU4MGWg}Gyow_^ zdSF9IX0v`D=?55WWIuuZ?!NzreTqS`PwfEn6{%2fN)aGfSf{sCvfX->#|k9|s!30! z#Dh=OPV@o1l>!%>Efe;oX}qR%fzP%=R?wp0OQ9SzEHkAJqXSrktzYD537HXsq|=L7 z`B>2XFgmu0h!`+;ksWxAVU3t-L?I1ei^W=7|k4L7tUslu?>1 z=I&Xa@tITM6I#})Dn00s)yV||B}g}2xV>B499NMVo`*0;SDibLMViMaK#m%5pbwA8!l;`b?W;0`K5Eb6}B&y#Uq z#U6OhPz$0Fz**yaFs9I;7`kX6V-;)-P331I`*Hn=LP?`N88?qw)meRZeb`CLG-CT>ky>crpO*`5YU=NlW6Abit(|{S@cFoO0iM6Fx3s0D^QxF^h*Z1^40evnrBgx4 zvMUe_6Cu~WEj@o|Du3>B9{dS*{Ig7uIGjtvf>>pwY8ZHl(s%}t{EnNAX^;8haK=4S zS7p=|wj?XWNbn8Ip_|nF{r1tdHJl1m6cLDu}?} za`Trg4ucsB!!`Kob_Ezd;)DG*N19w~iT$3ku~bO?faO;wgGxK197Gud?o`jpZABN$ z|IpBdefKwbqa)mLRuD^U%Py@Wl<1$A4UH~SXwcYcryv;ORD`p}pv@HUbq1`q@+xaY zt`i$XRqO9*k6D-mRIKabYI#LLnr8Xyfq_Mx$&*LQ_E=02SRUA7EWee>aS;k5xZf%i zmpA)f`kj&~b7nBF|MGsT!5BxiT#QU#U(k(T*EO-Z#?Ov}wjXRFb~rrd(Ge~!{n%Q! z+y9Z%at7eLx1FrpwT#sCzxXl7f-?MJ-Hl>#LU3NJb3t!eryO~OCL)Ep14hy>wxEBE zGs1FyLsEgtwt_$vF|mHTRgwMQ8tbB95>;6XoDQrHYg`DptuV^RK`4?yLMCDabk6Kx z^-*~z0pIub4NM)XkQ5c-oillmz#XZU$rQ>RyEb9LEFQ1iiBr6hpQv@rlEHuOf+%T9 zP!-R56Q8{h&{gY&0Ppm|{B!zLN=Bx2cb;K3-{XUoYI{JaWrB`cCVwzKEVl(JC(H+4 zXO*gE8^fA0nd`HI#^b;Lyd>o1&Ov*JkJW%q<;HeIX_0!7qM}ju?Ca~r(MRd#*a%Qv zUtg{1;Kk6bNwUJJi+j4;>Xwts_AfmKyj1; z28qznP?k_##Up?z=b6PwRyf6iG5ah>%(biJif^tRJtMz~TQ7cK9B6_t_GLqk0R}nv zxbRt+VB~PO;@E2z9bomYS!^Mq1p^wmL5Ef5T`-hR=U&OD$V~-rvM~cmQ+MfcaAn@!dO2{tWVUXtx;HkRsi4U#A!6`gY7e}?Ko~Pey#Xm zGnUqo`PP~RkyNpV{3`iLF~u)YX}!;*_>$Lf)s%#{WT-8EM!M44IzBNYVi1z^>L0YJ zYSm_Y_07hw*V}CYNzhK!>{Qw@bL~8@$dFsqK~m9eNe+_|qnGtTD~d=c+R1!k4#?uWQ&?Z~{Sqq=6qK&Yu0`K@)u0&5N~o>=@*e zKDUI4;qG$p}DL_WdO&O|H(ioPyZ<&ZCD zas>k4jpd+Q>06SAM(~wP^l8x+6w>x2p{agr+Mx7lcovPB4pCua%j=R|%>W{gb96Zg z(?aliAiuiPnKg47z(#+5I?D#lTiE`zK{bOda$r}ulVNHw4HKFw{CnmX$FsG>M&JLS z{EoAc&?D|Q6fG6qGal1G;Wu`Mvs(M9}793&wwmMOL zO(E9(s;i#l^;h2Ufo)MgUT9PZ7Z6g-a+0{XtgqgnQ;VY1jaCc`zI6ObBG%j+?oxyQ zQi-7~S7zb9cj%0&d|T@8f=9!MHpTS~@%K@}G|nd30I4?JwY^pB?`TxNtTR*-3{ugp zF;sW7kbEQ6c6?VBuj}$cU-*~C5J&co4=O*(n1ytd|-k`0D}u1 z4U=-L!053xu2^^XOp;O&EKHs_Lp z+z4)0R*} z`mYAk+9V#6@;Silr)I?)=7Bg9tC{I`>tHXJmj;*$Z7Mi%RXa7;WC%!_ysiNw`!{|E zveg7No$9yU>2ojA!#InM-FC!S@mLOfY$B)@OxBoAbhN2gK22_b0e@Z4BhjYSBZ4Zz zNrC-imaO1yU*YvkTaoKN$C$N~gh0wNUhFpg@0*Y~`P}g9FLd$mR8s-aB(-6&x$mn2GhG>j!BnT}kR4hf#GV*LLy%~?|%HS$xFU7Ne;(klb z2!u}#Ms$8EsBo<0*u`xEsKrJxL@Fi}i{acyltR9}{HSb4nws!eh) z0^I{%Xk4+AQyoU{Lz)Hz3{`8?=nvU4;#5=#YRPH2q{7Im2_rD;6F9l{h|`&$mHl+iAnzQhsUx|do*PTbeiAr}3!ZNujcxDU4ft3a%)NcDMUVX|cKo(tni^V_F&nXyjPAeQd+4Ba5Z# zV4J|2V6snJi6zkygS37uj{49CToNHY_|p!MsRMa96Bi!dLe~sbW^F^Xmqa=BM)?{J zV44LD&H5p$zW$x<58j>{CbvW{!(x4#dv>;8lt$RjX7J>gyz0eeV#ClBOXA|U*LYcO zOjU~sZBzN&Tm6=KD&VXj*&vcUu|{Z8-v{tW({_arlhQoAsuE_$sQnZItb4=wtFn1@7 ztNTmrpY>{BJHJ-A0q3z}NWLH?vkWCJ7){2+#(>E~ z+Kg`me~><9!xiY)`3JLgd~#-lFW2~Dd4&aqFvNP4&f_63q}7upr<_*V3tIJYgNSW@ z5}oh#=C%{v2@dECPdSL|>;e})aO5eIddTc*Vly!DRRmAT&~TIPIG9Wi?JVFKo_z9W zZ8j!JSMtczKpFt42u33z`9h||jAYiNL-Al1bbM?s)v2{Jbjhd`x$#hNfF^AUCH9e%Yo_onbZIm2>vd*&E-cq_J(T}M@W)KyU`P`L=T_DZ4N(3 zuN~$U&|(&_?FemEaTOfmQ=RS6ddBkV01dKCC;rA(iak>LGoSO-yNhkP!jNGUPB zmXhM1r(fKs3`WF6`>$*yK~=JG9f79bk*_onz^V?eQKKE^njy+0p(vRpt)67TbEny4O_S!oz677|{` zxnyX9jIz+rNx8d=AJ4@g@;Cc7)eULh+^iK`>+eMEBtV}F+M%_hDDV-KZZALv(+f{)f zC`Kv{nc|pJ+faf4Bgl%oll!0Gj1Im1#%J_ZWQ=(({B1l7dw&e?#O5j?dM{&2#%W-2G2C#I36T4#NwVklDh2F)`v;m>x(=3Gv=-$7?H80D(JD+IhXK2R zfli5183n>Md#{(f$n_y+AX{d&4}J~`6ut?$?TO^-s;oGC2-GeRzfmWKU<$`M zl|k!rLqpY}wzzKI1@GY|^4^qTmv9gvGr?6lWjx`cPAWcgl9c8{0sDiRCp;7Wy$7cw zQb1l?_(nj%_nL}#pzIlt>HLQvS8NX{SEsfrqXi^#j@?Ra_2*-ISz>*dI~?jN`Z?5gxD}BbM+_@t5GIG9bK1h6`Bx(e6YAYK zzI?Z}V;K>+Sd`Z;!nt`ZGu0zl0lqzIU^dYc7{Oju+SpK6WTe#*A&CSo1goztQ5ux5 z^7%rlK#v)1wMUGxHI>bwzA~m`14rG~|GM>M!yYN}? z<<4a3Y=!Q}`|Hg?xw~uUnzVJ!f!@xT0`~% zW`DWezAulZniH8hm_CMvy#VlsQD@Y68|WT>+HlV>Kz=6p%$8??0zp<7F`QG2{=yXdm0Wsp3b zP$D`ARc!iufAa{tX^Q_i*Pf*&_Ros>>hW?n^C|YfMci+IkGGRo;=p8dC*}A4(5wF7 zbvLj^5~E+D^g~V&S6Fr6!k)Yi@5xs3w~rr|Nya#vz59yH_PLme-G|&Frq)=9kdLXM zAA1x#=IC55HotScp0^Hx zDL}uK=cji$ldQL)JI;!bd6GAKx;Ps~Ny1PZ#!+{Z-?K2o5L}|hmEG+FWv6M;NS2SA zM$@7-b>r#;AA?m-a;}NOJdqh*l*vxvG`yz<-s-Hdg+n|EV(R8o(RL@MNDcsO9Hw|H zdB+=Gvohqfem`V#6aVG<)JDb=hJTcrJbzXAL-d*brGIEvSUGY!`RC>3Z8ge{>4rn3 zTmHMnYSq!f@-936+-gZ{;e1oQSLbjj@?ke?Jx*`CtLbk2AEkwm$AE>vQc+i&&Eu4u z>24(9@eYIRUxxdwrbY^HG+4IIB-7iRbB|L>(R#jwI`kUf;2}`XY9;xF=Tw zj)ox_7GoWv9qtfM^QY>&fznEd<-9PDz1s`vfT!K|+HRZ6@W=lu**zmG>2GeP1>|l| zN4psvJ(FfAgcLZ%lQLa>19$7qw2uqILV|9`&hr|bQ+4UseutbocV8oqtWz)MrvbmZs6)-_8~S{H}vc7xS$8(&jL?$lw09sNVv!;^sMl z(=cRL&3m(_Vr8vDC<|R^_YyhiZ@28*-yppTq>$pt*A!K8b!ZX`2Q6wtBn<}|fJbQyAgQlEBp(fMj)Af@~MZ};O~_>Yj~+na4NGBS_R7pPx8 z-lfT$mWDrFtvo%3cRb!s>&e~jU=np4CsTHv71%ud(|HW7ZEfwl@(Mfqkb_oo6vn`L zdy-a&4SzhJ#%2gP-a{khIk;`TUDbO!PuUK)wETI7@H(D3f2b@3ha+t^_Ie9X$5tLM z?`SW}bC&=94ZC2+x$Yabv21^x;!ZV`r`5n& z?T77Ti+JwYuS-qt2XRVzDfHB#uICH~4d*>OpY+~vgXL5UZ!e5i=LN#Ahtk5%&sMr0 z+iY1$0jFrs{Px5J9^yhDdP>t|Z~a4%WN%!3kX{MT`AJqIu|I}AT**C6rqRFIjF;

!LPr1tSZ>L++57EKf?Zp`oBE^|J)zP`xdF)Um-DgP}~K|3H)#O!$S9i zRM(Vn`0l!=3)#=`!tLweqi7x(JzC5Q(~lqIu7g~Ees+ADOex@6%syqO$*0Bh;rUm~ zZ`*~1H*#;>cFj}mJH}(|&;-TcV$cM%KVW+Q8z)i%tjR=MON4n~un*1Fvi^C;aS2fGtNn;epw*m_a}Q zKIZ-xO5PQ3oUP2dSn=mIG)9)^ox{B&H%D1NpIH Date: Mon, 5 Feb 2024 11:07:44 +0400 Subject: [PATCH 117/200] iamge proportions --- doc/source/api-reference/qibo.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 688e94d73b..2058f41b26 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -300,8 +300,8 @@ For instance, the following two circuit generations are equivalent: .. image:: ../_static/phase_encoder.png - :width: 1164px - :height: 670px + :width: 2000px + :height: 2329px :scale: 30 % :align: center From b14b1cc594c5893cbbd74ab8feae263e0c966971 Mon Sep 17 00:00:00 2001 From: Canoming Date: Mon, 5 Feb 2024 16:06:39 +0800 Subject: [PATCH 118/200] minor fix: [@BrunoLiegiBastonLiegi](https://github.com/qiboteam/qibo/pull/1137#discussion_r1475722863) --- src/qibo/quantum_info/quantum_networks.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index af549a46fa..89c9a6a8e2 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -42,7 +42,7 @@ def __init__( self.partition = partition self.system_output = system_output self._pure = pure - self._backend = backend + self._backend = backend if backend is not None else GlobalBackend() self.dims = reduce(mul, self.partition) self._set_tensor_and_parameters() @@ -211,7 +211,7 @@ def causal( return float(norm) <= precision_tol def positive_semidefinite(self, precision_tol: float = 1e-8): - """Returns bool indicating if Choi operator :math:`\\mathcal{E}` of the networn is positive-semidefinite. + """Returns bool indicating if Choi operator :math:`\\mathcal{E}` of the network is positive-semidefinite. Args: precision_tol (float, optional): threshold value used to check if eigenvalues of @@ -478,20 +478,12 @@ def __truediv__(self, number: Union[float, int]): "It is not possible to divide a ``QuantumNetwork`` by a non-scalar.", ) - if self.pure() and number > 0.0: - return QuantumNetwork( - self.matrix(backend=self._backend) / np.sqrt(number), - partition=self.partition, - system_output=self.system_output, - pure=True, - backend=self._backend, - ) - + number = np.sqrt(number) if self.pure() and number > 0.0 else number return QuantumNetwork( self.matrix(backend=self._backend) / number, partition=self.partition, system_output=self.system_output, - pure=False, + pure=self.pure(), backend=self._backend, ) From 9b1634e400d3c7c47afa1bba19531bef45739f13 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 5 Feb 2024 12:12:27 +0400 Subject: [PATCH 119/200] image for `comp_basis_encoder` --- doc/source/_static/comp_basis_encoder.png | Bin 0 -> 272260 bytes doc/source/api-reference/qibo.rst | 7 +++++++ 2 files changed, 7 insertions(+) create mode 100644 doc/source/_static/comp_basis_encoder.png diff --git a/doc/source/_static/comp_basis_encoder.png b/doc/source/_static/comp_basis_encoder.png new file mode 100644 index 0000000000000000000000000000000000000000..eb021395346b5f82426bdef2ff3888e350c4b76b GIT binary patch literal 272260 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 R%=R0WnV_b&{s9r z&u~@>s=Q9eEsH>{D&?tl1XHbZ7nLj)L>`o{lqYJ%iZgp|Y1miB8W2Wads36u%V}i!u<% z$mG!OY(kGm>Z~{|+}#R5mjgl6-*t=m5Vuu)z);itqbT-bUHNBw=l=sylwLR3xFeIV zVs%4l?vNtWWl+zPOuNa(zfI5g_@sK2p?!i9i!6|%TDtPvtgEyz_tjSE$JJk=P*ru^ zcnS#rv@g{Ls)OLf!Ow#~%~`7~_2W!+I@Y8G?o=)|F$GGYR#u4yHw<5H%?_HEj_e1u z^cSd(oW?bSQq65g;m+GqEw!^Q6E>xw=FeU?s9=xrSZOQIA#tqb<5*ALF#!eJ-lU@F zFAB%QkoN4yhz(a!D2mNUP*b@AEjtR>Zg~A-NqPWn#)>2NRKY|#9j9%r(%EG08R;W3 z2nxwuGfJ9#E!)M0e(FgI`ohu@9%nz@1^{1QDMu%@!}`R8)V5X=b%OMth$7kM%h;%^ z-M?PK>0j`l4i_?k??df0*qr9giYV~)id4--^wi>ruXiX>*r`WtBi`wrzNP;h`ld1hIOaE)$ag7;?W^rO_)n`->_x(kKU5bWdG%ET;M2PC_JE z%5l&%?GDfa32VR?>no9ez@fTBD?oa6`mBwt|E_^pKB@SQ*)^jqqF*Obl}{s&EsFUI zE1V~iY>Ziuws?6vFM})|y91EDsf}4vbr8KQUQM8EXKIeke!VM~5v@nlkk*$>LC~lR ziWPh9*L1PeWxMq%)`0kd86fd;6F6IND`rG6;M(Tr%~g=_`5iG%8PltKy_NZWt~kA! z3xm5r-7lA?teb9a?r+bbl*bb_+kal$P6!|YK@r;JC2OmL);k7A6{|w6fr1>*d1eh? zWLBW|ffu`y-oUiK>|XI8bI7-WD`sx6(W*&$KKLm(8dIq?hL^2a`pvZ{c&7kQH=r8A zOXTc8+6y+`)63$P-VS zg;&a%b!XMz$hX!PXJ~(sx3A7m?IsUo{n;$x_F>~H)xN2NZy`{goaS7*e&7I88Nk5x zK8h8fh6X?X??}>TPub=@n+OaOQqb*=w(a10X~dyh63>Xt_Axo-NbtVLPDIos zBc`irkqLgPESxf~C_XecZLfYHiImE}tDy)eD9*6T>@`g-~jb#k>POJQD!boap6yfSX}Gc3H{0V%gyuaF!*1#$?rcd5;zy@+q3#J zA%K1aIn&|xrruvpKR{{n-gAJ(0~Tbf4?-nV;9ooh5H|bww|w%7Rs%6K&P(FB69Eqo z*behQms$kVvT@y{8o^KKXGR2hh$AAW2@Hz~rAP|{fo-sb|ns3c5+?|i>_o6kkz zTS?pow$GhV_N1_;3=8AXFAApBwOg|r?w8VFh8imVupwErkC>`f_Qv&noS8*lLAgKo zJE0zMs4bPrT~hKrmGM1UVb>(CaDpai5p&y2zw!#PAGrK-?T#UOJw3SmEP(1=r1uQ2 zSorfP^~0J(19t4}h05(utOi&%FOY~M(C)}8JD?E z%1V+jYwsslDg>|vb$~0@e||uA?UB!#((fIeg)E>X1kF&*hn+&y^fRX9ioe%mT8m^% ztMQ8ZuRn(|e6PmWn>e!%plN#eEm^paszV+=00s@+PWu;oN#_Db9qg^aB(F*JxpCVV zL=S@|*#9ATAjYp}t5^8E?C&vlKQj3VHMyA>UN!<7o1% zN%S58G|hy-h&)k0wAlrb9FPh1kYd&4S1=M~i?xjGO%_js;%m}}zjjQC|B|2fE3s;Q zkoxsmXK5D|*Xl)e=lR|ZwdVo*JsQdO(bY6_#;VZ#nv$e zhyS32U4;g`S#HHEF7wajvHEKdT#ey=Ox-yaoM;dKZ8Yl!QuY8}aPZfS0bSSKUo`L8`xpQuQDFWdqb_fU}*-9DptC7tTr8y*g+^P4#O4Zb`d|Ll~g94^N91 ze*oEiOd)pXH|O`4u+Fj^(bI3Z3x7jHc5ndwAQU`_bUFM@7M>osryN{vi6j4V9x_}i zci5|I8nmMEr1KX`eES;sd7nqt+ENzilQPA3vL3x-G*4tq zI=bTPbN;7%ImFAur45ek(ng(j1L+`Tx^qfRy+kjaeI)tpYo*WGL)Zu=>!5rDy@h@b zl2HS=br3G8Eq_34=2;c`#s+r6v3<#lq(BY1AB5uvum}*vo0jGN62#& z;cSZaIZ<}&Le$dwOK8({rlISwfP4nK6no^RT)2)J*+0Fiy|G=wqmJmS((QfS(|hXlnhq5Nz_s9SioKKoWjmc7pN$!UwmEFm& z0u7R2R=HUx1p=y3BhHm{diFZ+3nXu>HSfaG=K9`(U_QrY0(EV6fRQ25X3@+@?fe&x zK*fh4m$>HR|9Y~Hn%lEkMCIag0L`6m!7GPJAmo?mqi}lZ4KV0`%(n>PQZLe~H1)8a zslWzyC!7o~Td-*AO+Ef{b_0DAD+$#WClUE{I|3T-K^Bk$Oyz;vxmO6Cy6hKs9prTt z#gb20ecY;9@1_oG^90AI=ZT9q?+vE`?RF_Jm}E0+ z`j@ABqXOpY5&)S8{#x3WD%OAE5lLnkbx7DCdx&EE^9dOZeb5i^)T5tL%-5a;&ntMS zqIEa>{ib7HejxlaZTD1}>gXgYyREwakYY4Ky0xp8r_1IkZ)8nRj#TMFjp=sBa)9UE z;{~?~U_z?V;5cC-L5Vk zU)yz*ELu`z=;Zy|7+3uVD%slG2*m1D##TKx(*tZyhKoCagvzq@2i^u&cjhV|S`0qn z1fuX1!i=tW$_I%Cc3B>3kr0{@kG;nq-Qp0dQp!g{fv4hB*!AMXmEkhKV6tdW1O(za zWF*p{YU+LCQ^X@RDsfHc1Qf{JUv(ohPr1fx!_2$$65uXWZof@+?*u!UaykjO3(4pH-M1ynV}q0cyWTc`^b9|5+Lv^0Io9=Vsy!Hqsgge4zjyTth0$Y~ zrK`G*Z9mdDs5Dfr>O#xmyhbD}lSP>&UHe5A0JZ>jYRB*y`wnKx!`7D@5O)V&iz)A7 z-BakLDG7G0l<@wR)&~T;PEVh5FKx`RVAGvLz4!~t00+_ue5D!H@Jk_-?^u&u|`Hu5%lGNA<>2E65nH zL1ZsoQu+`5N|AEQpN(Miy5ZMqD2^@BpIaF5kl;3#2;t7H`+6M&WkI^OxAf`zLvr1y z3fKvoqExt1ex0mAY1p-69k_cXqHoM;yGek42_fc2R_%$Lt=ULmU(Kelw(4uKxSZ+| z^+$-^U-GX_V;N^?569*CPTp&^3$Gg~t=n-%p-wanWb(i^U0 z;ZCF3Kdr7w=*rd9gQ!#;*H?^Z08$ zzk=dMK{oA5GZJ3wl=h=_qH<49;1-rS@>$J1Mu|&F=rn|i1Ou|wse_QzmA(D@5<((8 z6s-OG3MqcGzpVienOfweKmg!^#w6@Ya!~uJa5#k7{;NM|*=x<4yKuq0oQB<>ROx_6 zuHl$-oFlB{yisrO=PSM<)wa#{sV8109Aes){rroDY^dAAi-I<5s zPRT)|iq|?fosnl&kL%aA`;vZVVL~hwCFM&qzjgoF`*lsiGs;_V-P>-D;n%YzGiS3~ zUG=#eRt}`8)ZYYZtX7OFb|mnaA5@r72L_QaVJ2*I93#JXs!1EQ7XN{LwrlL#+?v^g zG3!IBhqL>AwZyvOm9*?nKB?Nxu-C2EkF#)`dSlG|z${Zg;GmW5R{`JYM?Q$=35}LNAe-sndDILv6nwvHZHW9I z(2xc0|I}zZ67Gnq{XUn}wp1tnGfns;ZK$yoKjL6x(TfY#1Y=TN1p0CQ(=nCUFRB6` zJ+?>JaR263#W7@>J?H}V891|90yzFO!$&5~q;hlQB&_JW>6fEsKFMARHhj>EwU^v~ ztlr3$D^A$Xk%+FNo~f1|sHlWK-0kNOXes!XDQ+nNUEp1tT`?!UwDku4`)63vw1qz~ z4Mdj46lK-%2Mmnf#O6btvn`!jzmP~-qH|IVELUlJd3#;$?bhrsdiesO2wl`}|J>f8 zh`Ak@gnfF3+rPGE?7r6K6$Ev^V7CQ4MbleWeI{=vyxN{wU(VO)U<9Cv{+ax? zZ}jT0N@?L%8=z#pe*2*^=R3$d>WIBamui}S3BAFIy**uAN%5+~A`m`Mkrx%kMmc77 zdZP`*8$%xevU`*3saYWy{uIE5bwzQ_7Z=XNnCA;_G&fh)H{=t-=QcN!Ad%OU67iEK z4kQ_MpTCi=TeL;cI|+!}_F3`+ZJ6bp=)}CG;CHxpBCu{{-z&t=*BxVM!nJ~6;yzV%B|AQJ0sk_fLC}>VG;CH&SHd zd1wPl;J4AT7#Zt*hQvNA70c>iJ z-i%L=P{anaPBT;$ICP}gQ~2I&W4vAC32d$pboqdoy%t5)K<0Oxe&DeQ$2f5;{n)-| z8^o)MJ>X(Jqibvh(_e|V>J)7%2ig~CSdhXOwxNl#>vRiOcaUgk#pO{h-H0vfP3g12K0)z4a4h+4*LXr-Wq{t$TX%)=|Xld>1WZ! z3(^~bkAl~VY6LQ&V%J;nmV3T*ofiEgA_RAMF5GY~% zi9tOeeaf8sg53mWpNC}Y(VjSBwq1Fe(FoPzKrKCMEI56ig{$K5=;QgkEd8`5W>ZAf z(ApgKd&v)X<**1F{RauK4+AHx_q@&LumkE0MFyW|87A}@zh$23V3TYM^*tqwm&Ir> z(RL{iPY*9{I|GqcnCnnzkZfEv_18|G>U54FkR&l8mX)Uq+@)het) zD%S#E`(7l^2rTtjFbM4ReM3w3?d?ukuQZe_5VN;@FDTeM#;EGCtOw3clyO8Zd$KfAe^VBKTd8Q6eSN2}WvxFWRTE4~-c%QXQGsY@EPBSk2$BXi*hw+ze zGfBPmA7dA0^)QQ%O_~qfxY4` z7n>~9QCc=Zwos#zoBF=x=eRi1KGJ8ZGLO3CuE>UG-dCq3=^X@?LZ@qcyA2IP-fTKX z)6SRSHQa{aML4hqfK9LTL66%_ECaN&AC~bx_Bf? zIfzf$W19ESNF%$1j;z9{FWg-@h#q#6 zCzakcI{uu<;xU>0TjqH=CXa)vouQ379%;T?Fz3>GS>nR-{F>UZ*R{nfZdrc1DU6^) zUo=>}kw?rpuUaT97c`%88-r4Mf$hlJQ|Od=l-2{M^b|X3`u~7rXbOZs%5h8Py}@8{ zA#L{L)?DB5`|7v@#J|F|ERoz5Avo^nwdR)@?Yp%1+&z>plWgXubLB#zchHzV;i+liCz+L#Ej4RwTzOK5u3}7=K^G zU&KlM8E|Du| zZc}gA9Bvlzj`kni!>=d**NH4O?Np>E3oN7PItIaGgGBf6YrTfPSHr2J^NRcQFSz~? znqL}1!^nu^9}-WE=Gn?qXGbixy##Rpt}{s7&tVkf1%S#9~rpk5l9Lt1^1BfSrNuzSFzA14V(e_Jo7Q zx5n~BKRF>{Ztf>(-M!Dm#V>iOC0kV^Q0;CrQ^#}fXx`$(WcPV1Dm}R@l?u$f~(m- z7_7}VR=q=!3I(`cLAB|ssSBYeZBHIR)vJY0K^-zUrXN5430yE0;j4P-C7o4wuMNCk zb@qi@OXh&9Sjs^oq_NueQnt*j0BJ6n5wH3hi(Od}b~r0hOn&}vk$Gu>|9JMMd$kG{|Fz*`RGlK~6^w$QW3DiGMAZRTuo;GSJua3_ zc=Q*Km-SJ@Xf=udN&DVEz~s$E$&7l%$rO{yc7ND!V>E}ZcOL4AnFLYvqvc`g(1?Ck zp>ZicT5$-I9OkeQ@_PHs4Q&d`BG93_y}*5yWvWt5bJO{-iuJ%*gf;xDNBUr+3i5-S zZ4N%r>}3lzHX*xdmQM3(^WEh;?;XbW(5fm1H-sJb*|ZO_ie7qU-*+7}|3t4+)T9s3 zKYS<<)E{TRJl(D&6i}}s9n(n_i4sDmWFBo^k8u-!D19HWWus+l*3L#B%qF=GM@KU^ zHzNd;3_%Gn3ylp_eMD-H=#sHqg6(3Z&L}SqN06Or$Qv;<(^GV>j(4E3Ey|SlRWHMw zvFB<6Xt@k+-FDZLm_G5i zq|Cn0MI2(R#b-8=LC)Hp4lmw&H;(u>;{^zJz31uuP5yd(RSBOaQZ%Mg|KV0y{UY* zFh$p-^jZujd5d%5&$j&VclqB#;V}lu-3CnHhgW-nxP!)@9UY&C%vPQHdL`?!Q?5V= zzNo`lRm`2nG^$;57YNf1Y)L>nf*Z+CROst|1UG=RX7PVWL9mDiSG(G(ULENZtrb)X) zgt+i*hYsZ|r0Jx(^E_@L`JmQwK(uaLtRZ6R_Y|$UzC}5}kZ^P-s*tFZdbf5ght-kT zJS?rQPR>Mn{^Z?BJ%+fiFT?{M0#<|Ph@ z?=Fb%wQ{L?>G!m5ht`cL(e(tagUO(*5TA1&{Ii)&_~@4F+VC+g3gsMTye2l>{_r>8 z6Ad_ucI3rM&Tg+^lVHbxf1YP07gz32{iy5|+4O!VNnQ}Xns{u`{7#`vt*YV48SIah zMSE!=-~6-*>rEpkK5C5>5Jz39E5)8BtDaT@4Yl#R3@0wOdr_lS;aBHdgyYzk@TH-r z%4&o2B}?CRK5G_bP#Z@o<&BzCc$>`|UP^-*s%xx&^Mk3lcxxqeO=>x9`gCkwC8tgs zRtjIVVUyR~y!Z;O^}Wb3D5JKU5$0e{cXM8LJaW@1>g)&JJ!loBGrR$BFuC=K|I)D? zZ~#nRvftFcl68)hpTUk3VIYP$=ym3N`oa77^Y{WCAd!!3MrT*Nc&cZ8XB*^LotJkx zF*vki+~TW$vq8Lzpc{|7ifw{?aH6V5Chf8;FjZxzS+Qss z;@R=*(as!+3~h9vp>a+B)k(Q=g#X$2N5_?~FXl*CwbB8u!)AF18y|71b-K-f;NAwF z22&j}5s20({;Oh{v@8+lCiaN9gYAwU9n`dpmk+tS)$H1Zsj-a$invZJ3m%-Is2-ld9 zMBBAi04#Qcpd#ZKxcv7^b^L2q6 zy{Em}V#V-g1!AXe`19YFiTdAwNMhf9D4kKetDv{Qsf;gL-ogI*t;5yBarp$&w@C`9z9s^ zE`VcIAwPcJTry2+(VMfzD10#R05^c@o?N5Ge3W2rhD2XDF6bgauUE>)jQv(+!|aHL zzPoAK&3R(EK5Tm4>dw5GhDZlP?VH|kFGq<#~=#wEcreJ z6P>_^WV+TGp2yM@3Hhe;l($`O=QI5H%4FjI*CP#&oS4$y zbh-k&IjTO!nxm0CHHL8I)L7%TVvF&~d^Fm68khK>QMlFB0E<+_TawB+ZcaZ{!i&D4 zV`FFctK%Aoei2z_|11vG4NI0hqZeT7Az`<0_j1pMskVnI7dgfm9N_L;^Q zBPKQRFP3dcNn^r5{=zqzlHK!44168^>~ZtCr}%C7>Z%?x!nlo-526P-ZmhTxnr-yH|JYyz14{lxzL?YV7mj9>7w};RcztuUDybfZXN4#EwAfu!Mc>> z-P|i;YU4g7J<9ebo8xciX9*uzXHz~8S-9D=&2aFgA8TA;_L(mpSg!Rz-xrPz6mdDS zF<(lE6mqqG^u=a{m92cSko@D2^%c#OQ4u?HbDF7gU@S6L zp6JipN3dlgVvzoeh7PO@azw54dwxn% z*N-ZCCVBq-l4&N{Z>vZ(UvaOltVmhDxp)iB?e zZsS`32mNQ=#Ro2{;$#s*QOIsLN?<#ZmSOhgY%6zWDi$EZe`D{@Y>SMo<&~3+E|9Pc zrJWn!Y05*1u^Rd<%u;^+l8~I6OToFv(J8zu|7UB`G&(BzZb0oDL3tSgXB7ERD3{{C zJugFIF>o^Jy5qb_$EwTIb%Bqm=h4}REx|s8)czc6%9H!;z4?{II(-bo{%@Vm7h9&) zm!%7z4FYVxzh#nlETsaxQs~)k+h(6-XJ<#r#pMlfE#I$AO)B6_ zx@I823neK{7(LjNHVsMtIu31$C)S})lFLe3`ka>j4kgG z(*G>uylIDy{X1fBfHi1#)V!+<`a@VpR2e1e@&_(we5AGW9jpn9VT(0A>(hvhJL~J5 z`wJXK z@!rxyl<1!~01@-Qf|QygYC6(EXBN-ti@JV}!WQ4+zq~HoA4E!iP14TvQ((yKr<{nj z4lSiFo#DQo2Or-4?*4P1I-J4}n>*zx_9{6A&FNgxBs(1svc^un*?iQ9b&fsvw( z!5|XH#_Wh9CQdCE>aPSE8tw0_1S#-_b}kjhc<_A&WsInk+1os%(zJ>KcIaEBEZl>~ zs$~p)=Ea|}Djo{CV2+FmN3yWS#S%itC+%8 zlD?~^Mk)`x{Egnk7vNQ+3HnV_B4`P?-Dy_GEJ8rWQrQ*BDR}CQ9f+?EO=%pb{!}&QIQRtv)T^O34@qHg3xK z1Wc%tD^^Bjnssy?P3V`~r0p?c9&bk}|E|@k{PI6(+5wiO;spjOg%(@*GYsZFeStdV zC>}}Y*0~FMXfs`(9!=d#JjGx$d+Ax~R}@VjeP$`XKLiGpk2!hqM(LJD*NM(AiRoY` zJf;4GmmREtqbkNEx6$iatCAgMmX~5I%1-sjSek)sY5ZvEx!c>HEaw%nadXX1rTD#8 z?7waGORv&&3hbz@JP37}Ba)k@mYg7`L;Ky9L;SGkYD{jj-GZ{Hc3 z$9%It%_7kSV-Tp-d|C3MdOVF;5Y18B_SBgCQA(qime=Ch)k_tUfFO9&xZ)eknNyiz zXX&oltk=oqyCIkoT%an9;cV_#0b=gjo zne-@%2z-0s$U!}M`QB!`S^{0L)b?Dk=t?2BUTcgfd!C z&!^KtDeV4^y6!L!Ol}A60{s3Y`*r%=RNN5*OxioMZco_II`(c!dEvwZnx5mnYnV6RUJOLps}ecVlbGaG7UX9*1whWy$mGb}|UpJhZ&buY5{aQ;H1 z&l~x0e47XCS`6(_}X0-ptaT|HX7&pb=Audvg|>&~wP0=^h? zTQ+a9)YH9$$z5tH0!7g4&pnKLQYEnUNx3&8v7))Olh2(7X#bQVz2*y~5hPkY9CMBw zdV=MwCpJEd@WqPrZ%8=qISSkzZfM#z*BpMl@#!8B27r#8DvXYW@K*n2vE=O<%a6B!A|YhC!9)r%oQRbM6^;Nz!^ z2$vhJH7j6(jJvY$o5!58#1X?C4zin11el8i%H3H(a zhuhPT^WD^o*y34?C4*R{0^sXer*m{trAFT$@;pYN$2u7;J1!vIWcVV`V{&pHK1I-S zTgZ^kk)ATwu)N1R)omy-+`3yeBDOg|wI~(44;h=q6f^l!ytICV&RAaI-q@BlK>a0b zV;0ry9$J6D53W;d07zvg5CAShgW~nz&uotF%jWGY%WH)9SoD8a8$Oav$U~?cHQ3kp z6{~@f&r4?gTHPY}$C;OrM`irVJ_ekuz`er;T0`i^iinTnQs{Xh<={hu7Q6lIng|_T zL_!aBMu)DS4x}}=hE-%EI*2AgUB!0We`=O~r6Mw+jaJXD=cA=)0(wWqXv$5uN)oMMrUvUZzlV*v1fd#^DhJw`}{t z#@IP0-_>op7_jl2^v)>xhPJCzu>APXJ8TvcmEYLIt7$I3*k3} zRp8|IqCq5>vqvu2z>;3Km$P8&eFIcf=xI7w`;AesQ8YI|TbAC;8KVN<(8q-M z0?UF85LZ1B^9ndS-(z3~>rrNd^P<%N-mOj6#$}ZbybSGU7VsLYg?54IimUo8Wh){o zX+3Tlhd+wh%L#3Uux&#RGXth$SGV|VY4=h(DBQ^7=B(L}20_{h=PTvDnYCediwz=c z@>mbFndVn=;2wf59hyo%8*I<_T{kV7qC8ta!AWRp%e64fVAZFATlq$1A>}H-7;!E1 ze2VW#Q ztA&gxzL69+i#n@6lE^>4&7uF;^xc1Lx-xgAR*2Af_~)lIbN$^=9dJmMb|tong1juZ zxWSS9mGz}3bv=;Qz~;dd%x{W>p)7>NJYYiV2LYo-axd~9A{Etgz?`$*bJK#dXDVOF z_$r2I+dko!N|^Kr>|b|_Zqgj?$bTfioNOJaloAXSqXf*ggvTtmK{;v%Y1ZS5wvDxY zMDiQWPj=~xU*JIPymD_#5Dh`ZV?*N0a>L=0M(qsyWU4i=8ROvhx>a6ch+Cu}T?Y+t zw?aB;K&;{k`qC3v>{XrfW2fok%#yDB0abRGlWuu-g1TX1T4Q)e>*|%scUS!)aaFVM(za2D92NIIq{V-7jS!_@ z#*#TOBxAn6|9c(uc(kCOUo~nW)AuVbUM=RBNMX23Mu%b-7$!wrB__i}P@RE*Cqx~_ zf+t0JRbQIuxx(k_Za%3+bzAWw;6bElbYwa~NpSFeyOWg9bCVop?|z0V7sBrU%Q z>Pv6as>-pxGVFG-@9MgF$uC}v(Dxo0)$C51vnARb@&jJcs2rEH<5UB`7(c9TK0jeW zTTBA4_j|fQKX6^Kz%smqs;2TtSBLdlM5lmIxArTy)@f*Nahv}WkhgJ$h&dW`)%Yqq zA#N)Wi0)4vnfjnIDmfmEu#EJ~6!JvS!0j@Wsg9qUB~Z&DPc3Bk=lXuGE-XSCBJf+> zVkBbFS`LUq_x_J7@FMw-IdvRc0mO(&!gG|9F&fG>H}{&|&EBpNIt-l-Pll=}vA?z@ zWqVGprpRS&sHZ(wsNVl})~!}0{HWNz9#?GF=(|}KF33kti5T4hx0Usa_=khvxqHKq z^j$i;$S)xWLS_)_u*8F=~ zk9}`R9}mDG_fKa3ou{5WX*{4MsxYuLNky8Pn!GQ}7HwVb^^Lznh3SXxmEQ2n(*v@% zJ{A&5)MJ{TRrfz7`ZDAV*BBX+#uvUX;Q=)JmM3v*)X|P}W>_>$3yC(1Jl|-L?0_5= z9m$4B#a?O+m;HSDu@Nks3>AZgjuH%dHm=#&?7ZhUR#eqZ zR8m>8NaTpK`b1H)6NxY<_gbIp2a!|7zO#8}^7y#&RaRWdO@8e;ds~c9`l{Z1d>8r%6!}GvUZnOcYDR-e7q z?l4k=8SUqQRKxvMpl|Gs9Ro`uzJjjTjBP=@6h$2bQl8C?;7K=u!ZJT1H$^Dk&ph3I z0n#kZ2O1``X~Xk>#^qNZFw-KZ9~`O9IkiM_876$ktD5WJ2&jZjsb+7L($^N8KAJeB zW`iL|S|gf#uUZ*){EmypxHbntqYWFvHZJW(fc2EwB(pHw{GTHNY!yAj|Hso3hTjR} z{lB6YZX5paO4<}5_=@jIYw6WgxZ=0l`DcN}5uZ|c0Q=8Qh8H+?ks7^6Z?V|EstLA5 zi#J&cnYUhGiOOjASn_@=?x>%dtgWMBdqLcXBsp*CC>&lqoWTN=5i0kwTT{l&SQ0k# zdE`vSzV7ZPkE26UM|1Bh{v_U9n8#kQEE=^T9eV9wCmjX4euwQ=CpAKr;*)-yA;!Zi z=&8{dRCdcVL%UO@H7zx4rk`UTw(`uOufg2HvFr#3@DTZW337LMGQ4zX`KYVNL=utZ zBjo!Wsb`GoW%0G)hgNRT7tYPdl#-D(o>GG>h+4feV_u!`JEv=R-^W6gh%iT~1w_*W z@tAqL=PsM;BUOwZA=GRYuiN3iio-|W-#)Tm6=35PVEhM8byl$a&FB90oSoF`o}^A| z&&&1a9eEc)CkV=DITg(uP;bL`u>&%hx%&K+fswuio9;6Fm-$B2PbM>}x1H(t_}m-Z zX2rbIn^VifV&hW-_38ndQV`3-W5bQc~nzQ+rg(4xBXcuy28{3KX3a>w8^Pp49Qk~)wmX8Kry`_gy;&y#{oWxyyEU-A zQ|9U+%9Y+BR~Zg?Pfv!h;xU6jnccH5Vm@A$PK!LuXUJVPRD3cUFNT2DN|UO1`js9(iN9 zcA^|x9^tQ0xW4)}WpkYt#25kS{sgD!qW;J^)-fp#yS{V5)nIqLwwO|pbm!3%h znjGEP;lNFI=X0Te5lD3^J_Fm~P?-=pSh;P@sI2c0XPZX|V_sJzet zuQiUcWWX!T-47$s5|)|msESqchN0qI0gqUqS*efH$T?=jjO1PE;Gt4NsrAK3(BKi_u6G<>2eB^c`P3 zfd1le7w?4OwGLFdMFlfJD>n-Fu~(}PN5o2bb~(ly*+1NDVI7|8X2y-JEF~H=vwoEQ zShwD`O?K#WnHEsDk1QiCYzZqht7;wsQW~F5FFX=6*|?cuu-XeywpM=rU3!F|$T?Oj zR^e6+;7HUYchXu4cB7dH3W|@$yU6PDxW9_|jYnqz zG0u*GbY1iNRekD7zogY~*l4UF!-rOLRgsDeUST{;%oI&@+at(~#>W!hR7+!vSvber zA6lFw%U$F?>UzGq$5YUV@rIoxFCmg#_}9j#)l9189+_0;+KH z0(qZGDHh}Qit0^FveX88rH~<{zEb#Rvw9!m_iJtjHLI9$b!lC4F4Xb7q&)E!eXSXm z3*);y_Okr8yre_DpPF7D_5LtHH!ewW?J#daqcPW69!N|YRQ%j$>t<^3okU(LF_%E5 zF=%n%FgE`|IgB;){K)fm#u6gn=*n}R-eAeQ?n#n|9u90vpuSp2+3O)4sb_4%WEvZ4 zT$4w$uy9On*dwlrWw?=t#q>t~$norC1V|!_z$fJ4II1s~l zGPQA0hWZ zu#gZ)i5dQdS#uRTGGmtBikR(v&3UqoB9SxzZ;T)n-Tc7anjQ{JCcx8l7KTQiV{Pjs zkF(UUy4g0>qEEe14oM?!*Hn$~jL;rx#PM@BCsQfKUHw`NQ*n!?*~SNaR*n`(uBs7Q z@Sdzq6dGbmLrxpZ<*O*S8qn^AO>^x5=c;Z8n@#uB(Hp87kd1l?%lLkiIL=#4-<}+l z?CAFzA~f9X_5u>D6ciXU23~oXqmd0{6i*uu*@E1kv`vo0T6ZMJdM+e_Sw+4 zPm(plS;YxIw-+(c&V_9dnTm{B%<8Ob-ZJ8i59VevnhoH(y#`K?YC&0jImDg5FQIek ztzSCwcB4M6dgFH0$-Xi0Z$|=>0cS2ZO)7uK3XXzKjfoH+p&Rt|-vmiJe!( z+-AC~q&B;J#Bhuo(R>PLY>v>Uihk%HPCV8ypj@QwiH;8{~jwAid_4$2c1@*1Z?fQv=I8N_&To6Co337B>3;K&tfScjZFoB#B8QD)CwF}SW?=AQ z$%}_;Pd<5 zXXoaB^Pzi#T^$)q+a6cdY#(4MaBH!#mx!D{9B-;;yHU-tZot`zGBs~VK|E<79WSad z@P3+?WdFU<;|Z)AfHp{+VhR=VAM3nE!)zFzs*N;`H^v4q5`+DP8>|Wp zyqlva+jM_gQ{GuTI&1)*iT*m?Y0Go|gTyg($Iu2@eqKF^Cq?cuL85AD>$Km}0A6Q% zjxm#)@g$d9zr_U*V`;Da+{G}Xjx0SxEIm>$w#*@T#dRn@;#VKg5y$wk*MOc9nfdN?Px#1enNCJ8> zjPM#!d!42HWy`4%&X?(LqCaW6=J2nk?)XII=jAdO4U8w3B>BKr=5s^jRaiwBAp`8H zS8@*)c=#W&kxX`v&ro@;PLB zI)NR{n2n{KIT8Z9o|?A4`;G>FFxypE`$XZ2nu2E?dnSC+nJ(yxq=CB7p)=noj%+z% z@yR*$H(<|=o3xxmdyCQG(b31n*BAFyXJ78a#b^JZ_kTW7>5_}hQJXh>>_`pGLhdKr@T4R~Iia9(V8sCn9nr zt5+~kduNCZ;9h(fMuO0X)HEAG?M>S)&vFMOaa{Q;s}Wu;G}$}{lD+A#c7&=YGUtL2 zx6YasFdIE^-Da3Ex8cSEBw$XBDlTIV^t_@EZ_M$}B`}pEOF;zq+?94@f#>)3P0AMk zXGgLCz54x6WQRg5vPz#8VN`(7+-mb1<#Iol>{R=Hb5JHz;_DO^2U8HbOJq$zg( zGD>~9|68c1T`2o?)rv1Fz?n4G0T~Ms0B&`_(9r;Rl%OHHob^A=iUSU(LWM2E4j z+W3HW?SIWgMdVN9_nVULsdPhrXgt!W-ne9u<$J=P0}DL~t)0(zK&sYDDsX4L?Qz2$ zW7cZh#1<2k_L7{0pROEi;=bQln}hr^G?^`r^#QCV7TT8}Zf+<3Soy7{HOIHjhH|)$ z?O(rSRO1=jsy&qzE(&{0dz?8g3Pv73($(|W;9%G}Og;V%OZ~JP{V3VHR*WQWC=oxe zy>(^P#P?Su{{2Zis3-qVMQ*B+pvBlx&@JefK);+p78>J_vqo^8t`Y-91N-KSF@i05Yr< zPEq$X^M@JtNL?0Q3*=F;NvRa?!Ca$PZ#C{_YsG2C;RK`FkRC4K}pr+~~>9kYeW3&zK%fc%!B9l-uNw+s;5}lvB?kJ!|rB$o$XA^ zSJT3*28^-Pc}*{AHdLscqy*3em%8z8i$q)|_%S_jA-gs!&M4%LafVTGqM?E%NzQvJ zb@H*Y5l~N!hHt#<@tqxHZyF|`zrnwf0r`mvOc3PW#;kVz-r=KhF>;H&kH(m24N+H8 zE)1Yx(C{B7Q(*LmCjRnk;){c;RUi7p!F#(d2K}$A{C_e=-u_M4nhz^}W)EDm9~jJK zx}shdtA9m7UmI~@vqy+t@2P?NOO9=^0;YyN9tJko_C-6jh>BwIx5~QJXto}Ti&!w)uB07 zd7e7j;;qY8j@v&-n1~3&t)QY;;Rw14^H3coCGdy*MqGS|F`0o;otH!j#L~7-%s2N5 z?EfgLDI@LOJpUY)I}>x5Yo(>=Wl64$Ud(6rL!6Y~Sp9pGv*L~E3(oZOh2f$6>?u2Y zwQdI`6bvv&h=<+)7TYVB&yDW-DH->rS7l-+8a4`7{OWjcSk?xamesUvJch_qOQ#L|WKYtPX*g-vQF zmcO+)duT_qsr}+Z|4q8Gz{)GbT6tO`V{%%Z?vo)^4R|xx)am8h0BUH1*MUO29vyYx z@1^Qv?YX^&-!jKSFW?aS?aj$YuMCWPbSLV~PioEzF>0GqPN#KH_yrvp+=oQM652-L4@>jq;7bfgA3_gysX3+T28kxO=1$J3+Q&`1U z`V=?JP*x4S*_Yjna-ee3!v;uhzVKb5Ic}Lsen2X|@rM(3%$hdwezTS6*msdNjNn3d z@l!i__o;`@c{}bFVQN3w@*sp58DSOd@);<5PSEn>g;T)K={-Yw)FnqVao?t z7|iQgtoWR6bMnuO3mmX?rR^~vyyxAy#=faNtGi+A+OT_TOQ6^5CLaRNRzug*RIhUb zz`?T6_CL*d!Y6<4|6n21r-|f0XcJA(3Af~_#=INnfhHLr+mLM2(>YN8*J?L=k(_9& zT@x(R%vzPy&{YTgB3rw+g!6%cSO$5{9O<|{wYgMF_#iuBa>7;@J!a4J#y6IG#st1~ z9toOB7qiBCnom@6mR0FP7W4V}z{2QoMQ%*y$v^w^;lOt6tO#4(CcGMd072`g8#!%> zNRV!v$@Uq;X7qQwk7N2Gb_>aee~9w(-|=$8o_H5E2}J%jHxd7zZrqCeR|j9F zZ^;s2ZTfV%26`^wIX7sQcnqJ`Vwlc@ioo9_Yp`h}HiFpM>OuN!!TGdV+_9*zavEl1 zL*RO#%v|Rhb{kvV_>u;k^7T2FTT9JMsK6nAcLfLQ(S$DOCrFNj{73>PvquzDb<~wJ zrAI>Ii92}h(yc+DflsL|CGS`=KrdrdlUpC|E$);I*qz9vfOrBjI-0%o`tpyz(pbtu z*|%ZHN3k~<4+=&z1V9KBSc``{iG_?i6I;nEIbhwD5mzT5L!y3%1+30DawU1kXycO51x9uN{+7l__dm0PL9 z&GRNJB*+{aO+@|I(DZt^22GNj=n5aT3r_QoszkTwu&U37k zBPWCbnxk2?ir&IV`38Ds6r4(lT*x>He_ld^X5+QA(su5|NNP^O`O}rOu*}d40(}|u z=%GT00(*R;&&^k>)`gz%3f?!rry-8EyjG?z=w653HOi_#6L07*HN)GX;r#sVOy|e! z7RFsyeP(u>_m$!c!~b#}a*cSYudWAgl2AVP1aU{ycCG@TQh#* zW16+oO*nK4ZhZRVak?oN$W_l(d0f;`scUFw`}^gp$7C?KIneSmQ(#h5Qm92@h*wqm zYJ6uGWDsaF{GnyPdeqYI;_Y)63|8Yl{5|v2B zWy(zOf*qY;U!EDDw>P~@1d7Xrk$aYtTQwD+Qw84AR4_|Vnr(S))lGA}G7E_@mPof! zur*s)ywvZRhfPL{_ZU0v!PZkXaU9%0R;jU7J>o<@y)}~2J^-5?w+A8qUL3rvbePP$ zHs_a7NQ?><7rTj!a}_HjgI10n_PqQAn8+qv%_IwGEu3>m0nTbQ%FgBMGR~7Sc{7TI zegi-lw|zAV-5CHGD);WW_3gQJArJ`btb5OTp!{FMay9@e)XwL9Ro>jWhu(@S&-hm%@T(^E**H3#DTt-hm z6>HbRHqO&$ha8_UTd*DoHiS-jCiK@@@E9o2{@6>UX&v#J$1!ZEc9A$PS&eCHJ>m-d zU^us|wX~=Fsa64`%&m{{YMnB?Hyfx zM$$QSR)&!~cdAqU3EH`YJu#uN46>9z>XC5x2%!9sBu=6?uOIDPyxh2J=M-#p-2r)Q z16^9s_g%$-8%CMR8P1_M-8oBfVDM-RIjw6$6e)k(PH_E5Dh%JiPY@{ zFN*9YXG8czQ%!wRpiR=&utyIRqN>PW#Gb}1TE;rv(orqL8s+_*OrCPi_!3#jRS(B~ zaqcQt1X7%i_r0|<-8!F-L#Mis#ArGHX>mZ}-i+6}t58F5_5aZIo$+k2?b~WqRjDd! zw_21MRa=PGY}MW~l$x<)#cYe(tEf#?jS7h(h!|C?HLFIfphjZGh`svex$pn;{D1HL zyl+0_Q@-TZu$l9uJc9LZ8el05HE1Q3;U<*8l&o3_@ed|5v zw>!~QIv;bD`HR{^-1%oWX+Ertr+#_E^=0eKlV_c2P7Ah0n;2{U6St3iV7gjb6A+!w zt1DhVI9oe;7qlA)*AL#_1}rJMZ1wNB$f1ktS03q5>pgy2zG4esP^OA-9yIUHYcPD^ z>X7ckM*q`1*EjZr%T6q#CMLz8DZLUzDqnl{^H4TQ(KZIjtXVoB%buC>lg47{bwg?K zqn5A(xlMA2Qp|zqU~s2%pW-K}zPzB;(8Xpgy07skGR8P45aaQvh>?;rz+fm(*2PHr1d>$%m~`y(uXlx_8~y(%px<_V@vQ2`(X9kL*D~E zDRKr{X_j?C?0T%N($TI(1j&q?;~?MUkvA>KID+CN!qf!9(%WJKOobhYD8`Z zs(!4)>gk716u%~b93RW@F3&ZkvSA%@2b<0W_)M!)%HgJRV3{>nYU*g3d%z#W2ZAc& zjxJ6^N_~YBv>*w5r%qpr)^r87*Thl%Pw|Updq-^hl}2IT{p0zZ?y>7H5NwYF9=qb+ z{5okKv5+&5#DsG6Q#>kFWe1nQary%Vw(iyf4*WwOKY9t!d$rz+1KymC&2A2re<|4 z(M?IlUo+xmJk&H47IQ-W3U0Y9kB}fXw$*X5A08gdQxu26Vc`HO-0yc>^dloNE82C3 z(;TLfrZzJ8crMIThpOXa)%o<5I(h_hGPge?m&wN|e4~I(EboNIC%(gx)m?FI=i9<4 zzSf>`%*+~d<4*oY?N(nwxTOYk{3^3mZ#jci+}Wuz?};PtlEL;jCDO&X{P57?0ZIAo zg$}1wDiEOl7rKzz9ySmDsJ&B(uz8X z_y1CF$O8HO(kc1@2r*ANB_ZkjeXG zOePs9M!ds;syZBk`>A?y z^rDMW-F^0=?$1~|z`A5GS8?c0;s|gte`Txd36OAyy1LPApNd@B(k{2Q^k&58d<`9@ z?CPtwjP^r;qokKyt}M)Zph*`DG9^nEatHPHRgOJ(h--8ra@!vs{!nLwPkLNx7VR=qO!M~o_y0ndB5 z$uCw@cOi@A`BxCz{`+nm^4onMa_P`<_&end4X#7Rv5MEI8dlqzc>j`sPMIfa)7HNX zf19o2cds)eMV-YpO1qVxtN4`CCb48rPaD8|6N@*?&#ECtN4rVtn*qI5$)9%BFYc!(2xnmIZH(Ls}d431nmcjT|4-jiFBawt7BRuR{IKA&}&EU+zMy zUaI~x5-pyNN6l{Lyt7vNsL+a6p{qgsZZ<@{fvNH`-KcCOlv`PUTk;^!a)|&7!oXxKiy19=J9L{uYCMT>R<5O z_U^xs#Ytzj@Q?5ULLOQIhtWu8e_u#69dH^S6p;kS#yKx06O($8xUwce`~l?$hQm@R zXZ?YGUIol4ml0grQIFhJZP9qexaIrRmRIVJl=Rj+BJZ=MO&E=JRf_(idbj9I6BGYX z4bDaFQ)HMr5|407>K8P49%>Ca@px0fsvYWE>%22W1@hZIAvzRj{E*1B2gE;-X^4op zMfUSikZT!lL)?!WR0Ph2tl@s4Ls6e9`DPKv>00@K%uQh+_V|V}HG_;$aYQuPI)a(e z3(@eKv|$=m+m-EPGZYZ;D*4E6bISlen9+hV7c5@VFK!^|6+4j4uME`vrGhRox|f8y zz`Uhin;mA~suYv+qGn8XUNaX68kh1QTS6H;VcCe>yYnsR5K&06(@3BG`1|bucO;Kn z&k$+|qxPQl;ZG+kfWyr{$`lS(>pWi2jPRi|i3+jGkdV_Dl4+FK(MaLNU;CGjr2dIU z%z1LqOY^x~Y7h6{+&z4oVEl4QO?@knGH;Q^fu>NQKeMOl^GJ&z_l#fL=tX)xZca%1 zwNAPU`$gv+y=U%It4sOtIepZ@ru)ZCLJ$c}|zosBRnjw#|5PvP!5O6*de+2fhB~N7yGSym9e0@J#VkZ3H zwB3*{)Kd%RsB>k8qcLFbi~eH&wAU7a9;-#wj~~ib;%B%-d_;*2Zpj}4HwKSs&j9Z7 zDf5Vt^?M&ctq}YNYkjnoNXJ6evP0_7%Dpc7>*l_7zT|S5zl6TiXJ8hl#I4(L^#T|? z?^Hmc}HXUMps{fbH^GzEQDPbiZF?;Ve z&ABPYM~%rE#~bnaHBM#6&zF8IkI`PeO(qeag^a9s&4b0~jB zRXC>4Kh0mJ%Ll2C!nvq}lEFv8~FV76H zDRrHB3=e{}pn%cgG5by6oh^7c4^OTr+$Lv8_D3zC5E?M(Gkb9(vY;Vsd>=g%W|p+C z5S;qghVBcNe`;r#^RC=Z?&$#H4@5LupQ^f|@@NZQjqe#@UcN{Rf?xMG~~)flNGLum4BL3f(Q`V-~8=pmJF4 zsp$EteBoHw7`E7lidzcPnnp-%9Gtzd(qpzIyhRk+SbZr$e!|atnVh5w z1)+h3$Z_uR26gCGsMZ(%5EBi;q*_$mj~-->&Oz7&{ExKrr$S}Y6* z;&`Pda|rjw6E7+^y&DJD$aP}xmC6kv`Fjc3&k5${g2%M`Gu(Fhf{M&R_~%rTc?|?$ z@&4SkaM3`>LhkMSvb$L{k#yIKK79E2MuRgr_;_8`b9`y65P_JRUp&A2|KZ<>Mdyr} zyKkOfywWn9S5#5Wp-+MA`P|67%O|is_!QUm8JzS@iroBQ(k4l8ifc*mT`QZ=BiB#F zoD7BaAG-?{MyWz0YMfs`4UbIUDy2mYQpkRm6DBwQh}Z7{ORymolcq;b@j91w?i0f3 zTSEyW-nmartT5FPDJ(?+c}fD+ZgciIXh>*KyXW}Vv32<<-*0O|I;zfo)M7**u|N!= znV**|=~%=Y6IAu+)2vUS7~M+H%2g`C;+L_KqUH-}RVE_LGqAc)K~sgb(7mq9FC<2G zpgH!tydG*0QBcdKuO)=|bE>(Zg&K(s4@wl?Rk$lYG+@zy!6_AhgH!F!mOQ?FDU3dl zD;|wU5@(;&0S!VDZFq(r4a9i(@ScHBqRZUh{yjTX^-m?Mt1T`9_HZujGTD6;=VBBp z!lk=*Pm%gCz3>l$BimVI~~OE2tc7vRHxo*U8@fEhbQON#-e{7iiL3QSt;cr znEHS4R%5+&ww3HJEXltUZ8C|^QS-Sxuhz?*nhn8SBqnWhadU63=`W6w@1LkE6*#P- zWTTXjwVYlS>Lcsd@}1)Al`H}MuU}*QHdXZ2>;YorYjt3HC+;e581JnhZ^x>EtNh#5 zvYK@d9Q!xCm`vcedk6jGA}jTs{18v3qC8VaxX5&Ik{pM+iE!P@LpF=x9E_~ z!nDy}{Tb=ewpBneugtSOKa^aG?b5JKbU%>tJx@9HntEeym$=-2XZxL;$1;Z&nF2&Y z?9E|07Pjy25*yClz^mf=1;`wjmW#o;l~7iz>TjKrWh^*ZN$6NL_Jsl$va)lrD%rF_ zPA_|%w_@VfzFFT*l(^3~YLe+56uJiq)A)&raZU^vXKywE2M%_E-c}#$S%BuN8(kr1 zy>mB86fjVmLhF0no_?=rixMco*an&v50T0$#ouT3P{@&Q>Gir*1z`Ozx#TA zaa!bWxv=R!wF#tImV2~EVQpg5#(P2Qe_nfrrMO2*E;ZBJeW1hNj?iCu1bjYVCFh^q zln>JN(~6T7nr`9AB7;R}s+I?uoxapan95UGV$58&uLFQ_n)mju$KTlx&OS}ZHyLJ+ zBmvMp`QbF0@&!)el2^i^MxLkAEhj;4Xw^ry&4X`PmKpy-_%Iy$&h3>6?BhMMB0KhW^+Ye*_b?{lpgs zh39t6oGwmf_8m3Yj%zr2jD&6#*J+$ufK9QDyXFP!ZD+>JW`1YAWsMZD3N(_*+{ z>g2V)Kfj`V`}U!DxJy|sAnV1>Y)|!ugM!e-kJ1Dr{hn`nq1ciRpD?91~ z+d_2g2a+(M+_l}$P8)r_FLF#nN59P$4sF0|=E@eIeGL|06d+jQl6u`|+`f`l9*=JV zT4lWgyfJ^_KR8A!=5Ipd@9+6|;?52e*;W`AVe)s#gFmtdxs}ojrqQ{BZ_=ToJCyX~ z$#sHBmLHEb2056mweNFnir{Z(4mX;(_oy{kDC*+pxp*sYJ&hjmim6`W%vtJu$aBXH zZv23016v^hpFC*VdCmg^>rcH)EtP0rd*(iC^{z__6R>tj2=qSOIAx26{E8j85-F*Q z0gjg$7bvq+tdHfABe-r`x`*RY-NE6lHr5q`hK(bbOQrEs{PUfTY@0Xv_m80G`?r+B zQLN~e{@d^u$H}uipla|LK``B0>LxEOOlc(A0VIo0g(0=b*D?vVF_Pf!7H9rv0-n6dQA_Z|$S~6AYO5m5(@ZY{b9mZd5W|ywZ59KruZHx9l z;!R`<{PcXtFN{Ay5N&^$9f4Wf4s+z(vzv{|q%6b8u`))y7W{C?xO9z0U@KTEwxrMw z|I=AxNQpaP*&-(8{x^8rmOpD_u<;X0kVo0zFf>f1G#=FqZA^Gzs&}I&m|vM=z;&qx z1e5l+QeQe2opR+lsrBw4O&E8JJyrePeXXHTzV$pQCHhpRWdBOd$=BmY1wFNR@T_MP zynMek;gSa_j|ui&VBf?2aQv#oI@MbU%gQZdJMxppmfXN6t<~iUmg?8;fYlMXv zj~*IB<~OaU9Wp(kPqUDk#@2k0J?Lv{y*t#hOfSYYn}_r-nRQEBMa)9ocuuaTjS5cq zDaYS0w?nEe_)y%xlSX57C9*qNZNdN}h>>^AaU7(5$5dbYRa?O9Os$v&# zek1VH!P?bJ#1abFrRRoTg?3)G!78pI4a7{g8Tpv2n6A6Yz<8#+9JO3m%K`GQPsO_@ zM)DeAr@J?j>6qSLx*h%iob~>`gWnX3m!~wGq#ZxT$|L(A>p|DB| z{%CW_T6|D`YMCmO)@G^LT$}`z^0KbXiS8>QUee;IMw-(aqHAYkL*2(D$8-ZngPnNRE z{jf`BA-?2yQWFfh4lbf7pAf7|k4ZA;CSfVkE`l%R(@hl-76qHGU?;oN1E1(Tdl53{ zMF;wG<{%%@m&Y9^^4;S&37?B)F~z@*v&27p=l6L?vhHR8NrhsZvPjSWJ}6I@*TAW> zBIa>P`f9b+Oa{9P$-n);C_? zT(roGaV&T0Qc5P%S2}KbYimesP{DrvYiN?f=>=5`Npd$6g@pZ)-WW<6*LWXRYB^^! zJ-rzwYYN`&Z8kX!{j1Ap@XzSU{_CQgMu?d{-mQgNwCDt&r~Gm(5oOx zJ3j|_a!@Y&j#bDy-$d@>J`k)35(^6J{Sn*^BwP(OTO)?) zk5t{LOh0MQ92_#sVc=u_{z}=?K|BfdA-NYv*7F(S{IRa33XwlAv#_27K3Uk9MP{S$ zp$^F(LEt; zB#$}lT&7otv0trpzfsXt=P++i2mCdi*gk`mA4)2Dk0_0j$PG5-{UM>MmCj1Dd$2yU zdXg`8>3g&!K_u3PzjqZI+xK2E!JEfAh?` zMd<@<8=>oQ~eTrxO$$cZq&HLih5O+C_d>3l~8JGd@)+fag^Ctl$Vxc)CIrQ zksV&Yo{^?kju+KinO3Z!S88cxCH4kf^*^=lMl(n>oij; zP&Rq_gom^7zxehVJU~~wlM{hRoh05R57$Ncoa>&S$>BNc3u6X=?2WZap)H`=*M6E3 zP0$Umg-Vh&HDS3WoS^VA#mO>y48k^yX4>ZzGub^-O7sDatNKTfH^$q>NfN474R{)G zHDnUB7EyhU9@Elm^x(E2tVOWaB^jId>kEj@wPp|^fIr9Hdts%i7aO+Lce8eOvk7z& zn23HaUP$ga%NyOBM9is8qk7lY<93bN-+<%E9_Q%$qD$ewL;Glm9>y;ShgBE%We|7RglY@pxNd=L>v@`Jj#f zW*4P5NA^C&yNaoqMcw~fEu=SRF$8M9knhJU0MeB*A9q&>7TUgechbPS?csT~U#CX` zxQO&qzcHDY^5?feJa|^kn)e%tm^j}#+SvL3AZf$&=4xwZChI4qKkZ|CGn63MDirr~ z#J)P_aV*WbDvgyYfEjYxkZxJOuRh3d>$UNPV*D2KorXNF!W)eN@vWgl%rLw8H5Pth z@vnMcT$qyq6dzU{_hW)t#+AId+ncY34K3u)<##yIe!sFO35Pn3w<;$4P`^s=syYT0 z_5^)x1=S}1nUzQ0Ejt^MmEY!@iY za5y-v`zj}J&>|mw_Z=4&ZsT)twtS787n)Av{AZ`iz12#z966XB`8OkW?Vmy@yO6UZ zYBEyV#ot=U4>&&!zx=`DDcPF1-M${?aYR!6mftwhK#5RVwpqU3zr z>5*EUz_z%dM#>a-azt`J6`7DJ2S?!O)N+D#?QGYW+$ZA#K3j7JM#P>#e7Vyim*H)1 zD?(~lx-+9UtN8ep*1|Z)+2nBCnqn^gOTO{SX4s_5@$acTFiAUiF+>R>)LtOC#m@V6 z9t|(xq<>(Xj@hpSahc%Pe5;!tzkKx~wKoCiQ47rfElFj^X4xUSteHROJ;>z!MekDK zXy~A?H(390WQmFrwwe32rDzE@^PE7N#ldOLQf`96|7gql4dm%Qmit&P?|0fb&UP~Y z96Mj!h^EeS3Z8tTQMEHn3?`5Hslf&I-+by@ZxvuSzsy6*?zB!RrEg#U8k6VxXDE4R zJY-@;t4QL6FU;4U90s*41k8m;Fzj*3$2&i;bGB5S$PmnP0l*;1g{#*5G)kV+T=Fwv z{eD#dlD~iUiUjo?_;>9YVI#+U1HygZOXbBQm8_>mx40IhUrVQ^Ke_iYohEK9ztG*f zvsJFx>5@9H_g2tvqSl0Br;Ji8C=7R|m^*@}>H50%kQygn<$*PS?l*@qkD3;A1Eb68 z=sxj(l()3l3N(Lw%5QqeN}MVjUCCInMM;BHZ(ereIeqz4p5j+7AYO~_y`&}k^q)6FlUMMdWPESPjAFOdupb?ra?+0En$ zA8!1sLP_{XBUP-s=Tu`x$z;@mwMexqm4P)DIG`i^B2mBuc@0jDkiToKXq4Otb!yRO z+SGE+(HU0!7C7m_7g$zZwi!Q>9v$y9zP!J{ug`MFGbU8^N~aH~^zDgiEU?NGjgEqj zL&omvP#G1hf2DgVgHFFD2SRn!sDQR{5xWtOeH9SN zE1OQ60n{m-ccw!(YUAk-#jb6?Xn?7$gQOpRVQqCpu-*-&B$gwdJE;2Lf8Xa>U$INt zKXL#r&W=pHTzyVTYpxlX+}leZc6 z3uU4B1f0Y@`y9sJCX*Ti7&w5@F8Zg)v~Nq=X@M7M<+*~*1wVOX6Z`i^mjJ|*(5^n7 zg3$+#-MUJDB9nOvHAeqZj^THk=T-k#hDW+7&$wL9Un~7NO)isyX0u^3ABZBp9?o4b zy}FZ>be_Re-l1lR%C={I#blF|q<%;h|5%0+MCP0^oXz?r4j?Ap#=GY_Fv!g4E}`kY zPzt$t_QBm}xECJw@D*vEt=Skp-x>#V+DLlhy`woWX;5==A3v2M`}(=ycL!MoskoEa zl%|6Q+U7!ek2!z-n}2SMy30?G>Wap(L#$0Uy{uu_uJ!3K$8Cp0ne2}D(O?sXg?;?W z6uiS{U@vT=cpwt1U2&MW5#aZEAK>uwx{XwYxpgyF0_m;YnSl~Ox6wm58L`=-m&Fx4 z4|5UiSNmD-#gK>^0m4z;Od81n$1c=m;gjeVv9dw3_wm>|tH%Lkqn@fX zl2Pa}2L!ht9Ubh{;{OWU5Y1n1L;nfkwwiNtQiIIrAJZ0=olMJzJYm&C888}4{xFx8 zA;|^rXgw7ni$wYI!FCNgTN)kJwO2E0kEtcHYsWB7#xG=3>srUl$cvxCKdjykc>wx4bwweB&mKweP-J^s3LzEncsivBpPd>GSJ% z^ZeX~tWZtoqlwM=L^Yd_HTMV65)4hsLk|Hi=E*|u z$lZ%h=PS8aV!%Ae4 zkqAZ}4GhWOYCym&E|bk)R|b*&^=Xbh4=YP91ZoOde!z)}!AGq&4IaEOXET>_6l8@T z(;7TW{LBn9*}M%Kq;kw3l@uHmj1wxkMWC;#NPxxoK_~-i{97|NUN%cC%9QTL>hVzA zGfmv+KnnA&heWOWa)=&noaArJtAIz!AH8$Qk$tZq>x+MB#VF4Xzjt^2-M5D}uKsk< z-3Ht~=E&d`q6&Q#t5P^Tr{Pwuv4fUe0HH{2@d68lg&^Iz%}nmp?LQ$n2Vp0Bw^ny1 zg`2AuG^26x{)J<$22znN#=~o}RP7#ZVH!33bvFndF$=dA#D8=ijC2=1Kvi|UGWDs- z3VtB9|Hxeo&Fxz2C8K1<@gNLq^(%hzU|a>HoNqdC;=c5{!WciYo-%>s5FS!<{=$tp zY!3^3A=#vIw?A>illF^C$>f};ps`UIEn$00Uw&vjfHmdQn5)#JrWxV)&PDe5C9>^i zdnWF`!%L=AZjB!C|0Bz>Tacgs*}{K~kol#>BdbfoYcrRKq~;m)7vHO?H^ewV4!T+T zAXPak%f+7e*BiKSRepDLoXhh5luh~$C;EpGhJRYf7z;jsWNhW35bkQ_xe|I6#KWFr zk!ap{o@I2&Wm9jXfu`dZ86T>C0Q#5}7Z^HNgz_aG3>-XurHG!fwTC$yX8#C5p@aY_ zLjBRMGejX1P!8|>wYl+>&{fe}1;+%fpoBZ19pmH&zF1KPsz!pn4f1rO(7_3}l;1zR zPHh)5x6^D4p*iJHGIgV=CeAc_oDGn7r(w?4a!Zq~24l{w5_G*;M2ZO!-aN(s(9QiognWlc*Va)f)b z?dFWI*`_tPA~#^B$C<)a`((DE$>5DzJrrQ}079g|cihK~4NS>J>q#4ZwOCv*X=oL+ zP|0-v;0~pD)ArzY|4y!Nu?%$vkvDTQ8&7hW#7Y^}3;SaXCoklLEh(G7G+|FFyc=}3 zU}KkIw=Q~1D;6F)A*XXh>M{GRe1XP2bMt{=c(ZGTf7I>od%RTs3jPN5YxkUlpO^u* zM&HgH&8_&}>00w;n)|LaIQ}Cooa+>Hrabv25^&kg|MHXORl8O0IqSk9&WPzAk7;cn z1=&23272kQ_-^x0)sOiHH&<+KRHU8y@=6V4puyi*eqZ9n(BaMh6guVfdyIRbwyt(ma0Y`~y)WX42#-yN=qHIT zqoZMiBiWC8jc*cOo)wyl}X0Zd6buGf_M3S_}#7)NkeuOsZ_shgM%)4*aDuA-Wm zB-Zce{;AZw`-23JQ%-Q;1$$o0Gh5Mg#h?CAs{zH+C#ap9Q%OSc55n)pWO!p##_7Li zY5L>e=c1v@dX_N^ zLPi^rIMTGxc3lA_^2z;(FF~8R!+hCZ|JE%VI-u8>+pC)@hW0bWTejvu-rq5;+^(t! z1SPl_sCiT_R5?g}pXd$vybo#Mc2?uSy{vj`Q4xG-Bio?y#sttPB3)FnDG-~*c$4kv*F=Kf`pJ%<>);BvFehgJvANsmdYb0DEX6Jt4nx%X5URyh)I z6E`hl$yC-80-UY`hNxp2DCOF%z6`1$mb7J@fbp z&9pV8#l^D5t($|6#ex+#I7%vPO`&YAL7|P{+IloUn3yxf3)W)%fD)QDa02X~gNz+U zC1JNBrAzhM2PIYAbL6QVMD^h6FY>jqCFg69jP@6&i<+~VYm1^h5CGW_{qr zyW6svmr>B%<**e=GY&l7&vX2dpR0F%()!aZPUXpM=h|bFj$4xXrkDZu+{jm;aYvCX zrvoO?$;06)R-pjHuetDcAWV}h4%~x1OR+|E4_wLrQ}3FFE%*9VBdMg3kBz@_E)b^b;%uqd&AM{FHpZfQJ7{ym?{O zsp&9RA6g@`KGkKan`u#5hVeTJxJLF0@j8X|?8{COf<=R!Xg)*a5xR3Ix;<*om#NK>gT4|!nwaHSq_#4-?CN$#JTe)Xk2^5fdX zf^4Sk$dA%b1?dd?;EA#w4?gO?8c z%nfSO%XgK(auncyZ=$WdA!I$@fcy+{`JZJX9Y?r?T3908aY(=U)2-IF*~{O0!YPb) z$jMq+{!=ey4;At_%^}vC$^&av#0*jMh#|{wIoBPU<~6m`qMDxoFR$EYvnersPZXpI z`WyBk^}upI{ZjQc}&K(z3(^v*l2g_`;O?BQ66C8EZbCNcbGDIlDbOlh+oF zyOgx+;1UK2s_8$tZs^GqtHVEN%D?RT~jQXRCiD$Dhe-ZU8(Ye0e%^G~JP2n-R z9M*Hkvk`6ubF}~Fm*!zm-5u4Krl$bA@Wab-G8 zNaUh!g=~RO$mEvR@7eh4Aq?*}v}`R*K7ntXO&x_<*%QEmLa+Mp4i5;v+9*_0N1F`6 zkV7=#?h7e0GNqgU31Y1OI<9oaO}e&FY#cdjtTep#kuG|-9*tyYvmechaz*e3E}~6tT}p08h>dk zum%4HtAcxjRXFk!@mGm=U01OV@c8BMF=-MwN8~T(>=^E>gs}@Ey45Hn}Tc``M)=*0#LESJs|Cn zg9kK@H_>iM`RqF8s8899x-MMe+OF5Wg4;+Oi|kH+;>qIw-W_yqqSap%r>KiF-M`Ab zV`HM{Jcbg_imE*D<{qhZ_Lshitk2|{Id-W_aDP2Q4!kZYnEt$Iq)uUMaPZk0H??`< z)n|srTjhry7ukwdsek~5=p>@luB-jCG}@OxkmLD%Hukw|df6L>XLkyt<+RHH){~q1 z`~U$z`_TaZ8Y>!Q0p^ci-uTVzPMEGw9k1UB8NVg7H4lX&9=PwTnQi10#vul;t$-mx4z5>1c)mS6Zn`ex#9uYD^xiY$ zK*wP4a!l}isSIHbPteG$)KuyS2y3da$Hx=*meXIgAYmZevTl@^ACk%nQZZe(b^ zxx>Oeqj<R>7qxP4kui~E|!r3Ss+OP{*4t6DQt`;7Z!K}<^q7u`?==~5f zcHBO)73n?vF;EoC?WqC1x>Ms0IhyT@vo@_-cS;kLaSR17mp;4HAU^4b8`p;H3Yq*a zW%<=gj{UA}UtLMP+c>AJc)z&7%5%=GkRtMOKliMt}}o=Nx1IZt`}?yWK_gn>P~ zHOPjOExwKeH$6(qO7_U+zd$0 z@}=pah;90szxx4*R=O${IvD@0Cgig>ddldB9I5b8bbR7OV`6=KE#k4#pX%J?hD@!h z*0~NmVXex6MmqyqBC^}RLE1>8sro@A8rrkmE|5ERl=qgHCZbTaehtkwa23Fg zDbk!38^;)6b-5qhy#~w*7$R!wFhzhc?@$Wt>mAwwiIco5*JQ|ELhTRC>bDM_pEwz# z-h@=M|5|!hv2OV%$>Y|F9kQCoNWUtF6P#@=EJGBbuRr5fad0nR<9a!EoO|QmXR$X6 z{8%$v>vcPO7LA_y?&-$&OLyi69u(p&ICFP)N;$;4jhio1KnyP|C2W2GW&=)41x)ac z_Q;y9iT8cW8#@F%;9ubr`rq&sy$e7IMWkF8BFGq=eok#!b8zRO00|mDDMjg6H*!oV zBsZ|)xATnay`(fR**GY3%%s<2FusZhQ=y|-`sl?O_)-SNy52jqN5uxQxoG&sc$N9@#zj%qEHP(k+lTb zJeYTh>aT?Rni~jz7vPNpF#un%r<3y?&r82;E`2YqJ?tZ0@0eJW@*HQt0ZN-4WMj(Y zQf^<;;sBNP3Q?(`=iEHzKZe#ON1a(!6!F#GGc8%Cm~EXy>owdm;G&qd+fs*HJOcO4 zWKBgkIZW`QQhp`NQ@e_P1&rU7?=1x-EBhVMVod6ztxAR#<2sjoaXV6ESz#?ELetH68hVGPJS2AqD#@`{$DtFme%@&Va&bVh^ag%cz zblltwkHegJVTOv?En4U!w3Z{9E8cU-x3x5tFJ0U98n};isb_x~SAl(a=t*OI9^+1% zqkNwoN5y^i8h6JdD|hT<`J43a!c_B=zX$g$YA3m4_WE|$Cg+vFkw?VewlsldP^8?9 zQ&4Brj%ZyKM;cWqykgp&A4Yu*g2Vx&ymyYKCbILRk3kt!9fYT6#jsle?e?1;yHD!P z1UL#ax{1p8-|I60d%t8uXUKy>L^yAH0?U~#N_)Tt(qWmORUpOi^)uk+N;7v;`)%gC z9Bl;yz=sl7bG@`x$DD~KEIGqaZoR*JRH>>s|6HfsyB0dEs0k}Mzg zU`pwnd-_^Rt9+a%^OUH2rXIJM**y0veDkb?rLR8ksmv_dZEcu-PxQ-#*lEot*0d?{ z4(9`xqdvL^noT?E*J)>zylaCC*|b<{AN;nUJq3#Z5exe(-Qx5Ql1-1AHm3q1%1!_& z1KJ>!&qQn6uVEPo$C7{DiJ50w?c z#npQ%G>G8Jz&X>T={up^Q$cwA*ITAoEL6m7ABNZtB zOE6l2te)l6i*E+AzN_N_uR1}^@Z^Kt!XXZB6^;AI_vWWBneXU>vcR>+MuzWwk8~ZN zx9~!b4XfW<;17Ui1)gaf7MQnkkt%(T&%QVik5F7eY-8f@eIPj|wc^IN(vT5Lu$+#( zPtaS;YjP@nrRliYj8Cp!W7Xpp*Z8TH#Un^@L7&&N3XR19*n4e%liEvN(gVlA z&@T59U&yOd?WM7;B6b--fWK&I{_IO}N4tqFp;(pRgF64Cxlwxgsx+2<&v)eZJQu9J`LF{#zA{Xgwp`Ck&)`nDR&Nz3lHMbnC!7H3>XOR-!?ofgfdabI!NF&9)^ za^IRtofe~OsihH_iHQQaum~!pDU~UvA|WC!DQ=*M;KJg?d#C1e|Az17C!P-Ok|NX(8mbxw?nhhBGF^SYhDL9RZppG}&gCrZX7z|?a@C)TY( zB6GfD&>CMZwkR^nGa^KM*f$a3BDbh#LiIE9nL7@qR+I*8Kj}cx&n&qM~+j%HPeNJ8JTJh0ujHa=LG!Tg^X@a6XSa_{NwBtF~ z2x7GBtfpr>zN^e2%G1aEX&58-L+9tGOr3M7WcsgnxbG3PF;=K(jQHH-JHOON`)_>l zu9$*VmE=A=vS5M~qyL}=1u^-I4wSRTT9P_xdpc`TiIwAH-Eh*=6<+j{c(<=|D=o&K8eiOr%gY!2Z1kMGjhsc=Ho9?Bf4@i=VkF>hfNV{s^LUbfrYT00|0V(Oo zJ8k&t*4{^$t2Bd`56kwBPWlt~=&IQ9_t~*^OZy0yHu-q+fGZ9kEMMnqm49#;SbJuM z_r{n4j^^5UFo)hwAJ{{`VPdVKcl742WFBW9_UN}?mTv6BoP+G zJdfi*_wDJtm@hyVw3!C1-X6?M`ek&vphd&S>mj7tAxZOh6pAP~8~;bl%cgvob&4U) zbt0zqUAGf>Q{dyavaG$%y(=|e=so8w#8PPyFv^?ae`v0I_}VU(J(;ue8<&-+$En4;%^tiQAEI2=l+{YeY zURzmBbA2D7TTTLh^gO8LR&Cq|%1kulwOQBD{c$E90Zp7o=W$rahc5;(FRoyR^UjXq zNaqAC$9NJnsl^TI_L*h9(>K6960prQ%=6Bb{aZNZMZsY9Ag%^|w}kY#Az^1ob^br2 zZQ;S_Zho)$)XJ`*cUsj*AJn6~extp*nE{#M`@>BxTm)XO6bv#)hn}7|%L4))L*4klSTI7JWQY*(bWHPH8;I+yI zI+fESD`x+_ceAqpu97<^TnnynzZAZpsUt+N^%eCs==y5*3=7&qpBz@!Vda6zn0y-t z%32M7SQ$Yc{k3x@So~}6T$oJ)&WqjB7tao7)-?E{-3=_@0j7#G)+4|&A{0t5QTJuC zh+sL%6fjm7WIZ}FW?!04fOln9CT3PBevnUX#$d-5_0p?FX%+N%^h9J;Jw)Rgx?0Zw z5C*$=buLc%LZglXwCp>>mgNRJNZFOk<68&B1BR=H04j0t$GP5d9 z)AMGnqIBfb)k70w)kr+S&&$U>n#P|cog!)WlEU3lcW=EBCP=FMq4N-=X>)Ua))~yCIFIg8-hL)abgeuwzfuZ?Ch8%IiX)6>w&$ROLLm#S8nZ^ z%Z+}ktul1pKV`Nv)Xg+YgWKt;8KRQn#FR4)5G|Cfsn+SjJ=aI~l#*$VW>miW%OCJT z0Ti-39br4RFr_QA+uPv&_><09r~W^mRKdbnt9PVvx_<_M;HI|-8Piz#|Q<<``N+FH~fW~!}p~p^Kt}B$U?S0jyUCCh<|Yq1k8|JXf87 ziUGZBMtJtb@R|oEBgMwyl+%ovN*B_4Om#H?s{<==XS2hJ@*nMeOO3E+n_E_Pv#qiK zfMRw&ily#rDRq~0LQiE7J%kS|9>cPq%O-%4^VP(U3!|Roj{KlR(*v1sN-?4|!*5h3 zcr;Yva$vL4{lCeHH`*UJ7jLz$gTl-%kvTGF z00?=weXz%YzGwd6Q;YgNMR30`=`eA-QB!i1Mb()eM=*>F?IQdWyZb5apj$xYK$p{l zZdQC_e+;27zVXR-gVfg9_{P=SGjY!jZVtEiHS&K&Hc#;A9hH34E8|ckxBQZL`0Ui_ z>#Y;P|KR>!^rGDZdu833Jyu^Lvp~~42V;EEv`Ix*Gak}|uu>yaTqcUelA!@V5ApH7 z1`I)*{u9bXE1})mg~K9|dXpY?6SS;LE%v?787>&Boq!dn#vYGIU_cld?vmPpBvvGu zIn$?;ESo2p84|P);W!srvJh#^AU+?cadE;M)0;za9ktEII^ujYo%B$UmU86VW< z45jCRY0*YgB#g=ps*NCv0t+!jJpl}HQxEGGmc4S{+7=j$Ig@61*%{$f{ajtSBe1ir zS@oRo@Y3njXT`Aj3Wbur6uYhoyWl`=;1Id14pv_2%Hi@SSX0uEqw$;pQs=a=~7(tL$4 zqiO5kWqevDGPK^c@08K@5qYC#-s`gKtC#kN1Yb7yDw9_1^!OE~_fTODuu*wVwed-T z>VMapYHqb`c{6@|f!8>m;^dJMz?hN9M~v?(I`Y)0(S*ji%R4>ptQ)6yrDj~BW~t`s zu2Pny+98S@t2m!qh-VHeT|4k?__x8eJrffZ!xYLVa%XZROZ;2=fh-VJH#ZxQcfCm< z2iMUAc(c;3WBOSsDUU1x(4&Eq>IeUvq~7=9|EI*kvjAH)y@ByU->YcBm5A;f{_f#=O%2=yjU+`KZuP+kTCJ7u=G|OA? z$jjcLs^BDaZ<7{oM>ls%7xznsp<^lJhK0r%K%|bOgc|FZzysg7Oiz7ju$1D=aa-;c zf6gn)oHhZyD88$gEpwS5w*@)%P0h_YQlx#^=)m;}tVm;>Z*(;dcVa|YNjm&Z#5-a8 zPEZ{vb0EvWiW7C7vp)YBe;PqHMF2#Lx?PEBSC%wGglK@Qyv?|g@f5{J2n8>MepUQ{cM^V@L5Tm$P?Q7GVUt&%{s~2> zDi^{t`2xv>D+7Gkcyl)A4fWSvhrZfK%0s zy_z*^OX9O29t6NK`?fqkML|0_n65}0B$n)a+jt{hmN_&mE`yDVVrK7EM*Hz{FYq!? z9I&0SeAW%9*mF1!#btc3j-$R=D7z-|*0k{2aXJeWm}Ci9NDwY%y$=hF zj2RxYE1YvhU7_hQ?dWNSl&X;m;13@S(x+rnWS(2>REqlJ+3klT#6;GBOd^V1_aU>L zDJ#Vw24%G##0Xp$W%pyVM0&CnD(F)r?o4CCR;88kU*4(yd+x3QHCl%&d0b6j{;~x- zne%QCjPrRJqh*TxROdq#73HfFZQIMUDc!nClI{-*R&Hf>rK$z(j?G=syna?s?`S!X z+Z;8{b>Ve4oK)8`yJTQ^K04V{@i7Bp6J){f!H*6cN{563FYz>zjlGB2rjZz5I$2MF z>hQ@PRJjZ@|AMN@^8)n$#Y@=;fp{55>YUg4LzpG9VG|gGrhqV7oMNG3Wxw)(+{muH z75RtZ4#ujG3x@JHc-P<%c^)Dexd*&SD|1*=kO>7#GrLygs$wwx+k&{{_H>*w@tDB? zZa_6T;dOAy4P@=zcz(u{2cd-KeY2z#%Oo}0dqun4J9o^xg^*<{nBD+3rW=6(~aKDt(pB5R{#c5a*IQPaf2So9=owFDOQWVQSl zZt{kw7@q>=%cOBlJgA((P1)VyvQ96|5|o1&*mW6&PRm}p)Ec1l+Uwl6l>lN|8U|*n zGJ7iXI92uO`#nsMKMfK(W*l?2chxx58>1c$E>3RZ6W8iZZg=ji)0*?IKo%NzO=Vj6 zbg%3p)RSw*8oU_1&g#Imt<5&~l_P+zg56zsZv`&@nX32XK7E`YEW6O(2@)`ka=A>)(MN?%!c<;=9J zf;78%OqhDnBTLRn!EO2K9s0lX6g)nP&Av%H&Lagh<#sxZbp#%bum~!(A>JyBC^Fg3 z2smCU&L7k2ms$TXNgl6H0SsLd^3V;y~F2kyamL= zL&Qni)F#4DYW|NB1#8T><}qU6Q9x<30H&m*jJ5y8#+_4)(Ri9SUYo9QR%~|$CL5Nm z*3PH%maSv``4#M7SJ9vsdM2o%B@zeSX5i@|Ac8TtuIqFG#J;_*pn>?xg#EZ-2x9CX z9!23q)Ozp3a&PJev7#EXPsNd=S&?x;xa?D??j$X<&J_K)Qn}{Ns%;ud9fx}m2$2OK zBPoC8Tw@mdZY$U=45<3h_OOLq-xIFxi8MJ0JlNEI2~*j~@kyD7tZ$`=#o%BlL6CfS zbvv&;7>_eoQlhAT6&0S`Y&`9)-qpG0^8OO{xlBu9zLX{%{t2-RShO5#!0u2|a{m5n zF5fuDp6rUL`j78(16|u~`&UeDASIofUvuyVa#s28H+~&*<2CamUn|266l?o6XKtX8 zn_mqR8|d}-U&+`8`rm+mskR%F@#LFdd;|S&O8?%M|JyWwISw~A#{c&?TnB8weQa|5 T3!#5wHtf$i|AMjo?fSm}4>7;x literal 0 HcmV?d00001 diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 2058f41b26..0390a1a1c6 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -270,6 +270,13 @@ For instance, the following two circuit generations are equivalent: circuit_2.add(gates.X(2)) +.. image:: ../_static/comp_basis_encoder.png + :width: 3400px + :height: 2000px + :scale: 25 % + :align: center + + .. autofunction:: qibo.models.encodings.comp_basis_encoder From 8e719a395d5ad48ea2b4df99a697f68e047680e9 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 5 Feb 2024 12:30:54 +0400 Subject: [PATCH 120/200] add `SiSWAPDG` gate --- src/qibo/backends/__init__.py | 1 + src/qibo/backends/npmatrices.py | 12 ++++++++++++ src/qibo/gates/gates.py | 33 +++++++++++++++++++++++++++++++++ tests/test_gates_gates.py | 2 ++ 4 files changed, 48 insertions(+) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 09e1fe1a54..9c99947881 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -115,6 +115,7 @@ def create(self, dtype): self.SWAP = self.matrices.SWAP self.iSWAP = self.matrices.iSWAP self.SiSWAP = self.matrices.SiSWAP + self.SiSWAPDG = self.matrices.SiSWAPDG self.FSWAP = self.matrices.FSWAP self.ECR = self.matrices.ECR self.SYC = self.matrices.SYC diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index 364845c514..ee65e90275 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -206,6 +206,18 @@ def SiSWAP(self): dtype=self.dtype, ) + @cached_property + def SiSWAPDG(self): + return self.np.array( + [ + [1, 0, 0, 0], + [0, 1 / self.np.sqrt(2), -1j / self.np.sqrt(2), 0], + [0, -1j / self.np.sqrt(2), 1 / self.np.sqrt(2), 0], + [0, 0, 0, 1], + ], + dtype=self.dtype, + ) + @cached_property def FSWAP(self): return self.np.array( diff --git a/src/qibo/gates/gates.py b/src/qibo/gates/gates.py index aa0e0d5ede..128518a89e 100644 --- a/src/qibo/gates/gates.py +++ b/src/qibo/gates/gates.py @@ -1533,6 +1533,39 @@ def __init__(self, q0, q1): self.init_args = [q0, q1] self.unitary = True + def _dagger(self) -> "Gate": + return SiSWAPDG(*self.qubits) + + +class SiSWAPDG(Gate): + """The :math:`\\sqrt{\\text{iSWAP}}}^{\\dagger}` gate. + + Corresponds to the following unitary matrix + + .. math:: + \\begin{pmatrix} + 1 & 0 & 0 & 0 \\\\ + 0 & 1/\\sqrt{2} & -i/\\sqrt{2} & 0 \\\\ + 0 & -i/\\sqrt{2} & 1/\\sqrt{2} & 0 \\\\ + 0 & 0 & 0 & 1 \\\\ + \\end{pmatrix} + + Args: + q0 (int): the first qubit to be swapped id number. + q1 (int): the second qubit to be swapped id number. + """ + + def __init__(self, q0, q1): + super().__init__() + self.name = "siswapdg" + self.draw_label = "sidg" + self.target_qubits = (q0, q1) + self.init_args = [q0, q1] + self.unitary = True + + def _dagger(self) -> "Gate": + return SiSWAP(*self.qubits) + class FSWAP(Gate): """The fermionic swap gate. diff --git a/tests/test_gates_gates.py b/tests/test_gates_gates.py index e014031eac..caabc73e57 100644 --- a/tests/test_gates_gates.py +++ b/tests/test_gates_gates.py @@ -1546,6 +1546,8 @@ def test_controlled_unitary_matrix(backend): ("GIVENS", (0, 1, 0.1)), ("RBS", (0, 1, 0.2)), ("ECR", (0, 1)), + ("SiSWAP", (0, 1)), + ("SiSWAPDG", (0, 1)), ] From a72a265b64e550e77ea642269d993b9ff809aa08 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Mon, 5 Feb 2024 12:49:12 +0400 Subject: [PATCH 121/200] concise test --- tests/test_quantum_info_random.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_quantum_info_random.py b/tests/test_quantum_info_random.py index b91ad4862a..0749723637 100644 --- a/tests/test_quantum_info_random.py +++ b/tests/test_quantum_info_random.py @@ -238,8 +238,7 @@ def test_random_statevector(backend, seed): # tests if random statevector is a pure state dims = 4 state = random_statevector(dims, seed=seed, backend=backend) - backend.assert_allclose(purity(state) <= 1.0 + PRECISION_TOL, True) - backend.assert_allclose(purity(state) >= 1.0 - PRECISION_TOL, True) + backend.assert_allclose(abs(purity(state) - 1.0) < PRECISION_TOL, True) @pytest.mark.parametrize("normalize", [False, True]) From e7afae18fbdaf69b41f2dad19c479deaaa3e732e Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Mon, 5 Feb 2024 15:41:37 +0400 Subject: [PATCH 122/200] added warning if connectivity is passed to star transpiler --- src/qibo/transpiler/placer.py | 10 +++++++--- src/qibo/transpiler/router.py | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/qibo/transpiler/placer.py b/src/qibo/transpiler/placer.py index c6b1f8f5fb..d57cc95428 100644 --- a/src/qibo/transpiler/placer.py +++ b/src/qibo/transpiler/placer.py @@ -4,7 +4,7 @@ import networkx as nx from qibo import gates -from qibo.config import raise_error +from qibo.config import log, raise_error from qibo.models import Circuit from qibo.transpiler._exceptions import PlacementError from qibo.transpiler.abstract import Placer, Router @@ -101,14 +101,18 @@ class StarConnectivityPlacer(Placer): def __init__(self, connectivity=None, middle_qubit: int = 2): self.middle_qubit = middle_qubit - self.connectivity = connectivity + if connectivity is not None: # pragma: no cover + log.warning( + "StarConnectivityRouter does not use the connectivity graph." + "The connectivity graph will be ignored." + ) def __call__(self, circuit: Circuit): """Apply the transpiler transformation on a given circuit. Args: circuit (:class:`qibo.models.circuit.Circuit`): The original Qibo circuit to transform. - This circuit must contain up to two-qubit gates. + Only single qubit gates and two qubits gates are supported by the router. Returns: (dict): physical to logical qubit mapping. diff --git a/src/qibo/transpiler/router.py b/src/qibo/transpiler/router.py index 82f6ac1b7e..8a3bf54180 100644 --- a/src/qibo/transpiler/router.py +++ b/src/qibo/transpiler/router.py @@ -5,7 +5,7 @@ import networkx as nx from qibo import gates -from qibo.config import raise_error +from qibo.config import log, raise_error from qibo.models import Circuit from qibo.transpiler._exceptions import ConnectivityError from qibo.transpiler.abstract import Router @@ -60,14 +60,18 @@ class StarConnectivityRouter(Router): def __init__(self, connectivity=None, middle_qubit: int = 2): self.middle_qubit = middle_qubit - self.connectivity = connectivity + if connectivity is not None: # pragma: no cover + log.warning( + "StarConnectivityRouter does not use the connectivity graph." + "The connectivity graph will be ignored." + ) def __call__(self, circuit: Circuit, initial_layout: dict): """Apply the transpiler transformation on a given circuit. Args: circuit (:class:`qibo.models.circuit.Circuit`): The original Qibo circuit to transform. - This circuit must contain up to two-qubit gates. + Only single qubit gates and two qubits gates are supported by the router. initial_layout (dict): initial physical-to-logical qubit mapping, use `qibo.transpiler.placer.StarConnectivityPlacer` for better performance. From 73d8ba6ffff57cc19fe0be5413d7014836039e9c Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Mon, 5 Feb 2024 15:48:46 +0400 Subject: [PATCH 123/200] avoid log raise in default trasnpiler pipeline --- src/qibo/transpiler/pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/transpiler/pipeline.py b/src/qibo/transpiler/pipeline.py index 4452a90eca..06b047d773 100644 --- a/src/qibo/transpiler/pipeline.py +++ b/src/qibo/transpiler/pipeline.py @@ -206,9 +206,9 @@ def default(self): # preprocessing default_passes.append(Preprocessing(connectivity=self.connectivity)) # default placer pass - default_passes.append(StarConnectivityPlacer(connectivity=self.connectivity)) + default_passes.append(StarConnectivityPlacer()) # default router pass - default_passes.append(StarConnectivityRouter(connectivity=self.connectivity)) + default_passes.append(StarConnectivityRouter()) # default unroller pass default_passes.append(Unroller(native_gates=self.native_gates)) From f0ba5adfa670cb61d145aff353b5f04a3f4d179a Mon Sep 17 00:00:00 2001 From: Canoming Date: Mon, 5 Feb 2024 22:16:48 +0800 Subject: [PATCH 124/200] update doc strings for `QuantumNetwork` --- src/qibo/quantum_info/quantum_networks.py | 34 ++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 89c9a6a8e2..f7ea285373 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -1,4 +1,4 @@ -"""Module defining the QuantumNetwork class and adjacent functions.""" +"""Module defining the `QuantumNetwork` class and adjacent functions.""" import re from functools import reduce @@ -12,7 +12,19 @@ class QuantumNetwork: - """Quantum network object that holds a Choi operator as a tensor. + """ Quantum network that unifies the representation of quantum states, channels, + observables, and higher-order quantum operators [1]_. The class stores the Choi operator of + the quantum network as a tensor, which is an unique representation of the quantum network. + + A minimum quantum network is a quantum channel, which is a quantum network of the form + `J[n -> m]`, where `n` is the dimension of the input system and `m` is the dimension of the + output system. A quantum state is a quantum network of the form `J[1 -> n]`, such that the + input system is trivial. An observable is a quantum network of the form `J[n -> 1]`, such that + the output system is trivial. + + A quantum network may contain multipy input systems and output systems. For example, a + "quantum comb" is a quantum network of the form `J[n', n -> m, m']`, which convert a quantum + channel of the form `J[n -> m]` to a quantum channel of the form `J[n' -> m']`. Args: matrix (ndarray): input Choi operator. @@ -21,11 +33,15 @@ class QuantumNetwork: Choi operator. If ``None``, defaults to ``(False,True,False,True,...)``, where ``len(system_output)=len(partition)``. Defaults to ``None``. - pure (bool, optional): ``True`` when ``matrix`` is a rank-:math:`1` operator, - ``False`` otherwise. Defaults to ``False``. + pure (bool, optional): ``True`` when ``matrix`` is a "pure" representation (e.g. a pure + state, a unitary operator, etc.), ``False`` otherwise. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + + References: + 1. G. Chiribella *et al.*, *Theoretical framework for quantum networks.* + `Physical Review A 80.2 (2009): 022339 `. """ def __init__( @@ -426,6 +442,11 @@ def __add__(self, second_network): def __mul__(self, number: Union[float, int]): """Returns quantum network with its Choi operator multiplied by a scalar. + If the quantum network is pure and ``number > 0.0``, the method returns a pure quantum + network with its Choi operator multiplied by the square root of ``number``. + This is equivelant to multiplying `self.to_full()` by the ``number``. + Otherwise, this method will return a full quantum network. + Args: number (float or int): scalar to multiply the Choi operator of the network with. @@ -465,6 +486,11 @@ def __rmul__(self, number: Union[float, int]): def __truediv__(self, number: Union[float, int]): """Returns quantum network with its Choi operator divided by a scalar. + If the quantum network is pure and ``number > 0.0``, the method returns a pure quantum + network with its Choi operator divided by the square root of ``number``. + This is equivelant to dividing `self.to_full()` by the ``number``. + Otherwise, this method will return a full quantum network. + Args: number (float or int): scalar to divide the Choi operator of the network with. From 09256fcc71c09037cf23ac93c18e4d049e5fda65 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:42:32 +0000 Subject: [PATCH 125/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/quantum_networks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index f7ea285373..41c4c4acd4 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -12,7 +12,7 @@ class QuantumNetwork: - """ Quantum network that unifies the representation of quantum states, channels, + """Quantum network that unifies the representation of quantum states, channels, observables, and higher-order quantum operators [1]_. The class stores the Choi operator of the quantum network as a tensor, which is an unique representation of the quantum network. From a0a4c5321e63ee81e150215801fec8c5e36fbaaf Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 08:33:24 +0400 Subject: [PATCH 126/200] small fixes --- src/qibo/quantum_info/quantum_networks.py | 64 +++++++++++---------- tests/test_quantum_info_quantum_networks.py | 28 ++++----- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 41c4c4acd4..5ae8902d43 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -12,19 +12,24 @@ class QuantumNetwork: - """Quantum network that unifies the representation of quantum states, channels, - observables, and higher-order quantum operators [1]_. The class stores the Choi operator of - the quantum network as a tensor, which is an unique representation of the quantum network. + """Quantum network is an object that unifies the representation of quantum states, channels, + observables, and higher-order quantum operators [1]. - A minimum quantum network is a quantum channel, which is a quantum network of the form - `J[n -> m]`, where `n` is the dimension of the input system and `m` is the dimension of the - output system. A quantum state is a quantum network of the form `J[1 -> n]`, such that the - input system is trivial. An observable is a quantum network of the form `J[n -> 1]`, such that - the output system is trivial. + This class stores the Choi operator of the quantum network as a tensor, + which is an unique representation of the quantum network. - A quantum network may contain multipy input systems and output systems. For example, a - "quantum comb" is a quantum network of the form `J[n', n -> m, m']`, which convert a quantum - channel of the form `J[n -> m]` to a quantum channel of the form `J[n' -> m']`. + A minimum quantum network is a quantum channel, which is a quantum network of the form + :math:`J[n \\to m]`, where :math:`n` is the dimension of the input system , + and :math:`m` is the dimension of the output system. + A quantum state is a quantum network of the form :math:`J[1 \\to n]`, + such that the input system is trivial. + An observable is a quantum network of the form :math:`J[n \\to 1]`, + such that the output system is trivial. + + A quantum network may contain multiple input and output systems. + For example, a "quantum comb" is a quantum network of the form :math:`J[n', n \\to m, m']`, + which convert a quantum channel of the form :math:`J[n \\to m]` + to a quantum channel of the form :math:`J[n' \\to m']`. Args: matrix (ndarray): input Choi operator. @@ -41,7 +46,7 @@ class QuantumNetwork: References: 1. G. Chiribella *et al.*, *Theoretical framework for quantum networks.* - `Physical Review A 80.2 (2009): 022339 `. + `Physical Review A 80.2 (2009): 022339 `_. """ def __init__( @@ -58,7 +63,7 @@ def __init__( self.partition = partition self.system_output = system_output self._pure = pure - self._backend = backend if backend is not None else GlobalBackend() + self._backend = backend self.dims = reduce(mul, self.partition) self._set_tensor_and_parameters() @@ -80,11 +85,11 @@ def matrix(self, backend=None): return backend.cast(self._matrix, dtype=self._matrix.dtype) - def pure(self): + def is_pure(self): """Returns bool indicading if the Choi operator of the network is pure.""" return self._pure - def hermitian( + def is_hermitian( self, order: Optional[Union[int, str]] = None, precision_tol: float = 1e-8 ): """Returns bool indicating if the Choi operator :math:`\\mathcal{E}` of the network is Hermitian. @@ -130,7 +135,7 @@ def hermitian( return float(norm) <= precision_tol - def unital( + def is_unital( self, order: Optional[Union[int, str]] = None, precision_tol: float = 1e-8 ): """Returns bool indicating if the Choi operator :math:`\\mathcal{E}` of the network is unital. @@ -178,7 +183,7 @@ def unital( return float(norm) <= precision_tol - def causal( + def is_causal( self, order: Optional[Union[int, str]] = None, precision_tol: float = 1e-8 ): """Returns bool indicating if the Choi operator :math:`\\mathcal{E}` of the network satisfies the causal order condition. @@ -226,7 +231,7 @@ def causal( return float(norm) <= precision_tol - def positive_semidefinite(self, precision_tol: float = 1e-8): + def is_positive_semidefinite(self, precision_tol: float = 1e-8): """Returns bool indicating if Choi operator :math:`\\mathcal{E}` of the network is positive-semidefinite. Args: @@ -244,7 +249,7 @@ def positive_semidefinite(self, precision_tol: float = 1e-8): reshaped = np.reshape(self._matrix, (self.dims, self.dims)) - if self.hermitian(): + if self.is_hermitian(): eigenvalues = np.linalg.eigvalsh(reshaped) else: if self._backend.__class__.__name__ in [ @@ -256,7 +261,7 @@ def positive_semidefinite(self, precision_tol: float = 1e-8): return all(eigenvalue >= -precision_tol for eigenvalue in eigenvalues) - def channel( + def is_channel( self, order: Optional[Union[int, str]] = None, precision_tol_causal: float = 1e-8, @@ -279,9 +284,9 @@ def channel( Returns: bool: Channel condition. """ - return self.causal(order, precision_tol_causal) and self.positive_semidefinite( - precision_tol_psd - ) + return self.is_causal( + order, precision_tol_causal + ) and self.is_positive_semidefinite(precision_tol_psd) def apply(self, state): """Apply the Choi operator :math:`\\mathcal{E}` to ``state`` :math:`\\varrho`. @@ -296,7 +301,7 @@ def apply(self, state): """ matrix = np.copy(self._matrix) - if self.pure(): + if self.is_pure(): return np.einsum("kj,ml,jl -> km", matrix, np.conj(matrix), state) return np.einsum("jklm,km -> jl", matrix, state) @@ -392,7 +397,7 @@ def to_full(self, backend=None): if backend is None: # pragma: no cover backend = self._backend - if self.pure(): + if self.is_pure(): self._matrix = self._full() self._pure = False @@ -460,7 +465,7 @@ def __mul__(self, number: Union[float, int]): "It is not possible to multiply a ``QuantumNetwork`` by a non-scalar.", ) - if self.pure() and number > 0.0: + if self.is_pure() and number > 0.0: return QuantumNetwork( np.sqrt(number) * self.matrix(backend=self._backend), partition=self.partition, @@ -504,12 +509,13 @@ def __truediv__(self, number: Union[float, int]): "It is not possible to divide a ``QuantumNetwork`` by a non-scalar.", ) - number = np.sqrt(number) if self.pure() and number > 0.0 else number + number = np.sqrt(number) if self.is_pure() and number > 0.0 else number + return QuantumNetwork( self.matrix(backend=self._backend) / number, partition=self.partition, system_output=self.system_output, - pure=self.pure(), + pure=self.is_pure(), backend=self._backend, ) @@ -643,7 +649,7 @@ def _set_tensor_and_parameters(self): def _full(self): """Reshapes input matrix based on purity.""" matrix = np.copy(self._matrix) - if self.pure(): + if self.is_pure(): matrix = np.einsum("jk,lm -> kjml", matrix, np.conj(matrix)) return matrix diff --git a/tests/test_quantum_info_quantum_networks.py b/tests/test_quantum_info_quantum_networks.py index a84103ece5..e02537eae1 100644 --- a/tests/test_quantum_info_quantum_networks.py +++ b/tests/test_quantum_info_quantum_networks.py @@ -46,13 +46,13 @@ def test_errors(backend): QuantumNetwork(channel.to_choi(backend=backend), partition=(1, 2), pure="True") with pytest.raises(ValueError): - network.hermitian(precision_tol=-1e-8) + network.is_hermitian(precision_tol=-1e-8) with pytest.raises(ValueError): - network.unital(precision_tol=-1e-8) + network.is_unital(precision_tol=-1e-8) with pytest.raises(ValueError): - network.causal(precision_tol=-1e-8) + network.is_causal(precision_tol=-1e-8) with pytest.raises(TypeError): network + 1 @@ -155,11 +155,11 @@ def test_parameters(backend): backend.assert_allclose(network.partition, partition) backend.assert_allclose(network.system_output, (False, True)) - assert network.causal() - assert network.unital() - assert network.hermitian() - assert network.positive_semidefinite() - assert network.channel() + assert network.is_causal() + assert network.is_unital() + assert network.is_hermitian() + assert network.is_positive_semidefinite() + assert network.is_channel() def test_with_states(backend): @@ -186,8 +186,8 @@ def test_with_states(backend): state_output_link.matrix(backend=backend).reshape((dims, dims)), state_output ) - assert network_state.hermitian() - assert network_state.positive_semidefinite() + assert network_state.is_hermitian() + assert network_state.is_positive_semidefinite() @pytest.mark.parametrize("subscript", ["jk,kl->jl", "jk,lj->lk"]) @@ -265,9 +265,9 @@ def test_non_hermitian_and_prints(backend): matrix = random_gaussian_matrix(dims**2, backend=backend) network = QuantumNetwork(matrix, (dims, dims), pure=False, backend=backend) - assert not network.hermitian() - assert not network.causal() - assert not network.positive_semidefinite() - assert not network.channel() + assert not network.is_hermitian() + assert not network.is_causal() + assert not network.is_positive_semidefinite() + assert not network.is_channel() assert network.__str__() == "J[4 -> 4]" From f6a794f7b5c11f0ba1e14addb3fa9586a1c18c24 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 09:06:48 +0400 Subject: [PATCH 127/200] add function --- src/qibo/backends/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 09e1fe1a54..04f26d870b 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -167,3 +167,10 @@ def set_threads(nthreads): if nthreads < 1: raise_error(ValueError, "Number of threads must be positive.") GlobalBackend().set_threads(nthreads) + + +def _check_backend(backend): # pragma: no cover + if backend is None: + return GlobalBackend() + + return backend From 6470632ba271a52676d7f3d2eaab31f75c2b0390 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 09:06:53 +0400 Subject: [PATCH 128/200] replacements --- src/qibo/gates/abstract.py | 8 +++--- src/qibo/gates/channels.py | 11 +++----- src/qibo/gates/special.py | 5 ++-- src/qibo/hamiltonians/hamiltonians.py | 20 +++++---------- src/qibo/models/circuit.py | 15 +++++------ src/qibo/models/error_mitigation.py | 37 ++++++++++++--------------- src/qibo/models/grover.py | 10 +++----- src/qibo/models/hep.py | 7 ++--- src/qibo/models/iqae.py | 6 ++--- src/qibo/models/tsp.py | 8 +++--- src/qibo/optimizers.py | 12 ++++----- src/qibo/parallel.py | 11 +++----- src/qibo/result.py | 6 ++--- 13 files changed, 62 insertions(+), 94 deletions(-) diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index d9f49f6a5e..a9b4ef0c2c 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -4,7 +4,7 @@ import sympy -from qibo.backends import CliffordBackend, GlobalBackend +from qibo.backends import _check_backend from qibo.config import raise_error REQUIRED_FIELDS = [ @@ -361,8 +361,7 @@ def matrix(self, backend=None): ``Gate.matrix`` was defined as an atribute in ``qibo`` versions prior to ``0.2.0``. From ``0.2.0`` on, it has been converted into a method and has replaced the ``asmatrix`` method. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) return backend.matrix(self) @@ -481,7 +480,6 @@ def substitute_symbols(self): self.parameters = tuple(params) def matrix(self, backend=None): - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) return backend.matrix_parametrized(self) diff --git a/src/qibo/gates/channels.py b/src/qibo/gates/channels.py index c620738da8..9616c59974 100644 --- a/src/qibo/gates/channels.py +++ b/src/qibo/gates/channels.py @@ -6,7 +6,7 @@ import numpy as np -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import PRECISION_TOL, raise_error from qibo.gates.abstract import Gate from qibo.gates.gates import I, Unitary, X, Y, Z @@ -80,8 +80,7 @@ def to_choi(self, nqubits: Optional[int] = None, order: str = "row", backend=Non vectorization, ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) nqubits = 1 + max(self.target_qubits) if nqubits is None else nqubits @@ -128,8 +127,7 @@ def to_liouville(self, nqubits: int = None, order: str = "row", backend=None): choi_to_liouville, ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) super_op = self.to_choi(nqubits=nqubits, order=order, backend=backend) super_op = choi_to_liouville(super_op, order=order, backend=backend) @@ -166,8 +164,7 @@ def to_pauli_liouville( from qibo.quantum_info.basis import comp_basis_to_pauli # pylint: disable=C0415 - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) super_op = self.to_liouville(nqubits=nqubits, backend=backend) diff --git a/src/qibo/gates/special.py b/src/qibo/gates/special.py index 5243b9fa52..3824f3672c 100644 --- a/src/qibo/gates/special.py +++ b/src/qibo/gates/special.py @@ -1,4 +1,4 @@ -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.gates.abstract import SpecialGate from qibo.gates.measurements import M @@ -104,8 +104,7 @@ def matrix(self, backend=None): Returns: ndarray: Matrix representation of special gate. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) return backend.matrix_fused(self) diff --git a/src/qibo/hamiltonians/hamiltonians.py b/src/qibo/hamiltonians/hamiltonians.py index 6354bf316b..10b9419580 100644 --- a/src/qibo/hamiltonians/hamiltonians.py +++ b/src/qibo/hamiltonians/hamiltonians.py @@ -24,14 +24,9 @@ class Hamiltonian(AbstractHamiltonian): """ def __init__(self, nqubits, matrix=None, backend=None): - if backend is None: # pragma: no cover - from qibo.backends import ( # pylint: disable=import-outside-toplevel - GlobalBackend, - ) + from qibo.backends import _check_backend - self.backend = GlobalBackend() - else: - self.backend = backend + self.backend = _check_backend(backend) if not ( isinstance(matrix, self.backend.tensor_types) @@ -355,14 +350,11 @@ def __init__(self, form=None, nqubits=None, symbol_map={}, backend=None): from qibo.symbols import Symbol # pylint: disable=import-outside-toplevel self._qiboSymbol = Symbol # also used in ``self._get_symbol_matrix`` - if backend is None: # pragma: no cover - from qibo.backends import ( # pylint: disable=import-outside-toplevel - GlobalBackend, - ) - self.backend = GlobalBackend() - else: - self.backend = backend + from qibo.backends import _check_backend + + self.backend = _check_backend(backend) + if form is not None: self.form = form if nqubits is not None: diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index 419f5635d2..e15223f9ef 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1000,14 +1000,13 @@ def fuse(self, max_qubits=2): def unitary(self, backend=None): """Creates the unitary matrix corresponding to all circuit gates. - This is a ``(2 ** nqubits, 2 ** nqubits)`` matrix obtained by - multiplying all circuit gates. + This is a :math:`2^{n} \\times 2^{n}`` matrix obtained by + multiplying all circuit gates, where :math:`n` is ``nqubits``. """ - if backend is None: - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend - backend = GlobalBackend() + backend = _check_backend(backend) fgate = gates.FusedGate(*range(self.nqubits)) for gate in self.queue: @@ -1050,10 +1049,10 @@ def compile(self, backend=None): NotImplementedError, "Circuit compilation is not available with callbacks.", ) - if backend is None: - from qibo.backends import GlobalBackend - backend = GlobalBackend() + from qibo.backends import _check_backend + + backend = _check_backend(backend) from qibo.result import CircuitResult, QuantumState diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 1f69c07a10..9af448c564 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -6,7 +6,7 @@ from scipy.optimize import curve_fit from qibo import gates -from qibo.backends import GlobalBackend +from qibo.backends import GlobalBackend, _check_backend from qibo.config import raise_error @@ -148,8 +148,8 @@ def ZNE( 1. K. Temme, S. Bravyi et al, *Error mitigation for short-depth quantum circuits*. `arXiv:1612.02058 [quant-ph] `_. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) + if readout is None: readout = {} @@ -197,8 +197,7 @@ def sample_training_circuit_cdr( Returns: :class:`qibo.models.Circuit`: The sampled circuit. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if replacement_gates is None: replacement_gates = [(gates.RZ, {"theta": n * np.pi / 2}) for n in range(4)] @@ -303,8 +302,8 @@ def CDR( 1. P. Czarnik, A. Arrasmith et al, *Error mitigation with Clifford quantum-circuit data*. `arXiv:2005.10189 [quant-ph] `_. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) + if readout is None: readout = {} @@ -390,8 +389,8 @@ def vnCDR( 1. A. Lowe, MH. Gordon et al, *Unified approach to data-driven quantum error mitigation*. `arXiv:2011.01157 [quant-ph] `_. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) + if readout is None: readout = {} @@ -495,8 +494,7 @@ def get_response_matrix( """ from qibo import Circuit # pylint: disable=import-outside-toplevel - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) response_matrix = np.zeros((2**nqubits, 2**nqubits)) @@ -599,8 +597,7 @@ def apply_randomized_readout_mitigation( random_pauli, ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) meas_qubits = circuit.measurements[0].qubits nshots_r = int(nshots / ncircuits) @@ -672,8 +669,8 @@ def get_expectation_val_with_readout_mitigation( Returns: float: the mitigated expectation value of the observable. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) + if readout is None: # pragma: no cover readout = {} @@ -719,8 +716,7 @@ def sample_clifford_training_circuit( random_clifford, ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) non_clifford_gates_indices = [ i @@ -783,8 +779,7 @@ def error_sensitive_circuit(circuit, observable, backend=None): vectorization, ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) sampled_circuit = sample_clifford_training_circuit(circuit, backend=backend) unitary_matrix = sampled_circuit.unitary(backend=backend) @@ -882,8 +877,8 @@ def ICS( 1. Dayue Qin, Yanzhu Chen et al, *Error statistics and scalability of quantum error mitigation formulas*. `arXiv:2112.06255 [quant-ph] `_. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) + if readout is None: readout = {} diff --git a/src/qibo/models/grover.py b/src/qibo/models/grover.py index 2da268aa97..c18fab512e 100644 --- a/src/qibo/models/grover.py +++ b/src/qibo/models/grover.py @@ -188,10 +188,9 @@ def iterative_grover(self, lamda_value=6 / 5, backend=None): measured (str): bitstring measured and checked as a valid solution. total_iterations (int): number of times the oracle has been called. """ - if backend is None: # pragma: no cover - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend - backend = GlobalBackend() + backend = _check_backend(backend) k = 1 lamda = lamda_value @@ -225,10 +224,9 @@ def execute(self, nshots=100, freq=False, logs=False, backend=None): solution (str): bitstring (or list of bitstrings) measured as solution of the search. iterations (int): number of oracle calls done to reach a solution. """ - if backend is None: # pragma: no cover - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend - backend = GlobalBackend() + backend = _check_backend(backend) if (self.num_sol or self.targ_a) and not self.iterative: if self.targ_a: diff --git a/src/qibo/models/hep.py b/src/qibo/models/hep.py index 13466cab4e..e03429136e 100644 --- a/src/qibo/models/hep.py +++ b/src/qibo/models/hep.py @@ -41,12 +41,9 @@ def __init__(self, ansatz, layers, nqubits, multi_output=False, backend=None): self.circuit, self.rotation, self.nparams = ansatz_function(layers, nqubits) # load backend - if backend is None: # pragma: no cover - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend - self.backend = GlobalBackend() - else: - self.backend = backend + self.backend = _check_backend(backend) # load hamiltonian if multi_output: diff --git a/src/qibo/models/iqae.py b/src/qibo/models/iqae.py index 081c787a1a..caf28e72b7 100644 --- a/src/qibo/models/iqae.py +++ b/src/qibo/models/iqae.py @@ -264,10 +264,10 @@ def execute(self, backend=None): Returns: A :class:`qibo.models.iqae.IterativeAmplitudeEstimationResult` results object. """ - if backend is None: - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend + + backend = _check_backend(backend) - backend = GlobalBackend() # Initializing all parameters k = [0] # uppercase_k=4k+2 diff --git a/src/qibo/models/tsp.py b/src/qibo/models/tsp.py index 3db11f818e..250360aa84 100644 --- a/src/qibo/models/tsp.py +++ b/src/qibo/models/tsp.py @@ -135,12 +135,10 @@ def qaoa_function_of_layer(layer, distance_matrix): """ def __init__(self, distance_matrix, backend=None): - if backend is None: # pragma: no cover - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend + + self.backend = _check_backend(backend) - self.backend = GlobalBackend() - else: - self.backend = backend self.distance_matrix = distance_matrix self.num_cities = distance_matrix.shape[0] self.two_to_one = calculate_two_to_one(self.num_cities) diff --git a/src/qibo/optimizers.py b/src/qibo/optimizers.py index 92eed2fbeb..0b5c46c778 100644 --- a/src/qibo/optimizers.py +++ b/src/qibo/optimizers.py @@ -86,16 +86,16 @@ def myloss(parameters, circuit): ) return cmaes(loss, initial_parameters, args, options) elif method == "sgd": - if backend is None: - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend + + backend = _check_backend(backend) - backend = GlobalBackend() return sgd(loss, initial_parameters, args, options, compile, backend) else: - if backend is None: - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend + + backend = _check_backend(backend) - backend = GlobalBackend() return newtonian( loss, initial_parameters, diff --git a/src/qibo/parallel.py b/src/qibo/parallel.py index 0bbf84f055..22a65fafe7 100644 --- a/src/qibo/parallel.py +++ b/src/qibo/parallel.py @@ -6,7 +6,7 @@ from joblib import Parallel, delayed -from qibo.backends import GlobalBackend, set_threads +from qibo.backends import _check_backend from qibo.config import raise_error @@ -39,8 +39,7 @@ def parallel_execution(circuit, states, processes=None, backend=None): Returns: Circuit evaluation for input states. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if states is None or not isinstance(states, list): # pragma: no cover raise_error(TypeError, "states must be a list.") @@ -88,8 +87,7 @@ def parallel_circuits_execution( Returns: Circuit evaluation for input states. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if not isinstance(circuits, Iterable): # pragma: no cover raise_error(TypeError, "circuits must be iterable.") @@ -165,8 +163,7 @@ def parallel_parametrized_execution( Returns: Circuit evaluation for input parameters. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if not isinstance(parameters, list): # pragma: no cover raise_error(TypeError, "parameters must be a list.") diff --git a/src/qibo/result.py b/src/qibo/result.py index be095d5bfa..5d74157007 100644 --- a/src/qibo/result.py +++ b/src/qibo/result.py @@ -31,11 +31,9 @@ class QuantumState: """ def __init__(self, state, backend=None): - if backend is None: # pragma: no cover - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend - backend = GlobalBackend() - self.backend = backend + self.backend = _check_backend(backend) self.density_matrix = len(state.shape) == 2 self.nqubits = int(np.log2(state.shape[0])) self._state = state From aa91b01a81dab9ca00718010fd89c706a4fb5ffb Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 09:13:34 +0400 Subject: [PATCH 129/200] replacements --- src/qibo/quantum_info/basis.py | 11 ++--- src/qibo/quantum_info/metrics.py | 45 +++++++------------ src/qibo/quantum_info/quantum_networks.py | 5 +-- src/qibo/quantum_info/random_ensembles.py | 5 +-- .../superoperator_transformations.py | 38 ++++++---------- src/qibo/quantum_info/utils.py | 20 +++------ src/qibo/transpiler/unitary_decompositions.py | 14 +++--- 7 files changed, 49 insertions(+), 89 deletions(-) diff --git a/src/qibo/quantum_info/basis.py b/src/qibo/quantum_info/basis.py index 119cf78380..dcb5d7ab84 100644 --- a/src/qibo/quantum_info/basis.py +++ b/src/qibo/quantum_info/basis.py @@ -5,7 +5,7 @@ import numpy as np from qibo import matrices -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import raise_error from qibo.quantum_info.superoperator_transformations import vectorization @@ -89,8 +89,7 @@ def pauli_basis( "sparse representation is not implemented for unvectorized Pauli basis.", ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) pauli_labels = {"I": matrices.I, "X": matrices.X, "Y": matrices.Y, "Z": matrices.Z} basis_single = [pauli_labels[label] for label in pauli_order] @@ -187,8 +186,7 @@ def comp_basis_to_pauli( array with their row-wise indexes. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if sparse: elements, indexes = pauli_basis( @@ -258,8 +256,7 @@ def pauli_to_comp_basis( tuple is composed of array of non-zero elements and an array with their row-wise indexes. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) unitary = pauli_basis( nqubits, diff --git a/src/qibo/quantum_info/metrics.py b/src/qibo/quantum_info/metrics.py index eb29f1b486..41f4740f8f 100644 --- a/src/qibo/quantum_info/metrics.py +++ b/src/qibo/quantum_info/metrics.py @@ -5,7 +5,7 @@ import numpy as np from scipy import sparse -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import PRECISION_TOL, raise_error @@ -79,8 +79,7 @@ def concurrence(state, bipartition, check_purity: bool = True, backend=None): Returns: float: Concurrence of :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) not in [1, 2]) @@ -157,8 +156,7 @@ def entanglement_of_formation( Returns: float: entanglement of formation of state :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) from qibo.quantum_info.utils import shannon_entropy # pylint: disable=C0415 @@ -202,8 +200,7 @@ def entropy( Returns: float: The von-Neumann entropy :math:`S` of ``state`` :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) >= 3) @@ -289,8 +286,7 @@ def entanglement_entropy( Returns: float: Entanglement entropy :math:`S` of ``state`` :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if base <= 0.0: raise_error(ValueError, "log base must be non-negative.") @@ -348,8 +344,7 @@ def trace_distance(state, target, check_hermitian: bool = False, backend=None): Returns: float: Trace distance between ``state`` :math:`\\rho` and ``target`` :math:`\\sigma`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if state.shape != target.shape: raise_error( @@ -470,8 +465,7 @@ def fidelity(state, target, check_hermitian: bool = False, backend=None): Returns: float: Fidelity between ``state`` :math:`\\rho` and ``target`` :math:`\\sigma`. """ - if backend is None: - backend = GlobalBackend() + backend = _check_backend(backend) if state.shape != target.shape: raise_error( @@ -666,8 +660,7 @@ def entanglement_fidelity( Returns: float: Entanglement fidelity :math:`F_{\\mathcal{E}}`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(nqubits, int) is False: raise_error( @@ -733,8 +726,7 @@ def process_fidelity(channel, target=None, check_unitary: bool = False, backend= Returns: float: Process fidelity between ``channel`` and ``target``. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if target is not None: if channel.shape != target.shape: @@ -938,8 +930,8 @@ def diamond_norm(channel, target=None, backend=None, **kwargs): # `CVXPY` only works with `numpy`, so this function has to # convert any channel to the `numpy` backend by default - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) + channel = backend.to_numpy(channel) channel = np.transpose(channel) @@ -1025,8 +1017,7 @@ def meyer_wallach_entanglement(circuit, backend=None): float: Meyer-Wallach entanglement. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) circuit.density_matrix = True nqubits = circuit.nqubits @@ -1086,8 +1077,7 @@ def entangling_capability(circuit, samples: int, seed=None, backend=None): TypeError, "seed must be either type int or numpy.random.Generator." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) local_state = ( np.random.default_rng(seed) if seed is None or isinstance(seed, int) else seed @@ -1151,8 +1141,7 @@ def expressibility( pqc_integral, ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) deviation = haar_integral( circuit.nqubits, power_t, samples=None, backend=backend @@ -1214,8 +1203,7 @@ def frame_potential( TypeError, f"samples must be type int, but it is type {type(samples)}." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) nqubits = circuit.nqubits dim = 2**nqubits @@ -1259,8 +1247,7 @@ def _check_hermitian_or_not_gpu(matrix, backend=None): `backend` is not :class:`qibojit.backends.CupyBackend` """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) norm = backend.calculate_norm_density_matrix( np.transpose(np.conj(matrix)) - matrix, order=2 diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index af549a46fa..b9d5b01f96 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -7,7 +7,7 @@ import numpy as np -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import raise_error @@ -593,8 +593,7 @@ def _run_checks(self, partition, system_output, pure): def _set_tensor_and_parameters(self): """Sets tensor based on inputs.""" - if self._backend is None: - self._backend = GlobalBackend() + self._backend = _check_backend(self._backend) if isinstance(self.partition, list): self.partition = tuple(self.partition) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 18e2eedaa1..f8da6a6825 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -7,7 +7,7 @@ from scipy.stats import rv_continuous from qibo import Circuit, gates -from qibo.backends import GlobalBackend, NumpyBackend +from qibo.backends import NumpyBackend, _check_backend from qibo.config import MAX_ITERATIONS, PRECISION_TOL, raise_error from qibo.quantum_info.basis import comp_basis_to_pauli from qibo.quantum_info.superoperator_transformations import ( @@ -1201,8 +1201,7 @@ def _set_backend_and_local_state(seed, backend): TypeError, "seed must be either type int or numpy.random.Generator." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if seed is None or isinstance(seed, int): if backend.__class__.__name__ in [ diff --git a/src/qibo/quantum_info/superoperator_transformations.py b/src/qibo/quantum_info/superoperator_transformations.py index b91dadbeb1..c888ed5b18 100644 --- a/src/qibo/quantum_info/superoperator_transformations.py +++ b/src/qibo/quantum_info/superoperator_transformations.py @@ -6,7 +6,7 @@ import numpy as np from scipy.optimize import minimize -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import PRECISION_TOL, raise_error from qibo.gates.abstract import Gate from qibo.gates.gates import Unitary @@ -61,8 +61,7 @@ def vectorization(state, order: str = "row", backend=None): f"order must be either 'row' or 'column' or 'system', but it is {order}.", ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if len(state.shape) == 1: state = np.outer(state, np.conj(state)) @@ -130,8 +129,7 @@ def unvectorization(state, order: str = "row", backend=None): f"order must be either 'row' or 'column' or 'system', but it is {order}.", ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) dim = int(np.sqrt(len(state))) @@ -449,8 +447,7 @@ def choi_to_kraus( f"validate_cp must be type bool, but it is type {type(validate_cp)}.", ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if validate_cp: norm = float( @@ -652,8 +649,7 @@ def kraus_to_choi(kraus_ops, order: str = "row", backend=None): Returns: ndarray: Choi representation of the Kraus channel. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) gates, target_qubits = _set_gate_and_target_qubits(kraus_ops) nqubits = 1 + max(target_qubits) @@ -782,8 +778,7 @@ def kraus_to_chi( """ from qibo.quantum_info.basis import comp_basis_to_pauli - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) gates, target_qubits = _set_gate_and_target_qubits(kraus_ops) nqubits = 1 + max(target_qubits) @@ -845,8 +840,7 @@ def kraus_to_stinespring( Returns: ndarray: Stinespring representation (restricted unitary) of the Kraus channel. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if initial_state_env is not None: if len(initial_state_env) != len(kraus_ops): @@ -963,8 +957,7 @@ def liouville_to_pauli( """ from qibo.quantum_info.basis import comp_basis_to_pauli - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) dim = int(np.sqrt(len(super_op))) nqubits = int(np.log2(dim)) @@ -1165,8 +1158,7 @@ def pauli_to_liouville( """ from qibo.quantum_info.basis import pauli_to_comp_basis - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) dim = int(np.sqrt(len(pauli_op))) nqubits = int(np.log2(dim)) @@ -1873,8 +1865,7 @@ def stinespring_to_kraus( Returns: ndarray: Kraus operators. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(dim_env, int) is False: raise_error( @@ -2038,8 +2029,7 @@ def kraus_to_unitaries( if precision_tol < 0.0: raise_error(ValueError, "precision_tol must be non-negative.") - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) target_qubits = [q for q, _ in kraus_ops] nqubits = 1 + np.max(target_qubits) @@ -2148,8 +2138,7 @@ def _reshuffling(super_op, order: str = "row", backend=None): NotImplementedError, "reshuffling not implemented for system vectorization." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) dim = np.sqrt(super_op.shape[0]) @@ -2215,8 +2204,7 @@ def _individual_kraus_to_liouville( to be used in :func:`qibo.quantum_info.kraus_to_unitaries`. In principle, this should be not be accessible to users. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) gates, target_qubits = _set_gate_and_target_qubits(kraus_ops) nqubits = 1 + max(target_qubits) diff --git a/src/qibo/quantum_info/utils.py b/src/qibo/quantum_info/utils.py index c1e411360a..e099c96f8e 100644 --- a/src/qibo/quantum_info/utils.py +++ b/src/qibo/quantum_info/utils.py @@ -9,7 +9,7 @@ import numpy as np from qibo import matrices -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import PRECISION_TOL, raise_error @@ -134,8 +134,7 @@ def hadamard_transform(array, implementation: str = "fast", backend=None): Returns: ndarray: (Fast) Hadamard Transform of ``array``. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( len(array.shape) not in [1, 2] @@ -210,8 +209,7 @@ def shannon_entropy(probability_array, base: float = 2, backend=None): Returns: (float): The Shannon entropy :math:`H(\\mathcal{p})`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(probability_array, list): probability_array = backend.cast(probability_array, dtype=np.float64) @@ -281,8 +279,7 @@ def total_variation_distance( Returns: float: Total variation distance between :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(prob_dist_p, list): prob_dist_p = backend.cast(prob_dist_p, dtype=np.float64) @@ -341,8 +338,7 @@ def hellinger_distance(prob_dist_p, prob_dist_q, validate: bool = False, backend Returns: (float): Hellinger distance :math:`H(p, q)`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(prob_dist_p, list): prob_dist_p = backend.cast(prob_dist_p, dtype=np.float64) @@ -454,8 +450,7 @@ def haar_integral( TypeError, f"samples must be type int, but it is type {type(samples)}." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) dim = 2**nqubits @@ -529,8 +524,7 @@ def pqc_integral(circuit, power_t: int, samples: int, backend=None): TypeError, f"samples must be type int, but it is type {type(samples)}." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) circuit.density_matrix = True dim = 2**circuit.nqubits diff --git a/src/qibo/transpiler/unitary_decompositions.py b/src/qibo/transpiler/unitary_decompositions.py index e737ba649e..472347b0d4 100644 --- a/src/qibo/transpiler/unitary_decompositions.py +++ b/src/qibo/transpiler/unitary_decompositions.py @@ -1,7 +1,7 @@ import numpy as np from qibo import gates, matrices -from qibo.backends import GlobalBackend, NumpyBackend +from qibo.backends import NumpyBackend, _check_backend from qibo.config import raise_error magic_basis = np.array( @@ -50,8 +50,7 @@ def calculate_psi(unitary, magic_basis=magic_basis, backend=None): Returns: (ndarray) Eigenvectors in the computational basis and eigenvalues of :math:`U^{T} U`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if backend.__class__.__name__ in [ "CupyBackend", @@ -154,9 +153,8 @@ def calculate_diagonal(unitary, ua, ub, va, vb): def magic_decomposition(unitary, backend=None): - if backend is None: # pragma: no cover - backend = GlobalBackend() """Decomposes an arbitrary unitary to (A1) from arXiv:quant-ph/0011050.""" + backend = _check_backend(backend) psi, eigvals = calculate_psi(unitary, backend=backend) psi_tilde = np.conj(np.sqrt(eigvals)) * np.dot(unitary, psi) va, vb = calculate_single_qubit_unitaries(psi) @@ -167,8 +165,7 @@ def magic_decomposition(unitary, backend=None): def to_bell_diagonal(ud, bell_basis=bell_basis, backend=None): """Transforms a matrix to the Bell basis and checks if it is diagonal.""" - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) ud = backend.cast(ud) bell_basis = backend.cast(bell_basis, dtype=bell_basis.dtype) @@ -248,8 +245,7 @@ def two_qubit_decomposition(q0, q1, unitary, backend=None): Returns: (list): gates implementing decomposition (24) from arXiv:quant-ph/0307177 """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) ud_diag = to_bell_diagonal(unitary, backend=backend) ud = None From 211b72cd32a8e6439bbf38e3560d79a3174e5185 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 09:18:29 +0400 Subject: [PATCH 130/200] fix coverage --- tests/test_models_encodings.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_models_encodings.py b/tests/test_models_encodings.py index ac997460c2..63cae6836b 100644 --- a/tests/test_models_encodings.py +++ b/tests/test_models_encodings.py @@ -98,9 +98,10 @@ def test_phase_encoder(backend, rotation, kind): backend.assert_allclose(state, target) +@pytest.mark.parametrize("kind", [None, list]) @pytest.mark.parametrize("architecture", ["tree", "diagonal"]) @pytest.mark.parametrize("nqubits", [8]) -def test_unary_encoder(backend, nqubits, architecture): +def test_unary_encoder(backend, nqubits, architecture, kind): sampler = np.random.default_rng(1) with pytest.raises(TypeError): @@ -126,6 +127,9 @@ def test_unary_encoder(backend, nqubits, architecture): data = 2 * sampler.random(nqubits) - 1 data = backend.cast(data, dtype=data.dtype) + if kind is not None: + data = kind(data) + circuit = unary_encoder(data, architecture=architecture) state = backend.execute_circuit(circuit).state() indexes = np.flatnonzero(state) From 63212934298aa5eaa3966b0f7e8d1ac12f5f18c9 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 09:22:46 +0400 Subject: [PATCH 131/200] more replacements --- src/qibo/backends/clifford.py | 5 ++--- src/qibo/noise_model.py | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/qibo/backends/clifford.py b/src/qibo/backends/clifford.py index 9141ca2fd9..8189287f82 100644 --- a/src/qibo/backends/clifford.py +++ b/src/qibo/backends/clifford.py @@ -538,10 +538,9 @@ class CliffordBackend(NumpyBackend): def __init__(self, engine=None): super().__init__() - if engine is None: - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend - engine = GlobalBackend() + engine = _check_backend(engine) if isinstance(engine, TensorflowBackend): raise_error( diff --git a/src/qibo/noise_model.py b/src/qibo/noise_model.py index 892eb48743..44311c2661 100644 --- a/src/qibo/noise_model.py +++ b/src/qibo/noise_model.py @@ -341,10 +341,9 @@ def fit( from scipy.optimize import Bounds, direct - if backend == None: # pragma: no cover - from qibo.backends import GlobalBackend + from qibo.backends import _check_backend - backend = GlobalBackend() + backend = _check_backend(backend) nshots = target_result.nshots target_prob = freq_to_prob(target_result.frequencies()) From a87ef8509220d93a166d76fc779a12eec3d0216a Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 09:43:14 +0400 Subject: [PATCH 132/200] move couple of lines to `qibo.rst` --- doc/source/api-reference/qibo.rst | 7 +++++++ src/qibo/quantum_info/quantum_networks.py | 9 +-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 980faf2c70..6d83e5446c 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -1680,6 +1680,13 @@ Frame Potential Quantum Networks ^^^^^^^^^^^^^^^^ +Quantum network is an object that unifies the representation of quantum states, channels, +observables, and higher-order quantum operators. + +For more details, see G. Chiribella *et al.*, *Theoretical framework for quantum networks*, +`Physical Review A 80.2 (2009): 022339 +`_. + .. autoclass:: qibo.quantum_info.quantum_networks.QuantumNetwork :members: :member-order: bysource diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 5ae8902d43..a5ba0a77af 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -12,10 +12,7 @@ class QuantumNetwork: - """Quantum network is an object that unifies the representation of quantum states, channels, - observables, and higher-order quantum operators [1]. - - This class stores the Choi operator of the quantum network as a tensor, + """This class stores the Choi operator of the quantum network as a tensor, which is an unique representation of the quantum network. A minimum quantum network is a quantum channel, which is a quantum network of the form @@ -43,10 +40,6 @@ class QuantumNetwork: backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. - - References: - 1. G. Chiribella *et al.*, *Theoretical framework for quantum networks.* - `Physical Review A 80.2 (2009): 022339 `_. """ def __init__( From d8a56d063af5008333bdc58770fdced93ebc26ba Mon Sep 17 00:00:00 2001 From: Andrea Date: Tue, 6 Feb 2024 10:09:45 +0400 Subject: [PATCH 133/200] doc: Add possibility to show source code --- doc/source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/conf.py b/doc/source/conf.py index be2efea28d..4937bd5889 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -43,6 +43,7 @@ "sphinx.ext.napoleon", "sphinx.ext.intersphinx", "sphinx_copybutton", + "sphinx.ext.viewcode", "recommonmark", "nbsphinx", ] From 68ad0a24104ebfe5df53bc4cc5a50f8ef663e2a3 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 11:04:37 +0400 Subject: [PATCH 134/200] new figures --- doc/source/_static/unary_encoder_ladder.png | Bin 0 -> 186988 bytes doc/source/_static/unary_encoder_tree.png | Bin 0 -> 177114 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/source/_static/unary_encoder_ladder.png create mode 100644 doc/source/_static/unary_encoder_tree.png diff --git a/doc/source/_static/unary_encoder_ladder.png b/doc/source/_static/unary_encoder_ladder.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7672b18260f0c88b8a18f35cfa3649f3519cdb GIT binary patch literal 186988 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

-o!WsIELO>MjRxvaH! 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

2pfeBVSr>G_$}V96=wQ=g z@ZYFXtYP|-i@vm7i~YKTRY?*J5zrPyL@!m@+F@(U_-l{TgKoym0jH&(T-fAcD=I4; zZucozE#Io(eQjftviLU&)$}mExBJe-22ul|CF_#hZKI@L)L?67Nl|Pf4bZOs;bDsKoa;B0OxP)DX2QAT=Lx`6<36*{>BLk{~iutNOpMM{t z4)_Qfn+2{iRkih&u=zf85DSz{O-WAuo&@!^JQEEtI=V(`#@OBAAhRel#01jd>eK&~ z@vvsW9SAW@_Llz}XfG+ijcD=nz)2E^)p16cjx2uPYy1q`*tb`Vc0im4s{-Z> zgVGuk%uh3$uF(M1?tfHDHYh_gCsvljg4isN)?Y8qbh>E%3IgaFL;9==PYz&>p5C5G zk6pewyXY*fNITu$>MhA$sDSW#Y}B74Eu7>lW^s+*VOpDtbQql8tS)bC1#1Lp3}g(S}ANsE-wG2?SUBkM|CQ zC=K&h!OP1M^&><_34Odq(qG%w2SOSC)jE>AC9#Bvt=D!m4KhvEd)&7>FM{H767KrL z`EetHR%RC_w%nGK%F(*wf&@DxDyeP+Et&59wxebJz-qJ5Rq#u*-wptL%jUo_G?eOk zFSI!fXV1#J_VhB{-N65EWuRT+oJno-0*OTvZG&-#l>8`%m%9HJGSI#mkR*33UDv!)6tJV~@bl-xM?~wO(HR@4%mIIn9nu6O!bm2?Rgz7lxrW8O++7Y;N!;CS&JT5H&ft+r;he#H_8{Fo6g}px6*aMO3oX-j%$!I!m*@;n-LS^Lf&;JuxvjIN&k! zVqU2J{2&aN(Yc{pDuoUC@*mDT+q zM<$ithl_`NkmgIm_%EnrP>O(z)s6IQkl*eNy`RcjxV_7&^ehzZ_Gj{!k*Q#2uUFC)Rqlq6hM<#AU9Ec5f`?yP|X!heN(=X5=c_gj8 z5}9nS{BCt9J9Tr*k@2OQPuH;8xT4KLt7es1VXpK}LSrdAm>j@co~S@5(J|tN^scHs z*Nan>el|uM2OQGA8#NJfK*%`wU2Lr1X7X-Gi$h)p(12bKUyz$VxdqzfWA{t@dkO-WUKEF&C@WO-}-kDU?d;hh7dNT zEhS#R_zmJft(`}d5;j>s6iIkE`66*}d9RlEl1oEj_p_t1n-yj-dG`r5thP9g(Jgs4 zR+jfG!P*m3zc=Oh-17$TqPeIo8O5Z}25NfAo+SOxBm=O|6MZf+DxwsDdYXDTRtXjR z*%poK@kF>r9nc^tPUrI`ZX0TRrY#>RaSKNP^j!{+{OmTl4Ye`Z#Kn>5XSab1L z*6`inB-M`yJ)J!k{K(?kTZZI@HPG*gTmas`=mQ_eg;_VhXAo=fMtKt2#KqZUgI9h? z`=G);pGp)X7o=i9l`J)Pl`I(iqBZbWGaOt$iurMlS_c1(-Gxa_ONmp&!f?aAQtlHY zq7~@%gVw@6+tU5w$ecvDd3Sx#gs4XU6qH=bI0w&y2Btz8Y#B>JFEen1F6cKvH%4&v zLcH`k8;k^NVGRxL)up9<)=o#OPtx>squ`&2lP{+N_iD87Emyvhq$c@IbSdLc_|=>4 zpH#@YWYU>&ZRj`7A#NpkSyG9Zl2H7D;uN8u@)D6k84RQ5T!uIQ;r^erRKJ_vtNTc{ z+O15HtmxBq)D3`t|FjOUCg#_5B}FVB%~;DoHviD#=f456C;Vz;5^Nx?nHSD)FkS*z zr1ChEHEIJF$A(1xM)l{E1DEqM1dGN25}XVnx%g)+;9pKHj&${+(HREG-?Mev7N`K% zX|KiebvdwYjiOhchcf_XO{i!l4_XvB6;Cz=65zT+J z^1lL{UW*%{sUAFvQV-5Q(15?fY)W;p`YK3k-qtw>gK{{yV7goz7nJwq3mBaN=(QRe z#}@UP`9+FIVZI6|lPUr^M?iF*I%2&jrTR1k>KE{|RpBFihBXh=>CF0r#taxUAZ7dm z-$^$9bd)^oQO*!OB%fQtATz*Qk8o?4$3!HHzB)RWU?D<91&q*3(PM&zIMtL0f=Yai zK@fA6b^Y$uT(z^ac;0txd23`wOfWFNy)c*2G~9moSHb;{+I< zwje~`Ai@OMcnptDi7}1e9`$DCk0$;Je6_qk3N#ti0xYxtMJ8a4q9m+DQoh<*dT4%4 zw2pxsYb@@7&I}uV>0N3P3XFyT7T{(r_!OsrAZmTPJiuoM87E=3sy_ei$W<9#CT=@aH;q`lJl5o;{*}=0c{8bVB+!c zOu$AoWpFM?Ys%L7ITlRdZWYa3(1z3!vd{W+$G-RD5JFai~lhNw8*$ zgBAGrQFc-g*2ltGrLcEu+uVSF=iFnPQd9YEBzC8djP1;PA4x-k)CS$dVa)>XJ!}e!e0+p-1R2 z0NMVlKQ%mRm>8&s%TDY)vo~}+Ehsx%RG;(kO+WlL28jS5Splmjp)@?0EzXSx+|XHL z|6wXOr8T5~*3(!afTP8^Ylm;o8Nol)+1!G*K1W1+wVzPbqIzEWHscEU=botdBwUZ{ceizy^0KW}|Jn@>6re zfE)9r4a)b7L}pl@wp@eMPez16mK>#_KFp6CU@lUYe7S~+AK0;Hp@p@?cSRcN1gkuW zf7ZnDJz2 zx7u$vF#Cr);}6nb2e}tBmgcs+33A^b(g|&+I8xigQkMR3G$>h67qCj_c_iyqX@;(^ zF>V%@zgl0@Ie9FBr6rkeaN(9`+b{;R(cC5_MK~|W>GTV&kc!u(1fnNO7#NrTtKCnh zXX=?hK9b0Q=n4YQc5&0lK-87)ab8zIugW`1EouSYMj zODH;Z#j6$#VPG%B22=_+iUeUtSJUH zUhlcPouP=e)JaVl;4$iv^Q^paZSbvYkiFM9V6(qn_V;Jvc#QPHaZbIkTj`Z`9@nIy z{v^>@>g<^`JP@5HDZgvt9>H@C0dt7iLbm*HB@gy^iN2AnKZ3!~ASQ_3)T<#-4=P7g zglUm_rsSm5s&9bL)B^RN7{tcu$bxsmYP1~un11})WB&pnAOs{9(%@--}eIR6x$8HiSW6=V}c*QE2={(NE=Kc*%>gEwI`r8)#!rMwRl z$eC69_~WB=c>rR<0$yGGBJj^t_~nCyPG0+Zm1nbqqQ1uAL}0G8d93KE zFi69_T8a>QnBOvGd3Ie8J`HbdG2K!SijV3yuK&zRfY8Mfruy4^{$Y^4>xdwZ#`oDE zhjIJ;h3$6rtFyUXb_lc`Qx+ED^)YZ6PDF&^M|X#ZqazJ_uvBL6l3uTh*W7O7VssTt zap;y`xd8Zo%@~>h_k9>T{f$j0Re7q6*4rBVydj89X zrv$2xI31HyHs0X!*OE@t?M-CF9?Fo!(Atin=rc_WvP;i=hTdlFFZt6Vhdz<59@?rA z$+`UA%Y2-j)`;WKeuN^%qHx+<*X8vDD-o&FV>&DyWkdWqrScl1Q+dIJQYN7x^H@^D z@Z_}XR>H*ftS+9StdX@oeZE)Zm~#XOsbac1d82z;CE&9f_MfE=ujv1(s0cKt{nf@+OdJp2#rA7zH(tB{NY@+gMODA)VNpcR^2Z&+u||t)#JqFuO$Q^ zBWVE$JiB?@XDRE8^>=T+x`9ax16}Wp=H~GV^rMpuZ*1W5fdZoi(E@knV zHXqk^m&Ef+%Z-GDG^5s=+?|AfAtVKGxO?pCs2&U9c+wEg!Gng>UbZ9pVU>KP&GAb% z*Oe~6$vqfCojQXs)F>|(8Xg95G+EtDzqw*T9?iR-1bby^`z9NeyBWcgkG(9TubpCJ zG<#Q6JY8c+wr4)6*NwG!kf%6SZA)M$f~Wki2GpkwXr!U0Qkf*qV=0Zp4Ye_-&2iHu zVU^`N7byH$!e3NYAf}{3Zm;`n4eNin4DFxy?pk#@vRDdxKE~A}@<|%{P-tmA@CBA3 z$b|00b+#!CZO_fkeY)LcZ9kbBmSn!gI->n9UdU$v7U{!&TWQCx9?HHp+cmrQ$0zs? zIpCbcZ))Wxwa9r=S?ZnZ#Dfkb+ng4B`^Fn9=bU7B3mk5q`g1Xa66zE1h^*1UQr1np zzVd6cdUs`z=WPdWMU|lgtwe6dtKJYBGexX6Qd6!!StumgZO48fB0K~{Ixiqzz3dS& z-dvs#_Fsz)m?-!Xkyr`y;oH=XMm<>KYm{QjM51e3u*HbxQskZ@roRO+J_hg@b;(z< z(6xT$tRI77w(YxXHk`TbY?ixO`7Lx#gBZp8liG7>VU<0Y-0!!oFJUoj4O(@eI)W=`=RsBi+6a(F;|N z+{@jTlV~hf-6-w&5VTt8I@uZ@f=#R$Jmn!>ifB?I#6p7nQ5>$&Ba#&f@9bROErH9K zVEfkBSV-}*L23tIFpcRn`ekPK3VCMLf8D=}hkReN{?)5Z#Vls2>BsVf-3=^P9!>xo zak5|rbNy(;ey5-^^JXkZjq^feFEMG8>R?DkjGj;$a2_Zj0vozcP=S%4%_7~=4wEL&&Ram6H2tby2=D=ILLi zXcc_TS11s&bXYw4pyz?ExGn#-APa$tJELz}0cm!fuGRF9Vo_5J_CMupLxri`y!Vre3`PSR%uq+&8n}z5JNY5;?u4Dz>g-yb7uK0c-@UW~a||W+y^O5Xj6D%Lv zR2P0^)kqW(0&FoPcw0fx1qL4a=;5ZfHI*VHDdF}Ui_%hQ@aY*2MAeEdr7Kux#6Xi| zr7i>de!x?`XR*;@(OZ>CbPYZxgCu(DZcq7A+wswV% zrA@HM(z~r1ExeU7Rex=S$8p~?9e!dvJK50HDB`A8P)ESXGRF21Yat7Ok(B`ZbOC`a zYoX5D^_=*lN9BfW9!*c_4zLs{txkYe5r}s(B`BLljymEQ7Sb<@;M0a)b6XsU@Sz<% zWOT1a<}4P*ES%_C>D^S~U=Po}PrhAWAQ*gV{0^TB)FyxkDTWNq4-bmtBNvumJLl|z;98hA$V3SlUIF=43xU!ivSJN(sx; z!Gxv>C~pCx1VhloUZa9|EERHt0M{}k31BAQh%huQjw1*Qlo{3%YH6rNDwCKYTWltl z4AF8ys!FY*$Ws%?u7XGjOgS*^063JW;60OAQ77LnbH%qNTvs zu)uzi03T_sCq(Xvb0EyztVI|w=!g>_jSD!_BbdbQg;-&AYsU7H6Op7I+_p02B!%@3 zhHpWHfT_j@Vv6dGR$LoVKuYGQhd@zlR&!sl_YXvB?( zVQsS6Y`-ZD_3pVTkF_y-2;$dO&?HMu7SWO5$l}8q+aLbz91x3Hr5m4+WE?g74#ygs zj2(}s4)7I>&@6rA2ZE%S)&i~GsjE)wXWXS!yq$p-a|WbTrZO7Rnd(RElDDtj#DdEo zUVSdvf#cMB*fZCPqO1R{8d~SX)}A zmw4Mt0vdo{XpA$wmZ7B8nDi&a`0) zhx+~WApy^DCjIvmJy>2z4XSyK;5Z_L#u4*WHAaU497Mn_T;sNFB-UmtJr8hFvu*Ca zd#Yp~t1(b~CXyaw<;!^k9~@K8HqU*Nc|2IJ~G!J5W?CmL>P)8wd#h(M}4Q61|5E^I2gMRkosNYBW8T$ zoUd$Td<&N23%LA_PrAAfm4@w(XDjiYC{!AL=%7koG}eyt$D}^TIR+Z(-TJVQ9zJXk zl>lo+bcPB^6$lyV7Hv6>1e)%F=wI!3Q&@HnoOR1ZWl)%WLod*xh> zK{OoP7)tFiW$E3QO#1D-I3&MA&_7iG5QiS#o_kj-*8?unSpFhnh$Ukj=L+m>7Y%i8 zC5>8Yh`t|ys`S95(=aVMKt! z(g?O$&d&_HEE0l=Fw?{P0dlwSksC7)7$pfY1?p$S*TTR(qNtL0kkjou1C~=AaOrb_ z`3t@p~b)^Cj)K{xRojJkQ}K#SeWLd0};4$sV*d#1js1^ zBGMg}X=Ye48FnDNJar%S5@VVIIEX2wcawoA&fbzgb_&*e5DN1EAxmfFe3K4quU04c)bBv?LPCSrZTOyzYKyTg`u_6EJ;W(h$F>B^o~iax8|JQ6L#Q*4$bpOSD(vHGQ(OM?ny%{YXk{@C#?M%b%qz>J56O0 zh~7=JjwHiGPYPF-Oah>a79NHy_)FpA0l{V02()!HlYT&X7dDjIvhhrx)AnU{7+vdokK+b3@CeA zrm}j5K}D963Lkk(h#V1y(k@DjE^-X4?xMOmDgM%(07u;Ags#5*aoTroC7dV^ZdxM*YFs;9FW$6t#bj^ zSYQysn;cVNfz%)PGwJ8{|7FzA)0s5c@C$WLhhr~m=T0+GAh9BHSm53P;-DN+DjdSJ zf41?^%K^i~qod*t;-RM@PB=a2A-V6_$8NtJyXrc|_8zFmu8aGguFmgO-LzBFCb;}8 zPFFf8=b1V=Afl;fQV#w#6d*lXY(xDGCXLS#@=1cOS)Pmxj`;W%s7N|3y^s)kK?eI( z?zG~|T^HuBs7fd7h&+}Adx<6qxB}HjMv&h1Js!rzzlZ|gJ!h-5c?a@h`9rh4mzaIj z>MQ5RpkVlqv9;lkgC_ZPB2AB5<}9*noU2_MtE!c0eWQwBc}v{hAns^Zs~jLf&4?@G z9sE}Dty<}-O_zd}ojW6UDlXp=Y~A@Laue^)l#8QBW}S{ve9n6lQxllPq?KJ-TFN78 z--F`U-V&NNp3v79Zc!vh!6YyI3GdPx1q{b96AWpQ#KG#+M2;AF--*P{cx?iCUe|88 zyEMXj$Hr3PHy6#W7Pq&Ld_Z{D)tKq*`g0w|8nK`4Y5V&9JZgr!2lwE2jHXq03Mzq` z+UwlyIkvi$#f4(u8n`KFNFuGk@PGG#B6!4bSGQCi{HOmo1QqTAiZ*<7acOKNcfUc>JL z=d`B;;0HTB$7mD#%+2TTm#F%r+hcpl$%KW+mw3dAm~0y|ZI)YZH4YlhY&uC8%EZ|H zfn&!b0k9N*fBf4N#MzL$Z|$H12Inlss4*l(D_{W!f?mR=d;Ak?>|!49<<4L z-pw56>TY|ICaL?|qIvNQ-fT_ovUFBY%;+ps==C!MwM+l5TBB03w_zj~BTYwGjXt0@}e1ze#KZm?DoL!L7+M<#To2s}XW zdi#oidCzyu{SwnNcm$x&E8BsP;vzjmbgDvdPbT9SJGH~R2yQAhT502Ie2XX{!L+Y@ zy7!^T#|f{|ovB9MZJnNF0)MCzfGbkV(ad;3*L1L@$YRnn46XBdWVLXx*GW)+=NjKL z_(S64A_4apt2F+vi}Z0aJ}#L%K!ZXcR8iqzOgaIyaYV287XW#$E#^?7LITi4=5$&$Fbdvgp(25R??*ElU0qHb5{%= zU!KmSZ^&|#kXude{hhaIyovW<=S3sqx0Z6?2o545Q#AC;sC(#lU3~%IXo1-&t150HZ8SXbD#LbH+uc@b`SCDSj9hsDrY^t{9r?auK3{QQ-&5_o9 z;m{Gm$*|j;Y>uYU%fK=Svc#+!c7K1*NTP<2}=$~_( zAVy`L{8-=7XlnEFoA$2Xximj1iOR&nrI`(nfat?fk=T!-^NA-WnIMGM(c8SsxAr~d zMyW}7Vs}&s?H6(>in*M1zjHl%Bi_^Pd1c$S_vR0umPGuq4Nl@}J+IM_>(idy%YHz; zEgh@M#4Zb1zg3#8y?ys6?~#O+`|WZ2p}Eaxu@^Y$+_*Swgg4>!4RHkcmf_v+(aDc0 zF28*LMD&_uUZ=w4m!vk-x!h{`n+&~!Mnh3FJ+_gT@64>PPkWzO>$I7u`qYVOtHYX& zmRWuEJeve;J<^8=I$BbdB4zCs*UKuqN8)^kb95OZV6kAsWIdMYa&T(lOOo}D!3UD` z55s$YK*CJ;e09^!mM)Jc$MkEc4kc+UILx`_PmG=~?$wi>SX^%~Db*^58B|9R5m|Nl z-Xss|Dk&x}bhcGUD-_`A*^(gNecWPQ+S|4RGQ?gHNj z8Q1R81U<=xDO-+Fvmfz9>?c%#+pl`H^YGmbsEiXOa=v^8=oUJFa|-Rr$U0Y`6N`uGwMA1+n%EpL_*<4j`8AhbwLC)QeYnxVQ?6l+QC-(^*(t zvy1OI(>}4>@?DY6`j*vOXz|`NO}ixGI>E1Tiwb<7M~!v%-`UBqkxE#+8oBA3Uz5>N zhQ2I4;=GyqF=r#(FtJ?Q-NSxiysS_oC#JuSu@_|rcBOaQdTn$R)bL@|v-oyjg+(p4}aH{ET48^xIe3iShQo|hKyn^oc;m3$zu8?bFrk-QpOte*17Ccu*} zhurF+-m>?EctOPrqs_|)xi9=a?&_3AUz|L@W-Xe4^4?5=?MQ%Kj~nT-nu-&*NKSyt zVNKvJgYLG6K7J61XNxCV-hStYPu%s2$*sT5L5MzYJE1qN{5}fNjnv(RRyNIsSalsk z$C^HOdh6!#vLkhrJN>v^v=L)m*(K3RR1l4N?!4+_X$rd%fj9nCepD`mC+q1;IgJG148CcEvCBR(kZTBsn`tzLs7TU#BzqN*JX2b;m|5o~RwZDgSj1A$1z+4Ti9>3p$Su5LdQ~t@S)68UCyQ54) z%#0yfD($x~F03WoZkePmi)u#%J@<9duMPIIDuiS;W>r+muMcpv=u&sds5T7X8GSP( z@X2rL<=2Rt(K;b%P`XV=pOMnhPi{<=e;DPnJ=1q5PpRp{%cNU5s($0XlI9cYrHLcC z8*0gTM=#+~aKA^!l58dZjBk4{K4#=f=a7nZO3g^0wKKYT95R(HCYTismh}9D5_e15 zwu{d_Gm^cm&&w;L#eh01=b~wbTELmUn`gz`2bRqA6w)|Io+v1Ehq?9n5@e=~hHIh+ zJR{bw&sL^fbjPR^c^sbsOU=J4sa13I5g?cc}y(w?8b%iSLTBs++l?mlYsV+_+eh|8sI zDvhk#DY4tu^!~BlAkgOU!-V>&?+b_oo65ew890?!QZbH<|f{}QSUiqQj zLq^oWj7O1*L7g{A$4qimc9?`i!@3B26lw1s6R7Dy0ew-#_6m`B!>tnYg-iD}$qiSN z{9+!ovq@}CS-0$0GOqM&ac|rKUt>gr6Hq=vB-(YmCw{!R=e6^~qW6z$^O$kkUcei0 z4}DyDd+2+TlYxbfZ?B^-Zcm`;;Ip-Ojz8#WkV!bP zWnERBFc_f_tkoChnbqgX855FSJX#D1uMANS25&E$EDSo?Z9clZyJ!&aqTx_W+wX~L zbueJJ86tj1Y;JevLVm5BAWsQ*mBnaJOGJk5+M0=7gJrJMy&loJC2utT8MB|R>T|TDd%3Q%-2Uccp{wik)bC-N%`0e^zAAe4y~}=En^R)DM~TZMJ+*0S zeBWeZU1+kaL!HMC*vDl#Or6H0+gH0?51L96`*tS73BBd5$@SU>zY0_>2O5 z4so#koL5!RcYkkcl~dkD*@v%j2T(1f-67(g{(e1MJLxCp-%eIVCc)l*=%ZK1JuU|a zncK-|L~Z7k8$-YrV&#$nU~NYPuHDsjoM}nzXx=DH(X90u{5nevt`+CI7qzu~fz2&w z9+X;JS2XF>C;x-BZ`pt75kl$Y>PS;~gCE_|75M&>sEP5BzM!$qWU$`{l{G0vFYSEs zr)_BoODf%6J z_Xf^(M$mL^RF;J_9Sp83>@PSS(>)}gBupxjHI?NXj1%0lWjU*;!o03lUV|>U_)$?j z<<%y|YbdBvQkSDqF-V%bw-D~cxh0UN_dfR7ricp3^quP6{h>HNtN3C^iLgy;mQ`N~ z>fHnDoa4qkX9;2Op_k#IjMK)XbED+5rIS{$(K=-U{%eo$)Ki@?ZMZjxMfChufghXMuW~zV4Dv|pcVx&PYycEuhZ#fsNrs1 z!I$wH{q}95_I8uL=!X12ch_YG24Me`)Dq!*^ZDa1{Gy&02%WRDmjoFOAQjcsP`51k zpiwi3SIbkzP_LqpX%4lvGYh4GjM>Z0WydcJKjuIg-!Nx02IX2_@KS`eoi`F3?Cz!p zHWpDsQI(>jZw-%vBo^XSZcE&L#Mu!9>!8b;+{X?4S+XpL(a$z$d3le!%=eR{ z3ESP`{mRk>SQl4FuKbH0MVGkc7rUfNhb}@q%b(}u>6beB1@10a+|oJxennh-eg&nNq)W$@`VC^$#Fee>BxWcnu0f#r!icRvT2rjkRj$-7Cii9mn z;zPm&+##W~~hH;UsMJt>1qr4M8rmrG`+ z)(f(VZ*18ciBiic6f&f$zPFE>AhmtHI3Qaq4h=H%Y%th;n++D#?mC=Qo88?yoH@g5 z<%K^wlNp#|Y1P?Jci2Xwd&M^pc{M{-#7MFiJ?Wmb*hYWmzDX+so>bL-Jd&xh1J z+(x5ggHci)N!x3}Kg5Rp9$W-_-m))#L(_C{bbV>lfqT1HYqbTwhfWJ^pTAxeG z@PvUfjlgG?^46r|T_eV0@dLQv`K?n^kTCV5CD%4+rp-HT?P%?TGh(lrCbFq`W!7W+ zbLsxh%rKp;@h*N?jwn0Gi28DN_Rju^#W?T9^-cA?g!|5pGX;A{Nr>()5AL>Pl2^zk z?;BSArxO)9$7;T}J~iqu(T6C!H$M0V#68CsPX?hi&l*0)3WFWqewO&-#d)S|%*{4( zW(brfo43Upxv$q4rtAjm;}3Y#$C}he4%AhV;m>Vvbq<|b!ts)>9`~y! zBoB7@8hQ{1lzlk$b5)m%M9ZwmOdJHFt;3lP%h;kf*2+?C|AdQ;)8SStCu0j~KI+}g z{a#166r^`8*yby0p3-xo$pcKN0Eeow7za^Y-}-lioSAl%jr!=vJ=%d=@^!zWp1_e8 z_6Is+2;``8QDHRKj`hzv?Myi8B6(v5%hJur~zgEkZau zoS&*4pn{>#d*nCeQCkrJR~s(U-dIaL4dTVr3cH$i!!M21y5ZHWv4Bm6l|=BaYXeAKdB@ZUQkK z+b8Q;qx=520=~)rJv*Z1cSZ&a%N^J#*rL#Cw8PcGi{<5*p(4Bwv#JuItt7hx=9 zYj^+W^IyEQLj5lJn{m3sA5^1C_jH{)xq#}9q$WUq^vs-|9Xy>P^9WDTpK~hgAcLDO z#sCvJ=dK^+gT8lN`=A7uqRXzTSfNRFejvdiG0`A1!@L%bR}xQ~NaFwE`?rS&(8%zf zLeF~O?XTLi&b*yUggbC8KO5wb8T@XnPXBtl^zN?}o_hoVwTL!V zX0SBEZQlJQfG1nqMCiAOFhO5FSotXqKp{y=fZFL<=K^EZy}g0vPr}r{?%~O>-KnXs z)o559=&8G5WH?7Blta+4GXK-3wt&y@--MzY+;?KR&_QCN*(tph)>(?{r3{Uq|7-*S zP$E8$czf9%VQPQphC%m{mqv_-3pR0^>kFTk{!ONtjBC^f4uvtpO`nH6RPPp3#S%9* zpPrV<-Z{i02tCNpY%pOL*EF=}i4K~WbaRm$zwqAp-=OFg@fI)Hc)iz6D0k&`>D@H{ zvY?pM`I}>_=xlY;cVZ?cc7qN(Mx5gMhI;m^+;meML-z70_TW!qkhi3(v$7M7K0*;oXIPXOL7Wk?!FLzSf-|Fr8ZRxGWW(PW~f?E zoPJc^A|~8b3)8lDBle!G*gu~(fS+tmLUuPCkPM&4Y*Y2$U^MZd!PZ9spK?AlHm&br z6?dNI)}!u6{#g6<&ED7UIHShJv#eZ2bQjXVvEM1*@#6LC{$Rk5G?Idk{hj8kCCg-d z(Q$ihS&YPM1ko@!UC=u=61`%Sd=qpfy>V%2bpJ>5z?7ngYc4}YXI_2^(s9XHkZN%D zTF&K$bp@{Eh`mhjy82RqhGD02;P&!i7^43t(57}Z;80{zjE{^;M%>=>MIdwCvnQu{1L#;<;$$W%n!n+AkXC!?O+kUc2R%*m%e%-PRZTSwiyu6^3)+Q;! z<39b;?{umgmH}mzeS;?1E23>xUZ#%LTygqOgoiLSHk8)4?%c&IX^mIrBjj_7lh5k0 z993)olDTeW~u(H@OJ?o99iSq5EnV+}FC`2F`4)7XXmLczi z-yxUNfs&BjP`lE}@9DkYIfAd>H9uU^(tNXQ^5u<^Z=iqhRG#oo8s*>jA5g=kj%QQX zCuX+fEV@(A^_sE&3YDDM<4Z22<7^<3uQxxQVzK_oTCJ^Yoc?py@X12$?#d7oo(wO_ z?>!i;TrEekmz(Bw<`2d7%@(0vh^=M|Xbf9>jLAp|flp+7Ryu&}6;eYv6DYv0Me<$Q7OF{nl zFDrqA5V?9CEtC*u%!CdNZsky82|kS&C&-yc5@zW5@5%Z1Pr%yRmd0t36(ng_mD{C+ z4&y#?jqsNPe4a+aXZ8iv?_`U=H)CxekkF_5z$*I8-aLKhCoUjQ_w+@skN)!_wLe4F zh%Jgaan@>z`U~Y$=id67a2yrRN-(V%0aT_g%BQ|K|D#S0P@mG>%5AyM@3Y2D{2Y+f z#9Leed=m~Nn9k5l^@!S);uOnI-UKq2QUhA^aAuOu{&tn7!xb*SI{I&z_J1kwE2T||IX$>EF_Thegf#dDexom3cs4e0hhKUIJs z$J{80CQ-MzdHxpxMPy$n%>gu2qGnqF&Ok=lAIR=X($C<0v^U8>ISPabqVewg0n(9#76Ev3wpHRs~#5rrm*~VeKfuU8M(P< zJHDF}P-*@3O61DfaV88#t^AV$3RvTRs10LyKSH#SrI#3f*%- z5v_#N95};Xp$5`;=S0znv9hWI>ZdrvxPbSQ$xM2P3*7-Ad_ztbl2afdkU$1l=08m|a$Pps;K1i1(W!Q`UauH_} ziW_|>A_q*Rg}EuNBAlc30$w^8RerCqpywXDVQ9KHs1)azzYy?}7zz2N3I;i^Bun_P z#r^Y6z^e#HwNS-wevei@bxvGnhK2&K6lms)=HANuO=uRNK5iE4)##3#W6 zN{zKZeTObi=F@cg;eIL4kj5Wz1XJ%b!?LyD!UeAUA`KN)I=h_N0nc&%bX;-L7IDv# zn((iZXz%#!;miI0>)-@j~Uay2$~aok9wy_F&l;nysxWN#5Pv zeQ@M1-=2c=d@vu>tv?s|z`DE)c13!jldyMUGO3-r@csW!T9n}IWZ1a9SmYb85RC}< zDJAvq^Z&2K2r$1cGQKJ&Te)4yR4YlATVZ(rL-V^w3YAaMI7K;)ZwZm9Fw&G!$g)(H z6~Q(Lz;;cSX^8l>9c8yC;?{d#2++N**I+xaRM4YY(;<&Pf>$;^(LR4h z|Jq|pZr+1s`e(^Y=MXlWQ;F15DPXu)kOUn~ocxkts>+RLZ7b|Rrpqat$!9n2Wn=xh z^#B&d6MhaEwK?PGLdrX#xIc5(2S=-VFe!l_!Zhj!mGzXGo}5o4F#?0pN~>Ovmj1I3 zV84k`rE!64%aw^-Xw99axB9qKtIclw83e5s+}hg8A9+GeIW=FkBhHFFUsV7k8;||Q zMJ` z-~N~!w06Ag^&eQ&Dc2t>Xk@mazzxUq%w2vK9&tHP*P0^>9*MdN=1wQ<-$w z1h=*DOwI7Qf z+ts}jlMpr&!UbrN-oOiJ1+J>9$JLra4_%$H+aHEypeO;HTlK;}d=2b|X|Kboj()N< zv@X0C@&Cb!3RxTfV5J%|tn~l#clc8c+VF~y4`Owar{t@{mH%Tl08@(L+2EW>*WCVx z7kpFz_w4^4SX5AX9}wjJDZTk$))qjgs&#PVoEw-GhRnHd@cCkvDBn29K#l&hECB%k z0&@4M*W}^&=P{G!9X`wDaYfv+E2cX}Kpm0O2^)yALTVG!vdIF5jRDz#G1!ccj1le6ZFXb2T*aBYaz-{6~ zcEyVL&4xIwRV$Pd8$`XmpLx5I|CcBy1Aqn)(Ih#b_!Q<*y1v?c6Vh=80jaEHfJ!qe z5ig1(?V#G~zX4I*V>Ep^D$d9IANC|6T?|E!TIa>QaG5cG1EH3DYq-X^7CpONqGd@_ z7zIYM=pFmZu1N1*WBk`;_xF2hU;mAQ>IP6y1)--Xs1JMDx*fTCa3=BpD!9{D;a2?B*Lj;6zno zD4gi;S436u{x)bLW9r`d&)X;l0{A{Yz^;zH7$(j$b8Sh4-hmWO@Z~=P$;StbTbsRl zV^b>iofg5ydJO=i_H~Se1$ZpMH}Ui02e86C&183LLFllHSH(DIOs>33yiEpQEjPc0 z^ZvwBzL1ahqp^!ThJ4m5*WM+vlfg?a;nobUa-7b}ue1949~jKy%{oCdr<6yeo#eQH zh1zt$Vszr0@by}KNg@kWKwX3ww{ccUnpyL|W-?N{^E-F{?`vVr?+mf2PPpCv7jmR( ztZ$q?v(Tw)N%$G#-2HcLo0rGbsw+gKD{Y!^;0uj4gyL&7QzW9x<3JkIGX!$xh(MaOe&S^n zj=(uHpUPcjaf?&NQcZT9okzs~ zizJ`NE7@X3eV)7*0pA`Ien?uc`tqzl^i=wsS-SxcVBMy&0^Gb5tw|H^G!V zMdW54?!ISQ)4&Uj$OAbPihh~dd07r;I#lC~!`-^F0rI-=)KRLywdi?0+#2F(poo2~ zMW%qvuhWkZ-PL1hd~OPVbv}6G0JmXqFG0>O#V{SxNerCvo1bcVp11yoMB*!Lt`U+U ztyg+6k1L1(HNa2C(f!{#gulH^$9Q#2fRAU@U&t2MltmD41p;_!Q~E@D9A&n);Q=Q| z3ft5e;V3=`k|KZ8jAIL!$N+VGzxw(pgxkHZ8kL`iVldtD!E@Fn8&3!~_unP8#X*5T zcn(;Mn0ti=WaAFy2G|;jNFcp<>$6YxNbywO{Wdzz^YYW!4XX7fU7@=}_34H#{u1v0~h7ntjs|2c`nV-bBQnNPEJT!yAbx&JX(no+T^Pz49jI z)Us|KC?b;bCC&{2FpnI_;5IXaXiKP&=p~$4H2}rvju>Fi+!iK8`{m;75uaW__p*epT;*FTMMXSD+>dPn8k0~#C*beX{D-J9Fq?t$>!PJ35=#i#SFp@6v~eNpqVNX ztD+-4zf6sgfR@f$fTuq)YEUZ?&51J>(3`{umR4U^X?%eW5)2it?dv##dW94SLm&aJ zmTR$(fEn+9t%iF6a)=e6%=)0!()}qNj*@TzC~EnKYxKv=T^tqZLID5u%DE+P*-BRh zQic-E_9@(#lULgEaRB~7+U)dY_kloqEZ2uEs59l4(9WgNn=aP~LJTZ}X ziHV6vP$+bNep70qEVXpmS*So_SEc@Bvn!s@)bH>hNBP8eDhO~UZEycfZ!Re*E0g=_ z2kG0@hgxY@PQ-+z3(fyHj9 z_wN&QIW4Og$PU>9;_07leLnmHG$pwmU{c5SqrR_Y;s1z^-cv!8Su}7{In%A= zU$yOfn>sfu;JjjM^}Ho;ZDD5or{C^+QgZQm$MG5%uY_RHCamlpEzLxExxe#?Dl*qt7oG{soud2v>WS;-F4lK1Yl~@baFa;dSX+PhI}p$RNa+w= zHdgnu7tDsPk_}u#_?#4-gCYV7+we9b%)0g9#NfGBvpOx(85JuH8D03`WjkUvt*I23 z>~vV(}h?s5>0eQbAVtCUlT(BqtBS&Thw59!05}-&S3`3G_w|IXW(}Y*?z0 z6YObq7f`nowsFvQ%fIJZVq558Ti#))t_zf*&gNw;HXHZ5^Xw1Yw&(x0MGh6+9KRtwq%p z_%mC6bj&F4rfyk>?o%Y@G!2wZtp6B6f%6DDbIQH@wS%=G!xfNFgTbH1#0BHqLxCk$ zYe`kx^GSwm_HNyRB^vOmEtgS? z;6%ZP5e#l(6k%&T!L!n;Une>uIr_NAJY+7Y%x zd`VWx@R|0uwyb4)3nvrxSHn~mAqO&AiVv2eC%a$hC6W3O2KL1R5 zp4xoedv^MhpO)r3oqkQqTQ$ZTR(|OsYAMnWUbHAytzPYwN&GRgb}98bj3S2;?TaGc z4r>Y-r2+G?HI^sAA0J zzcgS(^MheH)6lwgu8mPbU|zL-Wx3zLu3R`igvPr$a1G9oT8jGGQ7rcpmUu3D+em*( zr-*srF{^2()vw;59P8BNxXwTR9pPJyXFriqPcprb=X4L^QP~zWaTSqM+!FMLyV~H- zZ8sl82uwFFJkd>mvi!>p>KgbP_{lHC_(&XN$;)JB z-#*w(^5&D&B;50ej4;f1l8A-JV?0pdQ@^T8VhQQ73xv|1S5*04p79$zh`rQVt_py! zlaND}Z)@f9hHQf*Qob<0p-`1?BYCXIf3K_ftMCgg>+R7T^2M+whR~-YEABrDm9UL0 zY(E5s!VpR_;zzcF`@ADOX-DzQ9-pDxPbG_@3M9O~rc}pV4%YFfS}#0V(xq{!?=N}n ztC12Ncf8HTGv(}+B@|sTxr!+cHt%X~@UO68CL9z-Y?iqs1OgxnCZpt%&d4*L^-kPr zt^xocbWkSt5}nf*c@kMDOn#l4GVb>DbeVNQL7wMA`+gdyY!-yNeRe6&1MwYuS$2Kb zsuwBdqF&8YIQ0`FPgEqjbX<%)=)D{~P66{hiL*aBSk2C~gl!Mo<&BGr#Yt_{%wPOIMrZnDOQSKl;6qU;MAlL~18!(bbj9bH!-b>$HOZA*zIp)5#zu0>( zD=p({`KvmrJz=3j&PXE&BTa;qH&5JFWNi|Uk-%h4S>ws!=21=E$f|&9eh~@AlrB$R9Z8js=cHK_lPzwi~4ow;l) zKCmvH2voi#HSz2i9F|=`#`_s~gSRpyBmrNb%F_A3zVA_;c zgIwoYeI(pc+LRNFp11uz<7n`$4?&R}uM`ai*|dG6dQ?a2@?>+6qiO#~if8OCS4=6- z^zv{HyP7|zGItczxu#w=KX*C1lHNI_!31B2OMnCaWV6|1S@%k=Re7z=MocT@o_%PY zZD31Xr0vD+&EAnWm(!b-Ra0rSFZGi;OR|Tx z#Ffz#7kh^h{$ZjWreY^N&ix1M$}u^Moe2iM{Df!yK>pz4P(8~vdDpu4}0E1|jXg8N5ZmwC<_AOSX@j8^uJ zK3%`;&w1T>lf$7YWXci{ZL zz($1BGQ8O=+SRzvooK*11wefkO~?w=NKKpt0ORY|!<~hjrq0OoaJ<@@2MaV3_fBSY zLtYVu%0Ac@U(ythGq}rRJw2LWU)RHWH9u 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%0A~#>`X3ORV#}g4XbQ_qEz- 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�N2hZI*${X}$VTHqN5G3O{qyLjxUwwVIFL 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

  • ~STUPV8Z$ECg`qD@e>Wk~k$VwfhDuLNMWA018Hs1@&$AM7FN%3%}cE6LC;_==&>_NTpV0wB~@fZ8Zd2bZLz)Cy(B*6hgLz) zs@^8SSF4VRE>%x-^-q6+zk2Cl3!hWp;f}a-{_{O*(9C7QtVNFTM;~){!XbTN;Y6_M z?fBj29-fY;Z1xsPa+azcEqv^JJ{upMB$>T?_k%>t2OAsv;*3|U11uuK$H&dBR~#4^ zSX;ZdM`ZY|sfqiD)dP(gHwNro9bSVtq@$0>b^1%3>ou|w94r~({P2@d%_q$)z;Kzg zm-f{0O99pgY1}Xd6$sRn0~I|fX*c{;G1@e*Tvpv4!(Rpnl6fz06apWLW)+9CD;CjD zldaYRaZnPp53I+|bD5}}2L+4eJ(D@$tS1d_(}#K%B>jH?Yv-ak&e22X?yZX z_PeN~qxWVJN6Ut~lFFQ%DD^18pZdt3x@FeyVl(EM75jCgQ3kVWv3FGVT@XP&IL`Ox zemDJT@2aEzu4&P+w(+Ft4D*9V%51|-=g-3o*FV319v((a9MTLYqA}9q?0-o?lW&fS z-ndy=SAXF)te8zbK!goA})2;^dR2Yo3Gy7ZGJbW+NI!YtLTNF!SrBO_c*C<-z*0LRr3pz z94DxWi>w*j{>rnHvnyP@uBSVj*-kM`T-iWkL<~xFu;<9iaGps}iysO#czmbZdh(}y zT=nCgLtr^&*(U1dsSJ*tG&+KsbOE-^W_u6-0D3^eZw^;i~VZ_`~!4K4Z zSwF*5Z9_RF20eOKvcCWOR5qEmYN(?vE>{CLdOoY;M+%@}Lgl~#S1z+!AsGbHq44WT z(iD(*N?hMmag5^a#X@S};*c+HDUozlWg!H808^uzp;VSLzp=AeorSmcr4s9|HZ89a zR+@%0E4ioBi&Xs#^0fE>*NCH=Em{fw>fJ62!)?$ycm~!<+N!AOtbLd}VsKh1kj`no zatG_K$Zl#eK9dl>tPogPr;+>gH!;pXXq0MeS`6VElEU<&po&BWB$czX@7AYFTMB`k zHHwpe_ilLVp}(5-6PYpRe`^7334mDp;ggO&euLRY=WinATp=@dfQ0+|`pFXGbK=v} z>OjMapx31TDAG}3PwTGEZR)^=bSVzka&RnvrzkSN0M97nGeecr{MtkF9jT8kk(WOd zO!SH{QlB0U6?&cQ~!MeiNYP`Vo-S7C()d<_Xl zEjCkC?J+@`QD6DjK{Q8FYyozph5ah=&{F%OL_RMYm6mh1ZhiSgHyDE{YLXzerv{$D zB+g_xP$I-v3uZt|T>nx;stsWYj(MJ8ZouzJq2`Awfo0%u-{8nFv{miSKmLKjusPsR29(v;&Cu4%7 zOcAw$48=)mLxS|?@Cp(5@}fL}x}}4bH|A>UGExaLq5Pe%h@c)+;Kz}v!{ns8zi;t% z=O@UwY^VEUgM!ULQeVzu0jbNYz&;4$-n)K!67erg1Aih+q}hqKP)b6nf^p2LlOmW1 zSwn|x1&^B`Bz!?1%oK;ix!BPs-{NF9{a4^&sHq%Yip|D-*`o@x|+mMDDYVdhvjHO6FJ?uvELxu1%PMlD>DTu!;pR}WL*$k zM@Slby<7Z~`cfb3K{F>0o*DrLE`K{#6!ld5c}PgGc=JxsQ2DDI#w-O1aC{7M=$kq? zCDaN`JFun|#R5u4i<>lH*DCo4Ur7BLv#;SYJJm4S6Ogp7%uYT})BzG|9LU`+zt?yF z+T@pJPnO5mYS7bV=8<{9R zn!)nO=2+77SWM*rp@QmwcD(}vvs)`F`PX!XAWlLfg*Rn%vX`niyF+M!X(*N~eb~0< z_g_@QX#GXn;j0fdI0ktZa^pF=Xp&_#{Zvd=VMW-%w9>r$(MLv*s1a0w1y1plb+!9c z6@R&QV{n|3us}7ndspTO?kQIn_%}RbNSKI7WgCZC>S_F*>=SD@AV-pZ5Di(944g2X z3yXzXsUOEun!)E}+ENS18zmswwbWWb`}fLc=v0U5Te(*`zZz!3na}>O)vt``kMyfU z6%CqcUS@@EIZgBqP)*$Lj1Q^Yo9DNM_~*yVpEdc8G(~?J37u$z-c#G)nLvP?K9n7nX{B zMuoi*sHqNvZfanq(@OHI^iLYm_v}jAFm)*`;4&nFU3Qd)CmIHo?OQ=4-SB90IviPw z;w5^=IRl3H@piD?9yc=zCT*NB}K3VyZzE1 zn4X)_HC`87C$)%{RfF5omi=|#A{g&6j%Ii3UB+b^Ec!l6ZM0{}Et31cdg2vm!9yMt z{y;(ccqddcHd7ZG_I4q+h$PiUQf5)ms;tHMQ*j&HqM(}H-aRGX%lnD&&%PdiV#$Y( z%mF;w>!hQuv^I{*$JGJ9@L3J2yPenEQ&)BHW4SL>wM1+#b;^sW_7BecdPkhmj`nX< zAYS0qbTq27HF`Ltn@>Ihse}bEG6dIoN%O@-Z3m9OX*}V_Jw9-<1{elXU#;W8G09hE zm$R+tsi4I)pnhIIGOEW~5<>&k^qk^<#4@a;WHRSr3Mh%kx_Fxjb9{%dNWVM&o9j-e zFEZmrQ0$>;)Q_A1YQxb>EGLPvJKsz+SUij(q{kNnd`2&i2B%Zh6vYSwrQun?InDwS zO&q^y3JKTZDHRS8CVL5@cZS$tCaRv7g30c#*N1yZk32f1I{E}$KMU~*hRw3L)m3_) z-MT=WA~$O{-gssW#7(y7oOn2~6qdycb1F2L)RPr=;>SzN7k;x+p-r-Bo%71}F-i5T zK(1lZnbVYN60kl5F%Es1BXxqLRX+m`{RflFz7p9=b3z`*uw|ci{+TPb*8T0Db5;GF z`bH~e6k?1oLU#gBZ|ti+?o#BxC>-phcgSObxJ$KC_PTC&m@5 zVX5$ZD?)xLR9|4@0IZi5=SHUwp8IHFuRSQft&%j^Ab7@S5bubJqMhuuQO`PVpRDXB z$gJ;uUFUNz`oLA3aoYO5RB}E&0Sg{|eT0A`77>JH3ehKdllM1v83ujCTQe$JxM$dl zaj5T%Nf9e`@l#$lAwbRBd(XpLadF4f7Ec9)#H_N^0C1sMaT=+dPlqh*reJ59Ku+nO zQw#)%yoZyNiv`dvle*}^W5y&LZmH6dgYaMFdkht4r#;(zpKS84tQqqyY{ZRYj_=>Q z$ZHI;bRpHBZoXQJ$3!6FpqZB1at^2IqDS$6C`lnrsSSE-R)hXR3;!$KVx#L4?4zxz z{Y*sn7B<1g&BY7TpP>=jUS!z)@Zd0^Glk^zC$7xy3UwEF|w2G&VT}WrU4NQ!hApq zuB&hnQU9_!doi-*{|p2utTvr#D*U|q9@TKZP~VA(U7ru#nWw&1!OR-_$j$6*7QUi% z-Jbn!sTKL{5Y!J1wniF^!wHIJoOoMlyH-Q10x@OzgV)!o!9tHaF|NwO706M8W8KXn z)r&*Gmk;=O4+U~*G9?u)aDsLh8b!}~$Z?P3h(G7*`L2>_SC0^}p>8j;#&vE+b;DL9?^>;0pDE*KC#the;3CJ5+cQM|+jwpv7IXoFJn!AK> z9fj929E08hQ8C?A4NhB!*9Bb)=a*Z@RLfxk!Hy1DySZKb|EPafv|j7V7CKSpfi~O| zN%RL;^vTx22`L>1q0*LA+$Vuy_>e3K{kqr4Eu^L@#`S#;13bdK@`wH zaPCfy2$_G4mF$S?&h4bnYU%9Pt`?GeD5v-B6dE`x=omTqM-{Bv!?KYVXo>&ZA@#oz4YaGr;NDzLF5~ zv*)18@rAG{I%mZbS>1&9Q663RlRHe2uPqGX^i)yxDjW=yf$ z#yl>;F>Jmf5WRx725#oqK&TTUZZ?9z_31{6Vuw$q=Qc6BJE{l7z~&8}-c}}CLPLotxw}c4)v`iImE7k$T(Rm6UNG1^G15cHEB#HQuue`*>B z0I&KVhjd2U-Ft7^!Vww{SF(>K=0Dm*bW|WB>7oZIN;_2Eob#0C$vpU- zWU-DsWVT&c7`%EmW=Ly@ks+i@PCh;XQEQ~@VSGe0bgE(4^r0^D&GKsryAgTDhBp`; z2J)-Mq~1(`a!yl~AqnTKyLpM{ovpy>?CrklzHS}IFrf(K9J^LRPx{2Bf|tTpD&to! z>RYo6zT|gLw_e9v!K3o`ro`?(i|+i!cgv&H$g{AFuDzXMe&fQYF`j?(sNDaO2f5aF zLLOfoxi$mEgtJD5((Ez&mxS0!0k`Jnrhx^(SW3#AKHk!i4g0vn?H)iaj@~nmTFGsO zLqA|8ZCs#@)rFxr0zv{NN4OBsSmv9ei#cP)g@__hIup}zrN;X_qq$szC@dR-k9uE< zy+yEMol>WmPq7l@KEoV8|1mp%lcbj6NXO#}r-6uZu@=5fX^VRgJJerNaMh&?l?>L#oR)sQA>k^4)`is0 zSjH{K>4@b*P^zwu7t3ko@;rB4WE1292X`}WmCBhhanNvT=M+V{8&6y#!`^$8-4pDf zJyEfWhdCQi5{KsE#TXd3Dlq&>Q7pn?A;3c(i7+{YV);S}DaAfdb}QiE6!KUc!amA^ zE=|3!&L@MyiLyRTwq8B-kiD?8cc|apRM5u`AEw+I5vx@7U;U4e4j@ka=hNusy$su9 zXgQoZ{<4lO1ryGg3^giM(%kLhDFZ(_eD6;qagoA2Tgh-(QghdO$9_lr&Jprs<~8fbhjPUqD!L+-wC9`s zScQY}#gRKtAt?0S&aMIXcs^{nsT=T^5Akpd&^R<6K%^qZh$s?&5GTKgCaL}Uq^Ma6 zNAk}VT@*gW7!0;~#%KPc*{(H=p7f15$crnImmWF#GwYB+-$Ysq-{OWdfUeO5B${=u zsV;WdQ*E_Ey+f_!)@=~3pkxw*yK7mBA6G6pt+gCl5W3J0QN;QfmXhiC6ISG5XW_U)3+u% zcaLFcq%F&*oleuz(c*quUjGT(CoXLz&X8Hp(qw(@aL(sBNW%L8XP!#LK0v+igHIM% z?wId4lH15$2JLBkOv6e(GD+EP><_P%&Yc6DVyzFhaqQ~N-16`r$iw1fjxPw_Uu@U~ zNKmVw>Z#V<(1rHG3tTXG#DQJHUNqJ#lZV3~h|&0xj)`Wr+TADV?#iS?U;VUX>Eg+k`)$!t8jtKrn?OhrMow^aM`zAaf+x2v|AyBiW$bId~j& zzctxotzvogn1uIq#n z;kvNZTrayW-d}X9fMka%T`R`?4aT5QW-kZtXI2U+HZ$n=^vWR&zSq7r5U3OP$oO|l z*ZMWJe0Y8!H>htAfj?jM;md(MSVQONiahcK8^y>HMnel;Dd1?S2p6A@-4 zX5foF1cyJ(-I`zUa|dT|C240<`#8FvA2gwf4vDD(alw{v&Hv}$PZyHr+R63R8BbWM z<)XahO^`~)d*g@Iy<&Y!Ahu8AHS&mnLD<f+r#p1&Xim$2frms?`_vW$bkeIUj z{Fx&Pv|uxDq;uY86b$#aP?sPYVc64Z=9vtlCWJCT5|DyL3!?j|6JgTySv)|`&sRU~ z6U+VIJU++xLVKF~t39j|=I^gGnFQ(AM+E(QjddWm2wJiRWyV|fr)up%6l44RKjE^` zEE#FIUx#eNXg0(_92hB>nV9f#aEVD&8TJUTWJd7yPhy~ORHST|etwkV6%ykU*1uyk zga#L0oEQV$Rgbe(e#KuoKn&dfB4uuNG3n+Vm%eG#EpJ#LKDCj1xAjTT@ZJGY>N(qE zX(T#5*xLJ^^)WdR1bMhz1EYQimVNn27Ye|CZ)8A04c0~prjRseb~&LakF?$D&f|14H3=IY@_KEGFI z?SA(-*2Iv}F>?h721n~>hXfWk^el%zH-8K)zAJ7%y_(#=Snl%lsd_!*FpdpLVa@M( z&i0?P(X@PK74e|~5r;fLoYCnIm}R8!Db|dmP{wp#jb~m+g53Iv$KnwvQHPg^`)P)D z=~sTEN3pW>P~z@anfLSr3mLqhpzOuPws5_*wR_1?hGcmeOyv0+*H zb0@Wk)>~1kHw2H>PMjcP9G==TCB?5AcQ9>kY;uI{i@nL@rK|5d_4lwk~*D@ot(0^sNI?_$q`c515nZ0dp6b|L#! z%2r@+FfI)NWew4VeoLCLLlGrZlZ5GapYY@#GECl=_r6}O{iQ*L<{e{y7aSm;pPV?3 zIXki+jtroZ8QtJudiF)GC)J{RbD(-hs$@g1ZH< zY>or?EPzP*w+6)pc25Aa9`Pp6aJtveMh?8~`*O}!Um*>U6HY;_>b7o7A~V0%N4D-? zgx+!Q`hTGNN5UH4$SDPoy&)hVk&9t{OsgEI$rEz#eGHS87btx34M*_(P5O3@h~OML z%<@aFzfHq~Si@UakNt!0t!*>OB(Jp0kyX1V;Ow?pt=P^va?*_6x@@cIoN<4_>Fr>T z*QJjk({kTYJ?`CV&4p2V>r1sP0>B5TWTeY+POHk~F4w4z3zNB3(yhkQf_^R8&h>As$^bf5VxKh=!AjV^%ikj+)&Qt9@ zmV~vsTX4yzWH!O`S@X@_V8oB5;0B+;8?{zNvy6%0vKsiV3p^=Hn*110x!0(U%MDn z)~#sGHQyhP3ZsRd9+Ht}f~Vs3XC>o9{f1z9sZDD^dGur}M%EInlzam9UGjC4^PesS z=r-&Dm^?fX;z-VItT88n_@X>G3n~=?g{tCytl0!dfI#YzSmoPmb(x_MLi6|p76AH#^OqeTLP(&*6gI5RRxq+N z8)r|AGGr_K{0k?<^HQvMVA$cB)8s#vmBF53|2Yh8{zc;!07qDzais_P;A1ds>!ptS zn%lL4sD)gl(rd3VPQay6je6MUwgb%3n6tK+HW4iUl1UzX8qJuIt_}uVcaX>o>Vr~{ zqYMtB`z_uwH!%=)+yKeT|v&_cd5o{df+IJ6rkafN(WFyFBR!P%_iEf&Fy)<(~Qn_ zXxygfeg1*o6wUVSoU3r;_ePm^G&XVv$i&jZ#Qb^SOYvc-@6~Exha?o8Hz&-6L$R=+yg&|XV8G~aXuX^ujXAJ<39ArRKBp%SKB8;N>O)A4qYFn-?RC7@O|Bdx_zydH|B-?~{E zW=79}esbMf%Oz$24hVrIqdC%aO6yB4w#RSivXd=tIE=%{J#QyK?vxX$5!W& zY3iaVa|FCAH({0j0^lCN3Z|o=LDk*Pi?O&`r|h;C{XHYVwvLopC_GNZ8BqQ)v z``P{b!SCfbMf4Mr5?N(MUZjk@wmxIy)DOU z4vEEro9thVzV`RJbocdf_JetkSbLlMnL68@4a{mAr>=2xol)TQkbsazgW_GK%CxYsy9x~RQQ-b8rcO> zvUN`?R20Rr;#A)+e=vZ_BDGH8FTUQu134B$sjMN0mLa?$qv;k%u=2TdB(NMW1>H-X z#a}OxVcWP*cAEXh)%h(aC0hQEItGiYxl6{2D~1MQ50`tx69b~2e?Q+`G@l6rnyIBC z|76p~0qP7chvO<#NQL$eYChPw{J@WzVrhBESViwM8v$k7;d{25AQl2F9Q0P}&T$?} z1fDemm%?U7gKVvB|z#mn^fH4A{`-Wudvs7WvngK49*&orG6v+qBoBs<4U_+O zi3DU==6hVWTm-4Y_GxCGf3wsamBa5$?jMaqvq}lRU7?}}aR zv?6E;nXn3DQh~tDa`5YVPdn7#(tK_)&W!-OR8wn}kBFU^ ze0*$p@j|4%VhZI)KXMX?Ee~W zKNp~09W-sD5*W?$ynUwakZNJuh&Sd@>>U>9-e+%TyQ7R$_Q)k??|n#wB71MnKHLe}p^#Ow=i#VaR1&fhl2Nwg_x^mppHH9f z@Avx)?sc#C>$xA##{)*pd|XHivm>5B+v|&2>Dn3rAC_8v8XH-c~oh_Xac%tvmR4_V1R=nuq^(cAq z?1{3}RWUQLJ*U8mf7Gi>u~>i{Mm(;;%r=6g-Act8?Of!@@Z;OD>ml70Aek+H%YCSUH?C4q-*LklOYB;%q#F7KhCem z!w%YEg>fnEpKoCOElaa3MBYHwhfLD-$vJWtb?Q)OG}g8KSTg*ssl8J%Ihv_!7upyN zyP+pjb|?7wTe}vpR@pyXnHEr$)9|j*{k?nN=PO5>`N~au=gxwVvV1SecqW1}{9}tg z33Q^@%^N z4ASAJ41#xrf1{h3|2Zi)&C_Y$SG6>f#dndu5qqErkLhFx7Bf&iVz|PC(pp`@T8f88y z2VrU9S;yatvtAq1p8weWJ@WEM4UxGquYJTO-U%iI7R%Sn6*R$>$?LKOIZ~UG$2!k+ z*`SF7Cf%&`v#E}lTl$GLcyE>>*% zEGN*j76wAD54Tn|*~C-a+kps?8~Ib#)2}>d5+mzUE^#;PG8N&GU;7;~|C+dh_Cwh? zk$7-wyvXd`F}uM*8dc96Cj9Y;$O>q3@akN3LVRh3D(434czBM!wrHu0c>Prxtt?t$ ze3nDLK9GnY_qZCFTjOX_zmWvi{l1w6C%9!~z5<#+AiUet3DI8X5bM8>x<5l zK*zi`^ot!UUpV60yjr8+k7Va=rS6Lpa6f=+CzFz=Bz=>f`6)1dj(D(iVE2j4a!i}c zBUvpbu?f(P;DWiqlyoOB8M~MqV_xg&a|VV+fmu#F&Ai(un5QE^Fk+xlRd`2wH0{I8 z9k$H#POIiiwi{ewLOg-T)f^y&BazHFlc5)z##~+k^dtSC2_jQCSj~UNK&PsWzrV$i zhJB2yefW7=TI%oXZ9v9!8v5E+e9Mf$o3zozY`oU5HQ=5gK|(qv zv8lugiSylHZBz~*&k%fVVen978|2iUx8%HAbLZnuMkJZ*uGOXQCPQQK7nJWrPi-uvwMKyX?r2;=3d_7Y-uBFWS14^+#6W(eq$|xB}Y7m-)3FMh4Mj0Otk-{t7*hP zl26mIbZbDlQtJ5Rub}N|hc*6->Rqm<36SsouN~UqNwj=?=L(%R)8F0y$yqr2>sHJ} zy=|MMFuH%xY)*$U^{Nh2Z`$O5;4pz~2%VQnHW zRCg@R7#WUzt@`mLD+jB6HQT|NsednZUWh!O)@u59Bt!N63&tPX|61a>_(JaEpx;_8 zIu4$rSPs5~i-r9|kM4b{Go9Q1n)w7d;x=2P) z!lunhjsh0_`KtY{v*j%1Q05UoXn+43K=}Xl9zsq}`;Yg?>n3JaPxQmeKK_jT`#I~= z{IaLnDyl9xJijn8+evUgJ#>jVYDVZXi3Vq8U3&VAl9p0~7y!kgtcPh@VtL>UaM)Wd zCrY1(u>(>GLZtZ8SEz^9LonO#h4@fG>;?49M7aPDTNj0SW}{wQ<7rEnZGADe%VBPD zAb=6K!U?!$)V2Zxx+Ym+E2ehO_%4zw+C-hb4@5ta;n52-1h%uErs;=gfvzHmwE)TH1ey+Xt>CgsAGJ#n6Q`Piz(k?J$EDqM6txTq_d z{bg zd%POZJU*6BqHenAiZgXEpq8%CQSv54`1eAX(@_qToad);uOF=hE0<~Nxh^A|O_mfN ze2vteW4`GXZ1|0~hj$#{5X5U?K|SR7t;cb-6Mc$S+Nwpkt3sL8vhIb#I3}cQdQ^YSYy{Y(-nt&5q#d%eE$rfY*9jQjg{9FgvndyXrT8JK^!DbWYBxOY=!;9 zs|s&QUZ%0wV}6m2D_c~*2Pn1zaghQPz$zOv@^xhK5B)!ZxWhZ9>MIEO{`yZJk=@+{?MQo}^Jaid5>F~7G3f&~FHP=WIg>Z5LA5!Kl`PE$B z?l%(xWCZt5`;*L&ufx-S{FN5|*J?tMF}01{amtv(cvwa_KwPSvbAMy3z1%{rGaJo; zxKWB~pmZiLX^M_>BYoq|bZ(m?@5%GqsVNX4aoeS>jY3eX4(VxdDvS@$9-ZCk=Kh( znte=EOZJ);FVE{Dl)+6SnpH#bu&J>TR^heb5CdqxLcaI4qECq5Z7zW|tVDx_!QcnM z)w?h@^lfK&GE{&*6jdJeG1+I4`~>iem@a|p+^6Q)0QusR%U}MRKmT=6fXJI^5*uFa z3(_dbn}vF>%k~EoZ~FKfvMPY_uvkxniky5fmObD$^@|)zU7kS!1$qns87j`gDSZl) zwbuSffjstS9&2@~UT~?fxH|zm_#JMTqSDkRGh^~@H#-j>GI&iPRD3KZep2Wf;l{&i z4*Dy)IDdfqQHxGoYmiWxlP9~f6v=;0qV6wkhy&j{?3lkxlG`x~>@zAwIDp7F=op+s zg)UQS+12K4zB*wa-^0nOxm)8$;nG(>m{*4PbUU=HIU7STTp^dI z*UVnkTX$tYzsq|3C%>Hx=Z6T+UO80x#C?oK0^pG`jOpBc13kkF(auMyLM!WF5v~UI zk(w(Hz`K^FuDwqaN5}c#9z8ch{&`eyN$g+rtua(gj4n8LO0onCIqR-;jP`4<${~7@ zszhOTE2HE?X+(tc1t&PZiy4z&PAX%l=!W<9aVJr-GK1TSe{{5sci z9Q*slK;g)4C;x+>tg`TbW&3vGDRC0UGwP@29j(V#==&8M1~gq#+i=%34|&N`6c zkwfdA1(RE>H_v|B(Wrncg(;Z|4U!YY+5B;O%9ZHX&7}u#s{^sie@)FwdZrmeO4>%pBS$jOlIqX!B@7=Z>q zMTD~zpcLXq4m4t2M_8Pp`K|#>-YW{hC8_dL+fH~wWaowGE9R;Hrho!6emx+EtqchZ zfY|8%6+FNsf<&{PN})qy7Z541QVmLlWpH30d$+)n+OGh=;P#%YFMoukN-)Bn^*%p8 zG&cSw>w~clwoNWIsuR*Ts9dxIE zx=c$Tg%Cu#;^q_BJ*_3jj{9G`_}+SaTpr5qSFL`*j-;f#OHugA*J#fFT`@w-lF2z$ zI_|4Jk1J$q00Cv2J!T4=y;`V!HEUw(E!!uEmd93+Q8R_(J89S-Gb#rD^>t(Sv#+K} zJ+UwoHz5@pT#Ic~R_0jT`Q|Xgq&6*eL{mR+0)ESp4Z3`aCApc<^9^&NG%|& z1BB2(YY<)z59+N0G~)m9Y^v6!r4w7*w?g;S?o7F@XUb%Sl;0K{hVieuXyz}a%b_I% zgo}uSr^9M>lb-l=6$qK?{I*y(0ga*0>z{lHKHY4LfsF#R(SjD_*G>1;My6IDQy~)9 z!Ta1bvg*~M0NC4Eb<7xf&kk$kSflpuGusAK>Lmeka`n^>2Nq&sYu)pLEaWww+UpN& z7kwYf#wBeOmca%eEplEwS6`bZQh4}yY4yh0=dZh5;68xcTlD=Td}u`envosTv~X9g zIxYrQ(y7jiSs$vzHt`Qn%)|j?r}O7^?zjK7FE`>c+N&7dD*W!QD}Ma?!!k6M?*C1 z9$$jwpey-Xc`iO`7RUyLP*Md!K)F6>ru7%fK#zAP5(aeA(A}F zmN58{Xa#&&eE%lEr>III6m@Cc_mWI>Bkc9DiPhS{L1LtJfsod{Q8^|B?F;t!+P*ac z|1h4Xvyr(D9)B(guQpOH;A39o5piwq@2ms>EoZYYS8E&v$jx;lnj9BSj1QdfDwxn8 zd9O78_`b=zF#zpRjx0S#I2-~KNR7M{)}OoQ|BBu~ym}X^vispKw??$={OoLKn|yau zsq+J1$rjkM1vYQ5{yP1&c=Gcr1qDT;#r66IfPG-&UH?yDHMh&!G5jJjd;hne>D-Ur zi&uRLFFbbT^FlBpvd#NPmy==TO3e_P^4)~S8oxvOWB*4q8N zJ52f-v@DMjlblP1fsVCzvO@+F0{Rn!6%TT(68Rqktou1o{I8vFRspz3==9yOxqlj~ zz>Sttu-72g#LH2lwEOJCKd5b|(*Z_L|B3ACp7$vDF~$#vac!Npc?}`|B?|Rmx$h=* zl@Lx*xJPuALKo4z5Gy62h*4fI7Mk#*vs`gJ-PKTf|KeW#QH134)>^{d8j(8c3^|i* z$3-SB+JN#DDv@44N=<)G_%oFKEkpk+Z(dKem_4PfbqA`t5J_|QUs=yS_cyhfAwzc) zUJ3oVcE7hIm++p{VxkVG+WpB4@nU?xG7vv9aG52^x3Z8f0pLl&V`6lQL2ClE@=6dT z8=ocfoyij_yBHHI)u9jE3&h^X&n9D19R%2ShOYK3j6@fuy0upEE!Sn~lVddCvF@cz z3SiANbsWI|9?~FMhH|PNg}H<0;nL}iPGx&PZ|sO#=?+YIl%XPdp~Bxc2`m5=p*A-6 zbLHGW1zW57EonxG0?hC!YMQ2dmrkM-rM`AeeGr`k&y+zE_+-VLl0eEV6{{QN$3zN# z@IDk{%`i-iIa#zF6bbF~bj4kW=r3P4|)Hx}u zbg`N+O)efUHR4}!+^JV0d^VDNd=ke*3>?nGPxn8@r6^66#7UTAOTt}SCjVGV(KGcb zyl1Op_e#jpL*sauJ}ggK*dCXAWBE<(m&`@ZQt@XL>x8erwRK=zS-NnA3|3cXax(-8 z933zzy%IQivya*`*%<}(ugx##Lb`Qi&k8pX=%*y+UPL9UCO}C0`efAf5Xc#59c$C@ zRm|m$y!w?z&Rewah9JEi-NEJMI(3bO)w0(z(u!c^cTP$*mri>4*|(eEH) zB^peAgG!UwrD*o`26~ud9#`Li8M=Do+GD$eL5%~30wY#w*BD57a4Z1YCj}UE29((F z(|0uJIfb)gkbPh#vcMKq;{$|qmNUW%ft@5!= zcMKvh1MkQhF!o)t4`W~&m-v%^i+cQ|uS4M(3JMaiB%)=57rh<}te+tpi-(a;3iRq{$JlRXw!CZ5%&rKH$3qgHBvU#dP?qIPOUdToJC}kp zChdaXb0PWGvESXOV{|!sE+6>`o@0Qb4lC&7eiwjF>y_cXrK=^UD&&0FAO1;+@npDFNuGU{*&rY%FX6;@k^z zA05mPn}f$Fh&}qS<_%~NBfs+N?vimsdW!|52wW|9{8xP~X4f7;4LGmkB zU`T&2Jr-K84t0uq;P)NEq-Sc3qj(o(P=r7jWWk-WyFyr(fXZSd&&9Vp-SQKjWs!z% zV%`Wnh?&=Z;eu}g?MAa+4sUH~}!*RDLQs{ZqRUy;PXgj+Ph3&-I@M7rRcy<`w& z>ktV}*Q^-6c$g}cQS_xl=+zvE@EXx&ZT_-H(fsSMC2i&>t)>$f=a0;>*n2rwZc25$ z1N1@>Lwb5LInLu0S7*|_7!w}4v{Le0k4n0*bz*pqgi@QtSng?q>Dz{?(u`eNL#h!^R7;8s&b;Nz}p* z8=FePOz^Hz{Q0uO+vr{sLv_w?kj3OS&c9gLe-INUP?=4W7C?%w``P3!sW*VBD`803&W8h>H@+~>`ouV71DtvIq?Tq^ZsWXxqpQM+bIG!D`L*F8gqRM(7D@+>0l z-h0Fr5iCR=;dV#a(bW(Hb;p7YVIYt857ML?(;HE=(80$%&~eYvYipsJY~=w~xM?O@ zX3bQJL}J^^Wt>xK1@iRQ#II7^0)UHJw4APDB;JeMU(8Pm1Co$ZeDie^-5UT8`^OiT zY5vU#d}7{$ZCCK?H`6nmjg~--vhQ_4x1NdE#aP6G;jn??P-Spm(n(X*vK3kot+TQk z!{;emnnoDn_P*_ki(b(O^Hai^#%EH@T;X%xS+&5>b1LaZURi1uYqEJ6>U~yHq{H%! zW?L%yC8cPbprV~Sx~awu!!(#RlcBtv<$*rXLJq$Y!d4xD4{f8O?g{^Uch7-HCe8Pz zdqE?+7D4_Y=geiqE!!5wv+~-IT{ie*66c`gq@ER2_Ph3JiaxMu{GFNl9(0NblE^hF z7Wv)jt*9sn-&$Iw3a_reLs_s_WXz6~rZ)FVRVUM?awERx1XdLYVR@8uDEWe=j+Pqz z1=GAF=*1&VHmQ7t9dC|#%nediX@F<;wpxe(d1W^2HDU7S`x7&vj)p-*rq8$aE<~qL z!tVRH58@8H4%SsoR>C|^Zcc$7%)QDI5X(C^ZHz?DMH4>ju}pI0G|`ofEQlt~|a8$|)pvY6f6m`G8f=WglEO<|({>F(} zhQ0IrpL=^tk_Q4N7rU-m1VB)CfRhSXA-ZL#&M$Uwqx{p)-1VP4JApELoo4cb8iEPW zG&f(xJL@|4zP(jhigEmX)LtXkFA6da_a?_y4@0+8>7KDRNC*sGVn+rzY)hF_y-aqF zBt@o*tw6BGPKv3ht{bJa9RR(6++*o+POtsSW5V;*N@|L{65?Cfe56*$vPB)=l#WxG zUQ+2qcTBgXRvz2^e*hAHWh$A{#(!q%)H5rXM6&X%tY;X$PSKM#Sv1#{IK%rg~!xRRuylDu2vUsqK$Ri{M#G70v>a1 za*(-}ROLsF*}xNEMMUp*<%h)}Kck`kyT*IQ)tr2Th3G>P2kOS!7NuKH_ZR&ZAT3#t z|1UGKsYBVppb>~{L1Syh{u~xH)AY|Sg-i2qY>OQ;`&{-3yj)^Cl$UTVVqkq*=@PHn z(zHb+u9DePVP$^O&e+xKYPA^HUgqf%^=lzK#5%85nQW6tjl?VqsZXDyk((_U#~imM zf=bZ`*ENDM_)o(^l4h9OP_sa zmJ(hf0SVmmwX5G(AB3bZvyZu}pb!U3$@$HRQ*tzVdSW=V&IY1Vz`H6G#6` z#42U2=#SVLjx+thJs$_6E5FNDa^AcMbzzazs`2*^eW@wOU*10HlfnrOz%shGvO!O}P(lPkJno9%)-Ou3Y>;1Ulm;$SpGXXRZ|4EOP*gc2w`gsyN zKE2~9HEgo-B@IP}@zu$^idQuB1rw0QmleS*KzY{JJTb%~A)d;X|Hxq9d82BXBU;Sv zCdgP>W?+f5wzT6|>Cj4YqbSo0`rFyAyI^0cSpT3*HE={SH|b2C?XyX?8%oiI^WA=x zrJYvy%5Bo2n(JpohI!$jkq9Cb)A;W3NUkonsgXZy%H7)QPxyFC(gv*KCK`i7g$&k> zJ1X|V>hbzH#J5`~#c>5o^>+y*A2oM^Oo^B&w0^^AScGS8o9hpiqc{|hrqnkXQAc!& z9qdkfGSYbVI=F~)28=$R32!Vc$!;W9SCKiH>dEPb1^VK*M+AGBecGe53MY{@-9*wQ zI-|^!%rF+cC!{)=OT^gWr9PvVA7ci;%%Waq|4(9kOIqHnVxoWQLu0n+db|jRFpw>` zY3q~U-%qBjPyMmELWh<})oScnA2GRq=9vox9z~C9e6QHdx(Mz>;Uqeo5VI%5Rti9AZos2aF7DJ*tj@TgLNBM* z%V_9V)~qE~k)Vs;Z+zTk_0bz+N|$MF{?ixlGoYD<-2Y`}0^0F!iV1_*MkhPFOd{36 z-MD_R$U{b%WKrl8Muhr8Sr_B~1CZgKhPm1>%}{zs<`eRBjgjPb8i7>a(04=C`FYY6 z!QhkpYsv1$5xb$*dHsW{>TWF)DMs)^nG`Rgf?av*Tq-n`T&~v}()D(}AqMswGajW@ z>+TI?5WX@+TfUA9=3QV~jwCrj&t3IdR)els=rr8j+&r!&1nh3S(XtSX=4+uY-($`Z^pA^7kXk_Y=Uqz`bHx*8 zFELv&?Mn?L&k`vJcB8FD=UKR`38?&l&^1el!n^Nl_#b~em;cOfkul|X)OO?pKvEYc_oI*LWj^cA@>-I`#2jt<8}T*T z;#<3NOwgxcr8KTtM4mj%Sf-YVJ}EZbuSa5Tr=KsbvI9!pckIh=B`DOu+zTe%IUnH8 z#K1-feo1XQ`$Fp0E0h9)t(H=VG)~-n6PWEyDoXD(&%v|>zL@rCFek$tTymqgUq9b< z=4Yev&AN%)vnM-`>+w%_ieT>Bf2v3T?uVpdHFtM=uvd%FZS)qeWwfv$VlFpbbsAVP z6YZyEEPHXSHZ_mfC4k%iGPNWj-BU6adn1_XO;+ojVqHbympE}!H_6-N--nk`SY0gH zcn#kTK0BaUs+iFE#8cdCuu{8FQ3qez)hR5*!j_lC3_&Y zE!>`4xnxsaotX;cfycFcduV^R{(pc3w_~Q*Ar$4oncbZaJhL=OcfrKvUhK(RdQnlve}L)Lz|WCewiM?{$ZHj%4h zp1?zHht>~iu9A(j>Lj{e`xa5`Y6e!7M`YAJF0V=M#Igc;#WPVa#kM*qYXoyO7FR!?O*+Zo!)@Xw&t!shphw|Sqm7u zy9Mk?@VN4%e0VvhRL6y^0an>r2fczfVZ(od8-xfwKuNC?dUQ$=Blh$X*AN zn(ImfRUMTAjw>7f-6MG{ z&ldF2 z19T%L@4W((GRrlw@~AwQjkEy4dni>q%eiuZvVzIn08)XcbgrRmhCiDYHcq`kHm2qj z4L+3y^~_YPCRkN(V(V2Eu0f5(Vw<*IbaW|oPu>f{6^B^qeSwvEx z3s@FvmBUGl#I37dqIplo-$Z1^*r7k=M>5&VtRcmv9?e6hP5G0YW7J3q1{2n@WQ85( z0OoU8ivRIbz+lu1eFEf-Tpv4HCc@^MlQ5N<;AJ;TGenRWBgu7Cjwny(1Cb<3y7lhL zf=CfRG9!Yo=xa~z#vGx@h-dpwlFh(oOBzgoPHknSXYwe?Yp@2U+)?vzGIo+3VO0b3 zfhxqZK@IhxsDckJT%a)k)8i(F=2#VaIShrV73A98;#!jnji3pv#PLK-mck?t=jX}> zBlXxVJ7>+Tt^OxwddTeF0Rgj9@AI~Wt&B*Jaq#^?YQ4~i@v=BWiqOd?_Jvds)9&qh z0BoZiM9s6VyFG0JF;#c3&i6<@`4Xq7Who|uxEsyBM?+?MZJ}PIIGRhwo*zkP)Fgk4 z3OUdnpF0893gkJl-GDs=9ymn@bZp(l4@n}=@@iL~K1+f@{6weY4I;v%95t9OUJ_1a zE{0g!`XG_{Z(;a}J-8E=7I%B=)tzPc6yEHHWg=#0L$XCL^X?%HaGFpIEZAWcMV$)t zDPGHu)m*>z_j>n~Wj(&fo_a=uaHcX`}!v+BZ7Ja>D6Iu??Y%hIg5^@?}49}SuME_Wxt z;7{JBz|N^UM}*XU%y7v!Cd|~5H;8B3g>5x1S+{|WN@jqP6Lgd_7)I~~7;Nosl*Z2x zk*jYoQmTs&6wD3|J*bS8-^}Jc^P{&k%!Urlbc--ATSP3gX1QjC3OSF$n8?aI%&ubK zu4=m8YSYI(p7KNEjJ&R>7yy5@?4@?Kax=s%9)o|W?bpcPCsJ|q!PUNuceSsyu?mir zYX2be{wisl*0&!5E9ehSv-*MFjAqOv5GwX0Nhl*UD+ydTYFFIa%KVXPa>Bvt*ZG-y z_zAk5lBCUZ?0IIjn@Q)&>J(N0=H)Npc5!W9*9>)C5mI~~G+escIF1^rEq+SrmMXh) z_X81}k#2yNNm0XIt-geL70_Nb_vklWG?FSu(Um_gBav)1K|Z*CP)TV1cVJQpk_2=; z58dJCsXOU+_4E9%Z`oL=#B%Q+UUv2zE6H{B`JT+I<0)-tEVf?Cc9<4lL53E1%IZ^1 z9qvCWSJs^Wa)<;umc-m`he^4HyNC=&m!8^AN*gBov6K9x4b9 zc!Kv}{%Y|YyE-6pQ zjJbYTDo=kWJ zvSei_W++C_jsj3$$6XtTAk`xS)PMb;lzIB83xwh($fy3x()_Y=0f;Jj~_ z8k8QC(*8&m9E_+Uz!jTBN~(;t_Gg1A#7Ie&E@$Km4ryxxz`~s4VP(_41oJO8lF(k& zd#Om9s^`U~H!IUdN8C#Mn3hpqIFY<`F|#S!GZRN@Bpcc}K}4&SHqiW1hy?(-xU{j? z)>!8CEH1B#+5YJO>kuuTvZ|!3!Fa9oMSVflzxnQt%x-XqzdGrM1@2E*o|g|?vGetp zV$Mj9kI*q>~SjFKr7J>#h6))pk8PwpuQ8e%oTNv|M~Xai-;)*X`v@r#^( zv2Hx}TdrIpdaQ#2F?w>n4ayeoXCa@XV%`${iFxbwAopr^y>wXa$a_UfCV!r%4y*Aq zn)EtoC|-N0Tc`~6^Bni*xK{A@G5S!@4>MoW%ohbi>(nH7!htJH?_$|t2 zuLkc|-ttRkg^*5AUWt|yeFXvyx0a!TfvIS>_W6yguaw!5!PDyCknvFiaLygK`ci@0 zP_FeiUpSE&`}%q-S4MvFp*$`ueQo6o|3ypz0`i|;Zv#uo7c+a!`jRCNh;EYH1ZBlY zkZ}v9uTN$}hDQZHXBb!4GXU*+qMLbR?K|wF>kE>`^S zKCZaT>ZHIdF6qrz0FHFTaQ2%9P5$3?p}+3YS7vu_oa=O;dt?3<+}3zbtE(fVn42G$ z&e6|ea?^>bd!-&fT1@(`X6HUz4s$bVlth0r?fP9;Ww2X;DN)6_zJd;#@J{kA4UOhp zdikI#0J->XFDbuLD?==v@PaY+shguIr5ycHJ*%+ZsF}1DK&n%rI{Vno`D;(#*4R+H z8OA@lS`+-VOeCktOhjo4(5s5e^$q^N-2!Q!~n9)-Nn5+Wxx9ul5Q z;YBeml0CH1X9|gxB)udb)heb=-K4ci;X={F73MDO?3WpXthUcrA*4}RVV#}bnZ{8M zZEfs~?%dbFFmAdgwcCkTrg>2xr;!DW}XBrYBT z`6M#NY19GP-Vz(ARF02XBI$kntfg%ToV+j}vA(1^c@EV;Y{QIc-R1Dg2l6rMp|s{U z)256O z>~Q_0QvtOM4x`~y2fwAD`)s?g6M9kb`;CA7$eRQt5t%lY>ZJ#6iTJa%E{@dAeW0z9 zjr0p>3InK}?R|;m5=8aI{J5#Yt}Q^7qk~P&-@VxVCcFC9!i?X}agl9qAhq)5nC`pk z52?oN0sbC3Fcudf0|NxTVV-3r|J4loXjsSEdjHpMg!Olaa=34A_y4@hyE0L9XzX=# zoPlq!lne>+64BryIf7EeSby3U61unUCnMkPKgFskBL<{}abY%NKlBr4bi);>5R#Mc)V<%lEU;-#n zkrue}K*p|=zbhhS=!Otxkv$jnNZTeoqn67eo-bSy((=%;?0-UEs8>wY3z|`yxSzf$ zdHq+(C?R8n{Z%SC-%j)3w$B#6f^%|=WFi%wU|9yBmNl8X%g?sb#AD9G+z)eMyNqGt zjy<_PJfU{j-m4%gpiIVDOpWm;7}FWh#%Kza%i}!h%;E)HQG2nW^Ol^=q!@xrYl;wy z@*sV`ntI0DVyaLV!~7Ve7|++IcG<|*x1=qp%fYLCFkZ7-6C}C(r(X|lam&&C>nv@Y zHYNe+%0=Mo#voG^hi&MK4-l=bJyMfyny?y)0!MBFI@Z^R8YEEwp!lt6o$bY~jQP zED|Eb+QnXnNH7%E=z}G)i8CaHTqg_@IoTt;P@!P?4&SWL6u527;#*s3pUWSh>Hi8I2LpuW zMdfvX(h0l%Qv0#DAc|7g!xf>7>tuWFS?_I@Kmu;6fmhJfP~DHx|cROe3B4XXE86&rLjOZ z|C{O_7Ga#`xH{CN;Yp`riS4Z|{~vWkp2a$3Hh3$nZg^PBKP#SD?CotW*Xi)I@W@Es zozNo#mv)C4^>%@~$sAW=UX;>u#+?}$PBVNqXRqN`exOF~m!eYZhW&J*fWcTU=IckJ zAbM9690pah7^v!YZKUcLXKC*cQ$l4+QS*ig$QlJx4y$zMFZF&3FH82>9w+t{Y~H>w z=|kOn7H7b~4XL0j0ThF7_N(&-ssnHD81MT+! zoz@TS2>aP%pR3Q7(vO$D7F}<=UnqW@ONhH&&ylPWyA>ZVU%atXkkU~iS8knd9ytm8?afjVtZbu8@Z zu3XzbXRU&G&RshCa_>R9I}ZeCH()x2P&;+lI$&uKouXztZLE#z^4>B<2NjyQ4LvQ4 zpZlU$O?Fj@hJ$pi-BCr)43jz^iZFKXjp|i7S^Z-jp7Ef|_4qmN8Ap)z(>k@cza|Ao zcU8srnmM%AU){A%q<>?A6d*tIQL9E-RR`CEKM*SSl)7BI%K3fD)Zlfc3p(l z>(g+<9v`0DxT=S4eTC}a7DMAiUABBgp^t!}%Ig#3>=Mmm+XcYl`S6Z(NJqa-xqqh z)>b_GI6KJK>fP1p>46;4pUIIk6%!&SNB^4-FIc(?;j*y_3M0@{$_M_C1SXw1cvv_ zQwl(y5PzZ{bqGl)ni1$Jf0+>_=bJB!y@zn$i<3$1+i8K$}j9Vv<$X5%Xt z98tj;=)N-ar!xS7IX*-{XeDme7`dO+#$!H<*M*R8wy6}DW~2#V73n* zf^RKk_O!9&3heu#YukYP;E3wsAp_1AO+@kz45v|zlj!J>uI){Ue11K=CXcA>vo9#6 z(08w5TULUex~h3_u&v!fOyMT#=-Vv)`LF9L3GHHHUareii8Kf$({~e|J{BX|m58%k z%VWwSg@8;wnQHSM<8S8sJ}H%Do=g>o660=3;1>!ibwdc2o0(LY< z@+8ThuKMLGUPmKXA+kJWtas_R=uu|y3EKzBpge@IQR}?&7=*{I4JB?KWpki`NJtuh zCuX4p20bXSOXrvH+OObZ7}%4bb;{+Bw-8M$we< z-wS``aT9uter6uJ-@ZM{n_Ceg@gx6@Lu#7#hUtD26Y^KcY2>Y2dxTWE$g!WYqWEKD z+C5}vl>FCh(9YTaeV^aIa$i8+_-yUyj;DnVD347qbDW#0R8NoB#A?&@$jNn@)_*E! z?yttf?sodeWyt!hb});BlL~5n`VrNH^oNKvqhJ|pMM69x_xc-8EZz@yx<0hq3F;iE zWZxJd)}qqg8%F3tweOqf5QYVX?{3_KH>ifD!>-{x9p8=YJB(rkK*Eax67Z+h*k z&80cMz1tncU)wu|_}Z9j+!@Mw)XRVN_tzf)WgK49J0BQZ^7)OsGB%B7{$H9N`X|6S9{vtyJa&>h6F3go|NIabij}LSa;-{MM$F`36Ck)p(k>zasE1)2kRs} z3Zj>WxVzGCbY0;JU+xR{G;f1X3%x9^l?=(qqZcJ9c*FTw)|F`l+7SVN2q97_8;TwT zBf~fJqjqy}p7l{XhUKaA|#{Ji}7 z@MN8x+k^cg^vv@Aw0B)?O<-G8xRy~wnllIk!E)&WLy1B#S0uc!W z29+uSsgV)}LK6Z+6vc#Q2I)-*1P}rk2)zd-A%R>*y$|;v+y~Foc|2#Iwbowy`}TLX zt6tl6bt%}8BGXm!V!Y@KoAH~3U2ofK%pLpe4r6(NyQexp7?sus<}{OhB=8JD!X6fFGX6SL%1` zUf>itSO>S&!-L?!o@*KKk{&9RcH4EWFf!uu|3Ecj-EGK?^5TpCw9?Dk;!^C2deLK1 z|4U-Rc!qJ=@Abh|h=;5v+>Yle3UT?t#R=k`dngH!T1mK)U;@?hYQ})Orh`?IJN$!k z|Kx{p@6MP9U|Z9h?7MS8Y0wuzS@4X_00%mQU=mh6)M-MqO@>b<2K4U60_;nZRP2&f z7|;a2eBD8lXSO-ea^|OlkMXuba+9@!g&;Q-dHr$3?~HnTgr-3}-(~3!Sl{NRq@-}U zam`tKEqi^Xr z>0{@)YL^( zxZY~agqAkF3FC9Tf`ezKr>AG@5HD(K!dOnsCKZ@<`pYc_J}fWQjO68AaQ9W{IGyaP z0|HOI`CQvbr}}dd++`+@S5Xnp;*fTzEV|my5Khhby#@A~G_KydY$QI$ zwPbz?Sk;G-7LH1JHs!Mtus52AaLkTD`@j@vp1wcFc{`D2Q+~0cvI&NasP}*zrINL z2%TQ?ExOws18)MXstd2ia?j#>F%Hk4!OBDYJpEO6E&2!E>3o6QI`u6{ z3?A|7OVRFnyG{fUnIrPV5ouyxB&(~IW@V$lt#ndv_HJ#0-%Nmp+dDB1{iT+lh8dHPCbk8RT6Cd~IlEc&YcUpG7D_4)8wpqJSAimQ#pK~xh z6EPX_n5ML2vYjw$_h(L`1unIxa4hEeF7y(@0cwAO1nStaJ*G1;;o|daS@|edVc1U{ z>$wq0cqG+luNq5z&}vhZ%YJ2s4PIU(8RL7N@gv8;UvtlUp`Pj$4RXya-{Z9K`Ewce zMHd-9vT9*?#>S0+7OSW*DIw)W|hgu95G}Wjmc!;s1#IQ~E{S-FW@ay{?iiQhC z1R~|~fu)wskTVne+lyToHJnKm^(j!|x{FI)_#;YR0c11`u(CiRI{8mVB^knaG&9Uq z2{$AXpJvU5%DLi38b49VW@H}fl4{rxy|qyBV|uJu;bDMU{cZEsUds!xx1VyQ0_{Ho zlhdDD5AhxADrR}hTa?&9Cxmo2X%{=6s!e4LT|^gyBsHwn@+Nk|y|rid+dcVTZRvq` zCXQvUn{~^fnG3WquIr<1lqgwb3X%tw9qzO4_wn{Nvx%xjkI7>q%J7uAEBDtLs(owe z13{Xo5Rhzp{_;2_zwMxVz2fLNtJ55wlWGG*3^-l0&^MUr$OOY_P^peKr*m6ICw+@L z3Ron9Eh26(HLw{IA>p!A>x0{v)yCDP8{2wR7UtSrymxjL>FpL!zd%72dzIPB%^?M(v?=BfX(swx5gy#OTQONd_5`A}un zfZ>!~5O&=ODJDqCp!KM)1-6fRoYg0eE)1Z-X*lAq)3=vjE&!V=h23kFw1_#^uJZ zua?kk2|%LN>rEcBVKS&Z8jYrAiic1aC{;JPylc!($6VeGmH_9@Ke}#{n+z=*yW}+< zi<;>W<|Ejg<}3#E4TsfFeI=q%tG?-R>^p^G1uGaqYG#&`H$xkovxmn&hYpsxskKS9(XEI70VW2C;{X5v literal 0 HcmV?d00001 From 7e4ebb739b9e47011f95b67c7317a92cf5e95e82 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 11:04:58 +0400 Subject: [PATCH 135/200] better doc --- doc/source/api-reference/qibo.rst | 58 +++++++++++++++++++++++++++++++ src/qibo/models/encodings.py | 43 +++-------------------- 2 files changed, 62 insertions(+), 39 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index 0390a1a1c6..c28aee53cf 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -319,12 +319,70 @@ For instance, the following two circuit generations are equivalent: Unary Encoder """"""""""""" +Given a classical ``data`` array :math:`\mathbf{x} \in \mathbb{R}^{d}` such that + +.. math:: + \mathbf{x} = (x_{1}, x_{2}, \dots, x_{d}) \, , + +this function generate the circuit that prepares the following quantum state +:math:`\ket{\psi} \in \mathcal{H}`: + +.. math:: + \ket{\psi} = \frac{1}{\|\mathbf{x}\|_{\textup{HS}}} \, + \sum_{k=1}^{d} \, x_{k} \, \ket{k} \, , + +with :math:`\mathcal{H} \cong \mathbb{C}^{d}` being a :math:`d`-qubit Hilbert space, +and :math:`\|\cdot\|_{\textup{HS}}` being the Hilbert-Schmidt norm. + +Here, :math:`\ket{k}` is a unary representation of the number :math:`k`. +For instance, for :math:`d = 3`, the final state would be + +.. math:: + \ket{\psi} = \frac{1}{\|\mathbf{x}\|_{\textup{HS}}} \, + \left( x_{1} \ket{001} + x_{2} \ket{010} + x_{3} \ket{100} \right) \, . + +There are multiple circuit architechtures that lead to unary encoding of classical data. +For example, to encode a :math:`8`-dimensional data, one could use the so-called +*tree* architechture below: + +.. image:: ../_static/unary_encoder_tree.png + :width: 2000px + :height: 2329px + :scale: 30 % + :align: center + +where the first gate is the :class:`qibo.gates.X` +and the parametrized gates are the :class:`qibo.gates.RBS`. +To know how the angles :math:`\{\theta_{k}\}_{[k]}` are calculated for this architecture, +please refer to S. Johri *et al.*, *Nearest Centroid Classification on a Trapped Ion Quantum Computer*, +`arXiv:2012.04145v2 [quant-ph] `_. + +On the other hand, the same encoding could be performed using the so-called +*diagonal* (also known as *ladder*) architecture below: + +.. image:: ../_static/unary_encoder_ladder.png + :width: 2800px + :height: 2329px + :scale: 30 % + :align: center + +This architecture leads to a choice of angles based on +`spherical coordinates in a d-dimensional hypersphere +`_. + + .. autofunction:: qibo.models.encodings.unary_encoder Unary Encoder for Random Gaussian States """""""""""""""""""""""""""""""""""""""" +Performs the same unary encoder as :class:`qibo.models.encodings.unary_encoder` +using the *tree* architecture , with the difference being that now each entry +of the :math:`d`-dimensional array is sampled from a Gaussian distribution +:math:`\mathcal{N}(0, 1)`. + + .. autofunction:: qibo.models.encodings.unary_encoder_random_gaussian diff --git a/src/qibo/models/encodings.py b/src/qibo/models/encodings.py index ba0e5a4352..8d37bb8922 100644 --- a/src/qibo/models/encodings.py +++ b/src/qibo/models/encodings.py @@ -112,24 +112,7 @@ def phase_encoder(data, rotation: str = "RY"): def unary_encoder(data, architecture: str = "tree"): - """Creates circuit that performs the unary encoding of ``data``. - - Given a classical ``data`` array :math:`\\mathbf{x} \\in \\mathbb{R}^{d}` such that - - .. math:: - \\mathbf{x} = (x_{1}, x_{2}, \\dots, x_{d}) \\, , - - this function generate the circuit that prepares the following quantum state - :math:`\\ket{\\psi} \\in \\mathcal{H}`: - - .. math:: - \\ket{\\psi} = \\frac{1}{\\|\\mathbf{x}\\|_{\\textup{HS}}} \\, - \\sum_{k=1}^{d} \\, x_{k} \\, \\ket{k} \\, , - - with :math:`\\mathcal{H} \\cong \\mathbb{C}^{d}` being a :math:`d`-qubit Hilbert space, - and :math:`\\|\\cdot\\|_{\\textup{HS}}` being the Hilbert-Schmidt norm. - Here, :math:`\\ket{k}` is a unary representation of the number :math:`1` through - :math:`d`. + """Creates circuit that performs the (deterministic) unary encoding of ``data``. Args: data (ndarray): :math:`1`-dimensional array of data to be loaded. @@ -140,10 +123,6 @@ def unary_encoder(data, architecture: str = "tree"): Returns: :class:`qibo.models.circuit.Circuit`: circuit that loads ``data`` in unary representation. - - References: - 1. S. Johri *et al.*, *Nearest Centroid Classification on a Trapped Ion Quantum Computer*. - `arXiv:2012.04145v2 [quant-ph] `_. """ if isinstance(data, list): data = np.array(data) @@ -187,26 +166,12 @@ def unary_encoder(data, architecture: str = "tree"): def unary_encoder_random_gaussian(nqubits: int, architecture: str = "tree", seed=None): """Creates a circuit that performs the unary encoding of a random Gaussian state. - Given :math:`d` qubits, encodes the quantum state - :math:`\\ket{\\psi} \\in \\mathcal{H}` such that - - - .. math:: - \\ket{\\psi} = \\frac{1}{\\|\\mathbf{x}\\|_{\\textup{HS}}} \\, - \\sum_{k=1}^{d} \\, x_{k} \\, \\ket{k} - - where :math:`x_{k}` are independent Gaussian random variables, - :math:`\\mathcal{H} \\cong \\mathbb{C}^{d}` is a :math:`d`-qubit Hilbert space, - and :math:`\\|\\cdot\\|_{\\textup{HS}}` being the Hilbert-Schmidt norm. - Here, :math:`\\ket{k}` is a unary representation of the number :math:`1` through - :math:`d`. - - At depth :math:`h`, the angles :math:`\\theta_{k} \\in [0, 2\\pi]` of the the + At depth :math:`h` of the tree architecture, the angles :math:`\\theta_{k} \\in [0, 2\\pi]` of the the gates :math:`RBS(\\theta_{k})` are sampled from the following probability density function: .. math:: - p_{h}(\\theta) = \\frac{1}{2} \\, \\frac{\\Gamma(2^{h-1})}{\\Gamma^{2}(2^{h-2})} - \\abs{\\sin(\\theta) \\, \\cos(\\theta)}^{2^{h-1} - 1} \\, , + p_{h}(\\theta) = \\frac{1}{2} \\, \\frac{\\Gamma(2^{h-1})}{\\Gamma^{2}(2^{h-2})} \\, + \\left|\\sin(\\theta) \\, \\cos(\\theta)\\right|^{2^{h-1} - 1} \\, , where :math:`\\Gamma(\\cdot)` is the `Gamma function `_. From 1c538eda6624c6732c4321e9c786650197646fe1 Mon Sep 17 00:00:00 2001 From: Rahul Arvind Date: Tue, 6 Feb 2024 16:56:37 +0800 Subject: [PATCH 136/200] Test old test_qcnn --- tests/test_models_qcnn.py | 261 +++++++++++++------------------------- 1 file changed, 89 insertions(+), 172 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 34f92da826..7db8b56d78 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -3,7 +3,8 @@ import numpy as np import pytest -from qibo import gates, get_backend +import qibo +from qibo import gates from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN @@ -11,7 +12,7 @@ angles0 = [i * math.pi / num_angles for i in range(num_angles)] -def test_classifier_circuit2(backend): +def test_classifier_circuit2(): """ """ nqubits = 2 nlayers = int(nqubits / 2) @@ -28,14 +29,14 @@ def test_classifier_circuit2(backend): # circuit = qcnn._circuit statevector = circuit(init_state).state() - real_vector = get_real_vector2(backend) + real_vector = get_real_vector2() # to compare statevector and real_vector np.testing.assert_allclose(statevector.real, real_vector.real, atol=1e-5) np.testing.assert_allclose(statevector.imag, real_vector.imag, atol=1e-5) -def get_real_vector2(backend): +def get_real_vector2(): nqubits = 2 bits = range(nqubits) init_state = np.ones(2**nqubits) / np.sqrt(2**nqubits) # @@ -44,40 +45,29 @@ def get_real_vector2(backend): # convolution k = 0 a = np.dot( - one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), - init_state, + one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), init_state ) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[0], bits[1], angles[k]).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[0], bits[1], angles[k]).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[0], bits[1], angles[k], backend).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[0], bits[1], angles[k]).unitary(), a) k += 1 - a = np.dot( - one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) k += 3 # pooling ksink = k - a = np.dot( - one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) k += 3 + a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[0], bits[1]).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a - ) - a = np.dot(CNOT_unitary(nqubits, bits[0], bits[1], backend).unitary(), a) - a = np.dot( - one_qubit_unitary(nqubits, bits[1], angles[ksink : ksink + 3], backend) + one_qubit_unitary(nqubits, bits[1], angles[ksink : ksink + 3]) .invert() .unitary(), a, @@ -86,7 +76,7 @@ def get_real_vector2(backend): return a -def test_classifier_circuit4(backend): +def test_classifier_circuit4(): """ """ nqubits = 4 nlayers = int(nqubits / 2) @@ -97,14 +87,14 @@ def test_classifier_circuit4(backend): circuit = qcnn.Classifier_circuit(angles) statevector = circuit(init_state).state() - real_vector = get_real_vector4(backend) + real_vector = get_real_vector4() # to compare statevector and real_vector np.testing.assert_allclose(statevector.real, real_vector.real, atol=1e-5) np.testing.assert_allclose(statevector.imag, real_vector.imag, atol=1e-5) -def get_real_vector4(backend): +def get_real_vector4(): nqubits = 4 init_state = np.ones(2**nqubits) / np.sqrt(2**nqubits) # angles = angles0 @@ -116,140 +106,81 @@ def get_real_vector4(backend): b1 = 1 k = 0 a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), - init_state, + one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), init_state ) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) b0 = 2 b1 = 3 k = 0 - a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) b0 = 1 b1 = 2 k = 0 - a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) b0 = 3 b1 = 0 k = 0 - a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RZZ_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RYY_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RYY_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - RXX_unitary(nqubits, bits[b0], bits[b1], angles[k], backend).unitary(), a - ) + a = np.dot(RXX_unitary(nqubits, bits[b0], bits[b1], angles[k]).unitary(), a) k += 1 - a = np.dot( - one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b0], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[b1], angles[k : k + 3]).unitary(), a) # pooling - layer 1 k = 15 # k+=3 ksink = k - a = np.dot( - one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) k += 3 + a = np.dot(one_qubit_unitary(nqubits, bits[0], angles[k : k + 3]).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[0], bits[2]).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[0], angles[k : k + 3], backend).unitary(), a - ) - a = np.dot(CNOT_unitary(nqubits, bits[0], bits[2], backend).unitary(), a) - a = np.dot( - one_qubit_unitary(nqubits, bits[2], angles[ksink : ksink + 3], backend) + one_qubit_unitary(nqubits, bits[2], angles[ksink : ksink + 3]) .invert() .unitary(), a, @@ -257,16 +188,12 @@ def get_real_vector4(backend): k = 15 # k+=3 ksink = k - a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) k += 3 + a = np.dot(one_qubit_unitary(nqubits, bits[1], angles[k : k + 3]).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[1], bits[3]).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[1], angles[k : k + 3], backend).unitary(), a - ) - a = np.dot(CNOT_unitary(nqubits, bits[1], bits[3], backend).unitary(), a) - a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3], backend) + one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3]) .invert() .unitary(), a, @@ -274,41 +201,29 @@ def get_real_vector4(backend): # convolution - layer 2 k = 0 - a = np.dot( - one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot(RZZ_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) + a = np.dot(RZZ_unitary(nqubits, bits[2], bits[3], angles[k]).unitary(), a) k += 1 - a = np.dot(RYY_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) + a = np.dot(RYY_unitary(nqubits, bits[2], bits[3], angles[k]).unitary(), a) k += 1 - a = np.dot(RXX_unitary(nqubits, bits[2], bits[3], angles[k], backend).unitary(), a) + a = np.dot(RXX_unitary(nqubits, bits[2], bits[3], angles[k]).unitary(), a) k += 1 - a = np.dot( - one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) k += 3 - a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) k += 3 # pooling - layer 2 ksink = k - a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[k : k + 3], backend).unitary(), a - ) + a = np.dot(one_qubit_unitary(nqubits, bits[3], angles[k : k + 3]).unitary(), a) k += 3 + a = np.dot(one_qubit_unitary(nqubits, bits[2], angles[k : k + 3]).unitary(), a) + a = np.dot(CNOT_unitary(nqubits, bits[2], bits[3]).unitary(), a) a = np.dot( - one_qubit_unitary(nqubits, bits[2], angles[k : k + 3], backend).unitary(), a - ) - a = np.dot(CNOT_unitary(nqubits, bits[2], bits[3], backend).unitary(), a) - a = np.dot( - one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3], backend) + one_qubit_unitary(nqubits, bits[3], angles[ksink : ksink + 3]) .invert() .unitary(), a, @@ -317,7 +232,7 @@ def get_real_vector4(backend): return a -def one_qubit_unitary(nqubits, bit, symbols, backend): +def one_qubit_unitary(nqubits, bit, symbols): c = Circuit(nqubits) c.add(gates.RX(bit, symbols[0])) c.add(gates.RY(bit, symbols[1])) @@ -326,51 +241,42 @@ def one_qubit_unitary(nqubits, bit, symbols, backend): return c -def RXX_unitary(nqubits, bit0, bit1, angle, backend): +def RXX_unitary(nqubits, bit0, bit1, angle): c = Circuit(nqubits) c.add(gates.RXX(bit0, bit1, angle)) return c -def RYY_unitary(nqubits, bit0, bit1, angle, backend): +def RYY_unitary(nqubits, bit0, bit1, angle): c = Circuit(nqubits) c.add(gates.RYY(bit0, bit1, angle)) return c -def RZZ_unitary(nqubits, bit0, bit1, angle, backend): +def RZZ_unitary(nqubits, bit0, bit1, angle): c = Circuit(nqubits) c.add(gates.RZZ(bit0, bit1, angle)) return c -def CNOT_unitary(nqubits, bit0, bit1, backend): +def CNOT_unitary(nqubits, bit0, bit1): c = Circuit(nqubits) c.add(gates.CNOT(bit0, bit1)) return c -def test_1_qubit_classifier_circuit_error(backend): +def test_1_qubit_classifier_circuit_error(): try: QuantumCNN(nqubits=1, nlayers=1, nclasses=2) except: pass -def test_two_qubit_ansatz(backend): - c = Circuit(2) - c.add(gates.H(0)) - c.add(gates.RX(0, 0)) - c.add(gates.CNOT(1, 0)) - test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) - -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) - -def test_qcnn_training(backend): +def test_qcnn_training(): import random # generate 2 random states and labels for pytest @@ -387,21 +293,32 @@ def test_qcnn_training(backend): test_qcnn = QuantumCNN(nqubits=4, nlayers=1, nclasses=2, params=init_theta) testcircuit = test_qcnn._circuit result = test_qcnn.minimize( - init_theta, data=data, labels=labels, nshots=1000, method="Powell" + init_theta, data=data, labels=labels, nshots=10000, method="Powell" ) # test Predictions function predictions = [] for n in range(len(data)): - predictions.append(test_qcnn.predict(data[n], nshots=1000)[0]) + predictions.append(test_qcnn.predict(data[n], nshots=10000)[0]) # test Accuracy function predictions.append(1) labels = np.array([[1], [-1], [1]]) + test_qcnn.Accuracy(labels, predictions) + + +def test_two_qubit_ansatz(): + c = Circuit(2) + c.add(gates.H(0)) + c.add(gates.RX(0, 0)) + c.add(gates.CNOT(1, 0)) + test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) + -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) +def test_two_qubit_ansatz_training(): + # test qibojit case (copy initial state as quick-fix for in-place update) + qibo.set_backend("qibojit") -def test_two_qubit_ansatz_training(backend): c = Circuit(2) c.add(gates.H(0)) c.add(gates.RX(0, 0)) @@ -431,4 +348,4 @@ def test_two_qubit_ansatz_training(backend): # test Accuracy function predictions.append(1) labels = np.array([[1], [-1], [1]]) - test_qcnn.Accuracy(labels, predictions) + test_qcnn.Accuracy(labels, predictions) \ No newline at end of file From cdabfea1e10e1d29605967868beeefaa442d08d5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 08:58:53 +0000 Subject: [PATCH 137/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_models_qcnn.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index bc99f09d62..dcce3c3697 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -283,8 +283,8 @@ def test_two_qubit_ansatz(backend): c.add(gates.CNOT(1, 0)) test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) +@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) def test_qcnn_training(backend): import random @@ -325,7 +325,6 @@ def test_two_qubit_ansatz(): @pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) - def test_two_qubit_ansatz_training(backend): c = Circuit(2) c.add(gates.H(0)) @@ -356,4 +355,4 @@ def test_two_qubit_ansatz_training(backend): # test Accuracy function predictions.append(1) labels = np.array([[1], [-1], [1]]) - test_qcnn.Accuracy(labels, predictions) \ No newline at end of file + test_qcnn.Accuracy(labels, predictions) From 92a8183084ce2e8879dc500d15c3cb6cbd2bf9f3 Mon Sep 17 00:00:00 2001 From: Rahul Arvind Date: Tue, 6 Feb 2024 17:10:01 +0800 Subject: [PATCH 138/200] even older testing --- tests/test_models_qcnn.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index bc99f09d62..7db8b56d78 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -276,16 +276,7 @@ def test_1_qubit_classifier_circuit_error(): pass -def test_two_qubit_ansatz(backend): - c = Circuit(2) - c.add(gates.H(0)) - c.add(gates.RX(0, 0)) - c.add(gates.CNOT(1, 0)) - test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) - -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) - -def test_qcnn_training(backend): +def test_qcnn_training(): import random # generate 2 random states and labels for pytest @@ -324,9 +315,10 @@ def test_two_qubit_ansatz(): test_qcnn = QuantumCNN(4, 2, 2, twoqubitansatz=c) -@pytest.mark.parametrize("backend", [("numpy"), ("qibojit")]) +def test_two_qubit_ansatz_training(): + # test qibojit case (copy initial state as quick-fix for in-place update) + qibo.set_backend("qibojit") -def test_two_qubit_ansatz_training(backend): c = Circuit(2) c.add(gates.H(0)) c.add(gates.RX(0, 0)) From bdc9571cfc1bfe1a0c0eb30d6acb5ab69a5515db Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 14:20:15 +0400 Subject: [PATCH 139/200] remove `no cover` and add test --- src/qibo/backends/__init__.py | 2 +- tests/test_global_backend.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 04f26d870b..db25cf04c1 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -169,7 +169,7 @@ def set_threads(nthreads): GlobalBackend().set_threads(nthreads) -def _check_backend(backend): # pragma: no cover +def _check_backend(backend): if backend is None: return GlobalBackend() diff --git a/tests/test_global_backend.py b/tests/test_global_backend.py index 27386ed812..9ad3a4b2f4 100644 --- a/tests/test_global_backend.py +++ b/tests/test_global_backend.py @@ -91,3 +91,20 @@ def test_gate_matrix(): qibo.set_backend("numpy") gate = qibo.gates.H(0) matrix = gate.matrix + + +def test_check_backend(backend): + # testing when backend is not None + test = qibo.backends._check_backend(backend) + + assert test.name == backend.name + assert test.__class__ == backend.__class__ + + # testing when backend is None + test = None + test = qibo.backends._check_backend(test) + + target = qibo.backends.GlobalBackend() + + assert test.name == target.name + assert test.__class__ == target.__class__ From 65914fae1e35302b8e2a33e4a5d0b29c6bf05842 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 11:50:32 +0000 Subject: [PATCH 140/200] Update src/qibo/quantum_info/quantum_networks.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- src/qibo/quantum_info/quantum_networks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 7dd0a7735b..7e2068a77d 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -442,7 +442,7 @@ def __mul__(self, number: Union[float, int]): If the quantum network is pure and ``number > 0.0``, the method returns a pure quantum network with its Choi operator multiplied by the square root of ``number``. - This is equivelant to multiplying `self.to_full()` by the ``number``. + This is equivalent to multiplying `self.to_full()` by the ``number``. Otherwise, this method will return a full quantum network. Args: From 3abdec788d88604ca7dcb5be1e5bb50c6bb3639f Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 11:50:38 +0000 Subject: [PATCH 141/200] Update src/qibo/quantum_info/quantum_networks.py Co-authored-by: Alejandro Sopena <44305203+AlejandroSopena@users.noreply.github.com> --- src/qibo/quantum_info/quantum_networks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 7e2068a77d..91ba7bce2a 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -486,7 +486,7 @@ def __truediv__(self, number: Union[float, int]): If the quantum network is pure and ``number > 0.0``, the method returns a pure quantum network with its Choi operator divided by the square root of ``number``. - This is equivelant to dividing `self.to_full()` by the ``number``. + This is equivalent to dividing `self.to_full()` by the ``number``. Otherwise, this method will return a full quantum network. Args: From 9c197dd130f958c8079b1ca63ce81f81c197afe0 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 6 Feb 2024 17:59:44 +0400 Subject: [PATCH 142/200] fic docstring --- src/qibo/gates/gates.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/gates/gates.py b/src/qibo/gates/gates.py index 128518a89e..c0879b10d2 100644 --- a/src/qibo/gates/gates.py +++ b/src/qibo/gates/gates.py @@ -1508,7 +1508,7 @@ def qasm_label(self): class SiSWAP(Gate): - """The :math:`\\sqrt{\\text{iSWAP}}}` gate. + """The :math:`\\sqrt{\\text{iSWAP}}` gate. Corresponds to the following unitary matrix @@ -1538,7 +1538,7 @@ def _dagger(self) -> "Gate": class SiSWAPDG(Gate): - """The :math:`\\sqrt{\\text{iSWAP}}}^{\\dagger}` gate. + """The :math:`\\left(\\sqrt{\\text{iSWAP}}\\right)^{\\dagger}` gate. Corresponds to the following unitary matrix From d9a3baa953263d7008a932851f6006b9fa17ad55 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 6 Feb 2024 23:58:26 +0800 Subject: [PATCH 143/200] Update src/qibo/models/qcnn.py Co-authored-by: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> --- src/qibo/models/qcnn.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 640904e6ee..1f64e967ef 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -60,12 +60,7 @@ def __init__( self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if ( - ("qibojit" in get_backend()) - or ("qibojit-numba" in get_backend()) - or ("qibojit-cuquantum" in get_backend()) - or ("qibojit-cupy" in get_backend()) - ): + if "qibojit" in get_backend(): self.copy_init_state = True else: self.copy_init_state = False From 60964247f6b61ea382802e32e12bcd3bc8bb5cd7 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 6 Feb 2024 23:58:37 +0800 Subject: [PATCH 144/200] Update src/qibo/models/qcnn.py Co-authored-by: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> --- src/qibo/models/qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 1f64e967ef..8e8fe5227a 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -183,7 +183,7 @@ def two_qubit_unitary(self, bits, symbols): Circuit containing the unitaries added to the specified qubits. """ - if self.twoqubitansatz == None: + if self.twoqubitansatz is None: c = Circuit(self.nqubits) c += self.one_qubit_unitary(bits[0], symbols[0:3]) c += self.one_qubit_unitary(bits[1], symbols[3:6]) From 643752c13a0b81cba41d170087c5355690275880 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 6 Feb 2024 23:58:45 +0800 Subject: [PATCH 145/200] Update src/qibo/models/qcnn.py Co-authored-by: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> --- src/qibo/models/qcnn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 8e8fe5227a..f56ed804cf 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -279,7 +279,7 @@ def Predictions(self, circuit, theta, init_state, nshots=10000): numpy.array() with predictions for each qubit, for the initial state. """ bias = np.array(theta[0 : self.measured_qubits]) - if self.copy_init_state is True: + if self.copy_init_state: init_state_copy = init_state.copy() else: init_state_copy = init_state From 894f6d9c0eef7e4ae474285564780ff39b5b3e8e Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 6 Feb 2024 23:58:51 +0800 Subject: [PATCH 146/200] Update tests/test_models_qcnn.py Co-authored-by: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> --- tests/test_models_qcnn.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 7e9168b007..ab8d98e2b3 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -1,7 +1,6 @@ import math import numpy as np -import pytest import qibo from qibo import gates From 8b6ca7794ba6efeaa18ba27d7086ad004c0a7275 Mon Sep 17 00:00:00 2001 From: Canoming Date: Wed, 7 Feb 2024 00:06:25 +0800 Subject: [PATCH 147/200] correct the behavior of applying a quantum comb to a quantum channel --- src/qibo/quantum_info/quantum_networks.py | 50 +++++++++++++++------ tests/test_quantum_info_quantum_networks.py | 28 ++++++------ 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 91ba7bce2a..a688800258 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -337,8 +337,8 @@ def link_product(self, second_network, subscripts: str = "ij,jk -> ik"): inv_subscripts = pattern_two and subscripts[0] == subscripts[4] super_subscripts = ( pattern_four - and subscripts[2] == subscripts[5] - and subscripts[3] == subscripts[6] + and subscripts[1] == subscripts[5] + and subscripts[2] == subscripts[6] ) if not channel_subscripts and not inv_subscripts and not super_subscripts: @@ -351,10 +351,10 @@ def link_product(self, second_network, subscripts: str = "ij,jk -> ik"): second_matrix = second_network._full() # pylint: disable=W0212 if super_subscripts: - cexpr = "jklmnopq,nopqrstu->jklmrstu" + cexpr = "jklmnopq,klop->jmnq" return QuantumNetwork( np.einsum(cexpr, first_matrix, second_matrix), - self.partition[:2] + second_network.partition[2:], + [self.partition[0] + self.partition[-1]], ) cexpr = "jkab,klbc->jlac" @@ -532,17 +532,39 @@ def __matmul__(self, second_network): + "``QuantumNetwork`` by a non-``QuantumNetwork``.", ) - if self.partition != second_network.partition: - raise_error( - ValueError, - "partitions of the networks do not match: " - + f"{self.partition} != {second_network.partition}.", - ) + if len(self.partition) == 2: # `self` is a channel + if len(second_network.partition) != 2: + raise_error( + ValueError, + f"`QuantumNetwork {second_network} is assumed to be a channel, but it is not. " + + "Use `link_product` method to specify the subscript.", + ) + if self.partition[1] != second_network.partition[0]: + raise_error( + ValueError, + "partitions of the networks do not match: " + + f"{self.partition[1]} != {second_network.partition[0]}.", + ) - if len(self.partition) == 2: subscripts = "jk,kl -> jl" - elif len(self.partition) == 4: - subscripts = "jklm,lmno -> jkno" + + + elif len(self.partition) == 4: # `self` is a super-channel + if len(second_network.partition) != 2: + raise_error( + ValueError, + f"`QuantumNetwork {second_network} is assumed to be a channel, but it is not. " + + "Use `link_product` method to specify the subscript.", + ) + if self.partition[1] != second_network.partition[0]: + raise_error( + ValueError, + "Systems of the channel do not match the super-channel: " + + f"{self.partition[1], self.partition[2]} != " + + f"{second_network.partition[0],second_network.partition[1]}.", + ) + + subscripts = "jklm,kl -> jm" else: raise_error( NotImplementedError, @@ -652,7 +674,7 @@ def _check_subscript_pattern(self, subscripts: str): """Checks if input subscript match any implemented pattern.""" braket = "[a-z]" pattern_two = re.compile(braket * 2 + "," + braket * 2 + "->" + braket * 2) - pattern_four = re.compile(braket * 4 + "," + braket * 4 + "->" + braket * 4) + pattern_four = re.compile(braket * 4 + "," + braket * 2 + "->" + braket * 2) return bool(re.match(pattern_two, subscripts)), bool( re.match(pattern_four, subscripts) diff --git a/tests/test_quantum_info_quantum_networks.py b/tests/test_quantum_info_quantum_networks.py index e02537eae1..b9d3b214ed 100644 --- a/tests/test_quantum_info_quantum_networks.py +++ b/tests/test_quantum_info_quantum_networks.py @@ -223,25 +223,25 @@ def test_with_unitaries(backend, subscript): def test_with_comb(backend): - subscript = "jklm,lmno->jkno" - partition = (2,) * 4 - sys_out = (False, True) * 2 + subscript = "jklm,kl->jm" + comb_partition = (2,) * 4 + channel_partition = (2,) * 2 + comb_sys_out = (False, True) * 2 + channel_sys_out = (False, True) * 2 comb = random_density_matrix(2**4, backend=backend) - comb_2 = random_density_matrix(2**4, backend=backend) + channel = random_density_matrix(2**2, backend=backend) - comb_choi = QuantumNetwork(comb, partition, system_output=sys_out, backend=backend) - comb_choi_2 = QuantumNetwork( - comb_2, partition, system_output=sys_out, backend=backend - ) - comb_choi_3 = QuantumNetwork( - comb @ comb_2, partition, system_output=sys_out, backend=backend - ).to_full(backend) + comb_choi = QuantumNetwork(comb, comb_partition, system_output=comb_sys_out, backend=backend) + channel_choi = QuantumNetwork(channel, channel_partition, system_output=channel_sys_out, backend=backend) + # channel_choi_2 = QuantumNetwork( + # comb @ channel, comb_partition, system_output=comb_sys_out, backend=backend + # ).to_full(backend) - test = comb_choi.link_product(comb_choi_2, subscript).to_full(backend) + test = comb_choi.link_product(channel_choi, subscript).to_full(backend) - backend.assert_allclose(test, comb_choi_3, atol=1e-5) - backend.assert_allclose(test, (comb_choi @ comb_choi_2).to_full(backend), atol=1e-5) + # backend.assert_allclose(test, comb_choi_3, atol=1e-5) + # backend.assert_allclose(test, (comb_choi @ comb_choi_2).to_full(backend), atol=1e-5) def test_apply(backend): From 2869d3ed6a08c335e0410d1b85100f8beb52bef1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:09:52 +0000 Subject: [PATCH 148/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/quantum_networks.py | 5 ++--- tests/test_quantum_info_quantum_networks.py | 8 ++++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index a688800258..8992169ae5 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -532,7 +532,7 @@ def __matmul__(self, second_network): + "``QuantumNetwork`` by a non-``QuantumNetwork``.", ) - if len(self.partition) == 2: # `self` is a channel + if len(self.partition) == 2: # `self` is a channel if len(second_network.partition) != 2: raise_error( ValueError, @@ -548,8 +548,7 @@ def __matmul__(self, second_network): subscripts = "jk,kl -> jl" - - elif len(self.partition) == 4: # `self` is a super-channel + elif len(self.partition) == 4: # `self` is a super-channel if len(second_network.partition) != 2: raise_error( ValueError, diff --git a/tests/test_quantum_info_quantum_networks.py b/tests/test_quantum_info_quantum_networks.py index b9d3b214ed..18f377eabb 100644 --- a/tests/test_quantum_info_quantum_networks.py +++ b/tests/test_quantum_info_quantum_networks.py @@ -232,8 +232,12 @@ def test_with_comb(backend): comb = random_density_matrix(2**4, backend=backend) channel = random_density_matrix(2**2, backend=backend) - comb_choi = QuantumNetwork(comb, comb_partition, system_output=comb_sys_out, backend=backend) - channel_choi = QuantumNetwork(channel, channel_partition, system_output=channel_sys_out, backend=backend) + comb_choi = QuantumNetwork( + comb, comb_partition, system_output=comb_sys_out, backend=backend + ) + channel_choi = QuantumNetwork( + channel, channel_partition, system_output=channel_sys_out, backend=backend + ) # channel_choi_2 = QuantumNetwork( # comb @ channel, comb_partition, system_output=comb_sys_out, backend=backend # ).to_full(backend) From e6c9809b9662009f2af2fc7ddf0c10ecbae32102 Mon Sep 17 00:00:00 2001 From: Canoming Date: Wed, 7 Feb 2024 14:25:05 +0800 Subject: [PATCH 149/200] update test for combs --- tests/test_quantum_info_quantum_networks.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/test_quantum_info_quantum_networks.py b/tests/test_quantum_info_quantum_networks.py index 18f377eabb..9345ee3ede 100644 --- a/tests/test_quantum_info_quantum_networks.py +++ b/tests/test_quantum_info_quantum_networks.py @@ -88,7 +88,7 @@ def test_errors(backend): with pytest.raises(NotImplementedError): net @ net - with pytest.raises(ValueError): + with pytest.raises(NotImplementedError): net @ network with pytest.raises(ValueError): @@ -227,7 +227,7 @@ def test_with_comb(backend): comb_partition = (2,) * 4 channel_partition = (2,) * 2 comb_sys_out = (False, True) * 2 - channel_sys_out = (False, True) * 2 + channel_sys_out = (False, True) comb = random_density_matrix(2**4, backend=backend) channel = random_density_matrix(2**2, backend=backend) @@ -238,14 +238,11 @@ def test_with_comb(backend): channel_choi = QuantumNetwork( channel, channel_partition, system_output=channel_sys_out, backend=backend ) - # channel_choi_2 = QuantumNetwork( - # comb @ channel, comb_partition, system_output=comb_sys_out, backend=backend - # ).to_full(backend) test = comb_choi.link_product(channel_choi, subscript).to_full(backend) + channel_choi2 = comb_choi @ channel_choi - # backend.assert_allclose(test, comb_choi_3, atol=1e-5) - # backend.assert_allclose(test, (comb_choi @ comb_choi_2).to_full(backend), atol=1e-5) + backend.assert_allclose(test, channel_choi2.to_full(backend), atol=1e-5) def test_apply(backend): From 7df827562d9d9a5f69cb4e3123faa28a493e5fb3 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 7 Feb 2024 10:32:39 +0400 Subject: [PATCH 150/200] use backend helper function --- src/qibo/quantum_info/entanglement.py | 21 ++++++---------- src/qibo/quantum_info/entropies.py | 35 +++++++++------------------ 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/src/qibo/quantum_info/entanglement.py b/src/qibo/quantum_info/entanglement.py index 7f009e367a..28cbb70305 100644 --- a/src/qibo/quantum_info/entanglement.py +++ b/src/qibo/quantum_info/entanglement.py @@ -2,7 +2,7 @@ import numpy as np -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import PRECISION_TOL, raise_error from qibo.quantum_info.metrics import fidelity, purity @@ -29,8 +29,7 @@ def concurrence(state, bipartition, check_purity: bool = True, backend=None): Returns: float: Concurrence of :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) not in [1, 2]) @@ -107,11 +106,10 @@ def entanglement_of_formation( Returns: float: entanglement of formation of state :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - from qibo.quantum_info.entropies import shannon_entropy # pylint: disable=C0415 + backend = _check_backend(backend) + concur = concurrence( state, bipartition=bipartition, check_purity=check_purity, backend=backend ) @@ -155,9 +153,6 @@ def entanglement_fidelity( Returns: float: Entanglement fidelity :math:`F_{\\mathcal{E}}`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() - if not isinstance(nqubits, int): raise_error( TypeError, f"nqubits must be type int, but it is type {type(nqubits)}." @@ -184,6 +179,8 @@ def entanglement_fidelity( f"check_hermitian must be type bool, but it is type {type(check_hermitian)}.", ) + backend = _check_backend(backend) + if state is None: state = backend.plus_density_matrix(nqubits) @@ -218,8 +215,7 @@ def meyer_wallach_entanglement(circuit, backend=None): float: Meyer-Wallach entanglement. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) circuit.density_matrix = True nqubits = circuit.nqubits @@ -279,8 +275,7 @@ def entangling_capability(circuit, samples: int, seed=None, backend=None): TypeError, "seed must be either type int or numpy.random.Generator." ) - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) local_state = ( np.random.default_rng(seed) if seed is None or isinstance(seed, int) else seed diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 0108bcddbc..4161273082 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -5,7 +5,7 @@ import numpy as np from scipy.linalg import fractional_matrix_power -from qibo.backends import GlobalBackend +from qibo.backends import _check_backend from qibo.config import PRECISION_TOL, raise_error from qibo.quantum_info.metrics import _check_hermitian_or_not_gpu, purity @@ -30,8 +30,7 @@ def shannon_entropy(prob_dist, base: float = 2, backend=None): Returns: (float): Shannon entropy :math:`H(\\mathcal{p})`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(prob_dist, list): # np.float64 is necessary instead of native float because of tensorflow @@ -98,8 +97,7 @@ def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backen Returns: float: Classical relative entropy between :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(prob_dist_p, list): # np.float64 is necessary instead of native float because of tensorflow @@ -190,8 +188,7 @@ def classical_renyi_entropy( Returns: float: Classical Rényi entropy :math:`H_{\\alpha}`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(prob_dist, list): # np.float64 is necessary instead of native float because of tensorflow @@ -279,8 +276,7 @@ def classical_relative_renyi_entropy( Returns: float: Classical relative Rényi entropy :math:`H_{\\alpha}(\\mathbf{p} \\, \\| \\, \\mathbf{q})`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(prob_dist_p, list): # np.float64 is necessary instead of native float because of tensorflow @@ -361,8 +357,7 @@ def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend= Returns: float: Classical Tsallis entropy :math:`S_{\\alpha}(\\mathbf{p})`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if isinstance(prob_dist, list): # np.float64 is necessary instead of native float because of tensorflow @@ -433,8 +428,7 @@ def von_neumann_entropy( Returns: float: The von-Neumann entropy :math:`S` of ``state`` :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) >= 3) @@ -513,8 +507,7 @@ def relative_von_neumann_entropy( Returns: float: Relative (von-Neumann) entropy :math:`S(\\rho \\, \\| \\, \\sigma)`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) >= 3) @@ -629,8 +622,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None Returns: float: Rényi entropy :math:`H_{\\alpha}`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) >= 3) @@ -714,8 +706,7 @@ def relative_renyi_entropy( Returns: float: Relative Rényi entropy :math:`H_{\\alpha}(\\rho \\, \\| \\, \\sigma)`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) >= 3) @@ -806,8 +797,7 @@ def tsallis_entropy(state, alpha: float, base: float = 2, backend=None): Returns: float: Tsallis entropy :math:`S_{\\alpha}(\\rho)`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if ( (len(state.shape) >= 3) @@ -871,8 +861,7 @@ def entanglement_entropy( Returns: float: Entanglement entropy :math:`S` of ``state`` :math:`\\rho`. """ - if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _check_backend(backend) if base <= 0.0: raise_error(ValueError, "log base must be non-negative.") From 2b63c804d03e6b08a84ad45c446beb351c659545 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 7 Feb 2024 10:39:23 +0400 Subject: [PATCH 151/200] reduce complexity --- src/qibo/quantum_info/entropies.py | 59 ++++++------------------------ 1 file changed, 11 insertions(+), 48 deletions(-) diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 4161273082..716bdda3fd 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -57,14 +57,7 @@ def shannon_entropy(prob_dist, base: float = 2, backend=None): if np.abs(np.sum(prob_dist) - 1.0) > PRECISION_TOL: raise_error(ValueError, "Probability array must sum to 1.") - if base == 2: - log_prob = np.where(prob_dist != 0.0, np.log2(prob_dist), 0.0) - elif base == 10: - log_prob = np.where(prob_dist != 0, np.log10(prob_dist), 0.0) - elif base == np.e: - log_prob = np.where(prob_dist != 0, np.log(prob_dist), 0.0) - else: - log_prob = np.where(prob_dist != 0, np.log(prob_dist) / np.log(base), 0.0) + log_prob = np.where(prob_dist != 0, np.log2(prob_dist) / np.log2(base), 0.0) shan_entropy = -np.sum(prob_dist * log_prob) @@ -134,16 +127,9 @@ def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backen entropy_p = -1 * shannon_entropy(prob_dist_p, base=base, backend=backend) - if base == 2: - log_prob_q = np.where(prob_dist_q != 0.0, np.log2(prob_dist_q), -np.inf) - elif base == 10: - log_prob_q = np.where(prob_dist_q != 0.0, np.log10(prob_dist_q), -np.inf) - elif base == np.e: - log_prob_q = np.where(prob_dist_q != 0.0, np.log(prob_dist_q), -np.inf) - else: - log_prob_q = np.where( - prob_dist_q != 0.0, np.log(prob_dist_q) / np.log(base), -np.inf - ) + log_prob_q = np.where( + prob_dist_q != 0.0, np.log2(prob_dist_q) / np.log2(base), -np.inf + ) log_prob = np.where(prob_dist_p != 0.0, log_prob_q, 0.0) @@ -460,14 +446,7 @@ def von_neumann_entropy( else: eigenvalues = np.linalg.eigvals(state) - if base == 2: - log_prob = np.where(eigenvalues > 0, np.log2(eigenvalues), 0.0) - elif base == 10: - log_prob = np.where(eigenvalues > 0, np.log10(eigenvalues), 0.0) - elif base == np.e: - log_prob = np.where(eigenvalues > 0, np.log(eigenvalues), 0.0) - else: - log_prob = np.where(eigenvalues > 0, np.log(eigenvalues) / np.log(base), 0.0) + log_prob = np.where(eigenvalues > 0, np.log2(eigenvalues) / np.log2(base), 0.0) ent = -np.sum(eigenvalues * log_prob) # absolute value if entropy == 0.0 to avoid returning -0.0 @@ -557,28 +536,12 @@ def relative_von_neumann_entropy( else: eigenvalues_target = np.linalg.eigvals(target) - if base == 2: - log_state = np.where(eigenvalues_state > 0, np.log2(eigenvalues_state), 0.0) - log_target = np.where( - eigenvalues_target > 0, np.log2(eigenvalues_target), -np.inf - ) - elif base == 10: - log_state = np.where(eigenvalues_state > 0, np.log10(eigenvalues_state), 0.0) - log_target = np.where( - eigenvalues_target > 0, np.log10(eigenvalues_target), -np.inf - ) - elif base == np.e: - log_state = np.where(eigenvalues_state > 0, np.log(eigenvalues_state), 0.0) - log_target = np.where( - eigenvalues_target > 0, np.log(eigenvalues_target), -np.inf - ) - else: - log_state = np.where( - eigenvalues_state > 0, np.log(eigenvalues_state) / np.log(base), 0.0 - ) - log_target = np.where( - eigenvalues_target > 0, np.log(eigenvalues_target) / np.log(base), -np.inf - ) + log_state = np.where( + eigenvalues_state > 0, np.log2(eigenvalues_state) / np.log2(base), 0.0 + ) + log_target = np.where( + eigenvalues_target > 0, np.log2(eigenvalues_target) / np.log2(base), -np.inf + ) log_target = np.where(eigenvalues_state != 0.0, log_target, 0.0) From a876281e39a27b316af9ca98caa2d4b98bbc2db5 Mon Sep 17 00:00:00 2001 From: Canoming Date: Wed, 7 Feb 2024 15:32:52 +0800 Subject: [PATCH 152/200] add a tutorial for `QuantumNetwork` --- .../tutorials/quantum_networks/README.md | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 doc/source/code-examples/tutorials/quantum_networks/README.md diff --git a/doc/source/code-examples/tutorials/quantum_networks/README.md b/doc/source/code-examples/tutorials/quantum_networks/README.md new file mode 100644 index 0000000000..8b9f1197c4 --- /dev/null +++ b/doc/source/code-examples/tutorials/quantum_networks/README.md @@ -0,0 +1,126 @@ +# Quantum Networks + +## The Quantum Network Model + +The quantum network model is a mathematical framework that allows us to uniquely describe quantum information processing that involves multiple points in time and space. +Each distinguished point in time and space is treated as a linear system $\mathcal{H}_i$. +A quantum network involving $n$ points in time and space is a Hermitian operator $\mathcal{N}$ that acts on the tensor product of the linear systems $\mathcal{H}_0 \otimes \mathcal{H}_1 \otimes \cdots \otimes \mathcal{H}_{n-1}$. +Each system $\mathcal{H}_i$ is either an input or an output of the network. + +A physically implementable quantum network is described by a semi-positive definite operator $\mathcal{N}$ that satisfies the causal constraints. + +A simple example is a quantum channel $\Gamma: \mathcal{H}_0 \to \mathcal{H}_1$, where $\mathcal{H}_0$ is the input system and $\mathcal{H}_1$ is the output system. +The quantum channel is a linear map, such that it maps any input quantum state to an output quantum state, which is a sufficient and necessary condition for the map to be physical. +A Hermitian operator $J^\Gamma$ acting on $\mathcal{H}_0\otimes \mathcal{H}_1$ is associated with a quantum channel $\Gamma$, if $J^\Gamma$ satisfies the following conditions: +$$ +J^\Gamma \geq 0, \quad \text{and} \quad \text{Tr}_{\mathcal{H}_1} J^\Gamma = \mathbb{I}_{\mathcal{H}_0}. +$$ +The first condition is called *complete positivity*, and the second condition is called *trace-preserving*. +In particular, the second condition ensures that the information of the input system is only accessible through the output system. + +In particular, a quantum state $\rho$ may be also considered as a quantum network, where the input system is the trivial system $\mathbb{C}$, and the output system is the quantum system $\mathcal{H}$. +The constraints on the quantum channels are then equivalent to the constraints on the quantum states: +$$ +\rho \geq 0, \quad \text{and} \quad \text{Tr} \rho = \mathbb{I}_\mathbb{C} = 1. +$$ + +> For more details, see G. Chiribella *et al.*, *Theoretical framework for quantum networks*, +> [Physical Review A 80.2 (2009): 022339](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.80.022339). + +## Quantum Network in `qibo` + +The manipulation of quantum networks in `qibo` is done through the `QuantumNetwork` class. + +```python +from qibo.quantum_info.quantum_networks import QuantumNetwork +``` + +A quantum state is a quantum network with a single input system and a single output system, where the input system is the trivial 1-dimensional system. +We need to specify the dimensions of each system in the `partition` argument. + +```python +from qibo.quantum_info import random_density_matrix, random_unitary + +state = random_density_matrix(2) +state_choi = QuantumNetwork(state, (1,2)) +print(f'A quantum state is a quantum netowrk of the form {state_choi}') +``` + +``` +>>> A quantum state is a quantum netowrk of the form J[1 -> 2] +``` + +A general quantum channel can be created in a similar way. + +```python +from qibo.gates import DepolarizingChannel + +test_ch = DepolarizingChannel(0,0.5) +N = len(test_ch.target_qubits) +partition = (2**N, 2**N) + +depolar_choi = QuantumNetwork(test_ch.to_choi(), partition) +print(f'A quantum channel is a quantum netowrk of the form {depolar_choi}') +``` + +``` +>>> A quantum channel is a quantum netowrk of the form J[2 -> 2] +``` + +One may apply a quantum channel to a quantum state, or compose two quantum channels, using the `@` operator. + +```python +new_state = depolar_choi @ depolar_choi @ state_choi +``` + +## Example + +For 3-dimensional systems, an unital channel may not be a mixed unitary channel. + +> Example 4.3 in (Watrous, John. The theory of quantum information. Cambridge university press, 2018.) + +```python +A1 = np.array([ + [0,0,0], + [0,0,1/np.sqrt(2)], + [0,-1/np.sqrt(2),0], +]) +A2 = np.array([ + [0,0,1/np.sqrt(2)], + [0,0,0], + [-1/np.sqrt(2),0,0], +]) +A3 = np.array([ + [0,1/np.sqrt(2),0], + [-1/np.sqrt(2),0,0], + [0,0,0], +]) + +Choi1 = QuantumNetwork(A1, (3,3), pure=True) * 3 +Choi2 = QuantumNetwork(A2, (3,3), pure=True)*3 +Choi3 = QuantumNetwork(A3, (3,3), pure=True)*3 +``` + +The three channels are pure but not unital. Which means they are not unitary. + +```python +print(f"Choi1 is unital: {Choi1.unital()}") +print(f"Choi2 is unital: {Choi2.unital()}") +print(f"Choi3 is unital: {Choi3.unital()}") +``` + +``` +>>> Choi1 is unital: False +Choi2 is unital: False +Choi3 is unital: False +``` + +However, the mixture of the three operators are unital. +As the matrices are orthogonal, they are the extreme points of the convex set of the unital channels. +Therefore, this mixed channel is not a mixed unitary channel. + +```python +Choi = Choi1/3 + Choi2/3 + Choi3/3 +print(f"The mixed channel is unital: {Choi.unital()}") +``` + From ee58ad83b1c8b787c1eb842a4ab0d988ee7e3693 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 07:35:09 +0000 Subject: [PATCH 153/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/source/code-examples/tutorials/quantum_networks/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/code-examples/tutorials/quantum_networks/README.md b/doc/source/code-examples/tutorials/quantum_networks/README.md index 8b9f1197c4..75ca3254f4 100644 --- a/doc/source/code-examples/tutorials/quantum_networks/README.md +++ b/doc/source/code-examples/tutorials/quantum_networks/README.md @@ -123,4 +123,3 @@ Therefore, this mixed channel is not a mixed unitary channel. Choi = Choi1/3 + Choi2/3 + Choi3/3 print(f"The mixed channel is unital: {Choi.unital()}") ``` - From 21c1e1211511307366ca3c179182e3275dcfc3d1 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 7 Feb 2024 12:13:09 +0400 Subject: [PATCH 154/200] cut image sizes by a third --- doc/source/api-reference/qibo.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index c28aee53cf..40d3cc91d8 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -307,8 +307,8 @@ For instance, the following two circuit generations are equivalent: .. image:: ../_static/phase_encoder.png - :width: 2000px - :height: 2329px + :width: 1333px + :height: 1552px :scale: 30 % :align: center @@ -346,8 +346,8 @@ For example, to encode a :math:`8`-dimensional data, one could use the so-called *tree* architechture below: .. image:: ../_static/unary_encoder_tree.png - :width: 2000px - :height: 2329px + :width: 1333px + :height: 1552px :scale: 30 % :align: center @@ -361,8 +361,8 @@ On the other hand, the same encoding could be performed using the so-called *diagonal* (also known as *ladder*) architecture below: .. image:: ../_static/unary_encoder_ladder.png - :width: 2800px - :height: 2329px + :width: 1867px + :height: 1552px :scale: 30 % :align: center From c1cfe94ffc2bd7535905d84c9e050fa562510375 Mon Sep 17 00:00:00 2001 From: Canoming Date: Wed, 7 Feb 2024 19:16:18 +0800 Subject: [PATCH 155/200] fix math rendering in docs --- .../tutorials/quantum_networks/README.md | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/doc/source/code-examples/tutorials/quantum_networks/README.md b/doc/source/code-examples/tutorials/quantum_networks/README.md index 75ca3254f4..26cb7e8752 100644 --- a/doc/source/code-examples/tutorials/quantum_networks/README.md +++ b/doc/source/code-examples/tutorials/quantum_networks/README.md @@ -3,26 +3,27 @@ ## The Quantum Network Model The quantum network model is a mathematical framework that allows us to uniquely describe quantum information processing that involves multiple points in time and space. -Each distinguished point in time and space is treated as a linear system $\mathcal{H}_i$. -A quantum network involving $n$ points in time and space is a Hermitian operator $\mathcal{N}$ that acts on the tensor product of the linear systems $\mathcal{H}_0 \otimes \mathcal{H}_1 \otimes \cdots \otimes \mathcal{H}_{n-1}$. -Each system $\mathcal{H}_i$ is either an input or an output of the network. +Each distinguished point in time and space is treated as a linear system \(\mathcal{H}_ i\). +A quantum network involving $n$ points in time and space is a Hermitian operator \(\mathcal{N}\) that acts on the tensor product of the linear systems \(\mathcal{H}_ 0 \otimes \mathcal{H}_ 1 \otimes \cdots \otimes \mathcal{H}_ {n-1}\). +Each system \(\mathcal{H}_ {i}\) is either an input or an output of the network. -A physically implementable quantum network is described by a semi-positive definite operator $\mathcal{N}$ that satisfies the causal constraints. +A physically implementable quantum network is described by a semi-positive definite operator \(\mathcal{N}\) that satisfies the causal constraints. -A simple example is a quantum channel $\Gamma: \mathcal{H}_0 \to \mathcal{H}_1$, where $\mathcal{H}_0$ is the input system and $\mathcal{H}_1$ is the output system. +A simple example is a quantum channel \(\Gamma: \mathcal{H}_ 0 \to \mathcal{H}_ 1\), where \(\mathcal{H}_ 0\) is the input system and \(\mathcal{H}_ 1\) is the output system. The quantum channel is a linear map, such that it maps any input quantum state to an output quantum state, which is a sufficient and necessary condition for the map to be physical. -A Hermitian operator $J^\Gamma$ acting on $\mathcal{H}_0\otimes \mathcal{H}_1$ is associated with a quantum channel $\Gamma$, if $J^\Gamma$ satisfies the following conditions: -$$ -J^\Gamma \geq 0, \quad \text{and} \quad \text{Tr}_{\mathcal{H}_1} J^\Gamma = \mathbb{I}_{\mathcal{H}_0}. -$$ +A Hermitian operator \(J^\Gamma\) acting on \(\mathcal{H}_ 0\otimes \mathcal{H}_ 1\) is associated with a quantum channel \(\Gamma\), if \(J^\Gamma\) satisfies the following conditions: +\[ +J^\Gamma \geq 0, \quad \text{and} \quad \text{Tr}_ {\mathcal{H}_ 1} J^\Gamma = \mathbb{I}_ {\mathcal{H} _0} \ . +\] + The first condition is called *complete positivity*, and the second condition is called *trace-preserving*. In particular, the second condition ensures that the information of the input system is only accessible through the output system. -In particular, a quantum state $\rho$ may be also considered as a quantum network, where the input system is the trivial system $\mathbb{C}$, and the output system is the quantum system $\mathcal{H}$. +In particular, a quantum state \(\rho\) may be also considered as a quantum network, where the input system is the trivial system \(\mathbb{C}\), and the output system is the quantum system \(\mathcal{H}\). The constraints on the quantum channels are then equivalent to the constraints on the quantum states: -$$ -\rho \geq 0, \quad \text{and} \quad \text{Tr} \rho = \mathbb{I}_\mathbb{C} = 1. -$$ +\[ +\rho \geq 0, \quad \text{and} \quad \text{Tr} \rho = \mathbb{I}_ \mathbb{C} = 1\ . +\] > For more details, see G. Chiribella *et al.*, *Theoretical framework for quantum networks*, > [Physical Review A 80.2 (2009): 022339](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.80.022339). From 48e4aa9b732aef71c5f8d68eb8e8210fa245552d Mon Sep 17 00:00:00 2001 From: Canoming Date: Wed, 7 Feb 2024 19:20:05 +0800 Subject: [PATCH 156/200] fix math rendering in docs --- .../tutorials/quantum_networks/README.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/source/code-examples/tutorials/quantum_networks/README.md b/doc/source/code-examples/tutorials/quantum_networks/README.md index 26cb7e8752..349fc10fa0 100644 --- a/doc/source/code-examples/tutorials/quantum_networks/README.md +++ b/doc/source/code-examples/tutorials/quantum_networks/README.md @@ -3,27 +3,27 @@ ## The Quantum Network Model The quantum network model is a mathematical framework that allows us to uniquely describe quantum information processing that involves multiple points in time and space. -Each distinguished point in time and space is treated as a linear system \(\mathcal{H}_ i\). -A quantum network involving $n$ points in time and space is a Hermitian operator \(\mathcal{N}\) that acts on the tensor product of the linear systems \(\mathcal{H}_ 0 \otimes \mathcal{H}_ 1 \otimes \cdots \otimes \mathcal{H}_ {n-1}\). -Each system \(\mathcal{H}_ {i}\) is either an input or an output of the network. +Each distinguished point in time and space is treated as a linear system $\mathcal{H}_ i$. +A quantum network involving $n$ points in time and space is a Hermitian operator $\mathcal{N}$ that acts on the tensor product of the linear systems $\mathcal{H}_ 0 \otimes \mathcal{H}_ 1 \otimes \cdots \otimes \mathcal{H}_ {n-1}$. +Each system $\mathcal{H}_ {i}$ is either an input or an output of the network. -A physically implementable quantum network is described by a semi-positive definite operator \(\mathcal{N}\) that satisfies the causal constraints. +A physically implementable quantum network is described by a semi-positive definite operator $\mathcal{N}$ that satisfies the causal constraints. -A simple example is a quantum channel \(\Gamma: \mathcal{H}_ 0 \to \mathcal{H}_ 1\), where \(\mathcal{H}_ 0\) is the input system and \(\mathcal{H}_ 1\) is the output system. +A simple example is a quantum channel $\Gamma: \mathcal{H}_ 0 \to \mathcal{H}_ 1$, where $\mathcal{H}_ 0$ is the input system and $\mathcal{H}_ 1$ is the output system. The quantum channel is a linear map, such that it maps any input quantum state to an output quantum state, which is a sufficient and necessary condition for the map to be physical. -A Hermitian operator \(J^\Gamma\) acting on \(\mathcal{H}_ 0\otimes \mathcal{H}_ 1\) is associated with a quantum channel \(\Gamma\), if \(J^\Gamma\) satisfies the following conditions: -\[ +A Hermitian operator $J^\Gamma$ acting on $\mathcal{H}_ 0\otimes \mathcal{H}_ 1$ is associated with a quantum channel $\Gamma$, if $J^\Gamma$ satisfies the following conditions: +$$ J^\Gamma \geq 0, \quad \text{and} \quad \text{Tr}_ {\mathcal{H}_ 1} J^\Gamma = \mathbb{I}_ {\mathcal{H} _0} \ . -\] +$$ The first condition is called *complete positivity*, and the second condition is called *trace-preserving*. In particular, the second condition ensures that the information of the input system is only accessible through the output system. -In particular, a quantum state \(\rho\) may be also considered as a quantum network, where the input system is the trivial system \(\mathbb{C}\), and the output system is the quantum system \(\mathcal{H}\). +In particular, a quantum state $\rho$ may be also considered as a quantum network, where the input system is the trivial system $\mathbb{C}$, and the output system is the quantum system $\mathcal{H}$. The constraints on the quantum channels are then equivalent to the constraints on the quantum states: -\[ +$$ \rho \geq 0, \quad \text{and} \quad \text{Tr} \rho = \mathbb{I}_ \mathbb{C} = 1\ . -\] +$$ > For more details, see G. Chiribella *et al.*, *Theoretical framework for quantum networks*, > [Physical Review A 80.2 (2009): 022339](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.80.022339). From 7d76ecd1dcab28becb3b7905eb882d326e2046da Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 7 Feb 2024 15:26:36 +0400 Subject: [PATCH 157/200] rename qubits based on connectivity and solved minor bugs --- src/qibo/transpiler/blocks.py | 4 ++-- src/qibo/transpiler/router.py | 8 ++++++-- src/qibo/transpiler/unroller.py | 2 +- tests/test_transpiler_pipeline.py | 1 + tests/test_transpiler_router.py | 1 + 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/qibo/transpiler/blocks.py b/src/qibo/transpiler/blocks.py index 199979767e..5b881d9e06 100644 --- a/src/qibo/transpiler/blocks.py +++ b/src/qibo/transpiler/blocks.py @@ -65,8 +65,8 @@ def fuse(self, block, name: Optional[str] = None): (:class:`qibo.transpiler.blocks.Block`): fusion of the two input blocks. """ if not self.qubits == block.qubits: - raise_error( - BlockingError, "In order to fuse two blocks their qubits must coincide." + raise BlockingError( + "In order to fuse two blocks their qubits must coincide." ) return Block(qubits=self.qubits, gates=self.gates + block.gates, name=name) diff --git a/src/qibo/transpiler/router.py b/src/qibo/transpiler/router.py index 8a3bf54180..6023296d8c 100644 --- a/src/qibo/transpiler/router.py +++ b/src/qibo/transpiler/router.py @@ -379,7 +379,9 @@ def __call__(self, circuit: Circuit, initial_layout: dict): else: self._find_new_mapping() - routed_circuit = self.circuit.routed_circuit(circuit_kwargs=circuit.init_kwargs) + circuit_kwargs = circuit.init_kwargs + circuit_kwargs["wire_names"] = list(initial_layout.keys()) + routed_circuit = self.circuit.routed_circuit(circuit_kwargs=circuit_kwargs) if self._final_measurements is not None: routed_circuit = self._append_final_measurements( routed_circuit=routed_circuit @@ -658,7 +660,9 @@ def __call__(self, circuit: Circuit, initial_layout: dict): else: self._find_new_mapping() - routed_circuit = self.circuit.routed_circuit(circuit_kwargs=circuit.init_kwargs) + circuit_kwargs = circuit.init_kwargs + circuit_kwargs["wire_names"] = list(initial_layout.keys()) + routed_circuit = self.circuit.routed_circuit(circuit_kwargs=circuit_kwargs) if self._final_measurements is not None: routed_circuit = self._append_final_measurements( routed_circuit=routed_circuit diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index c62ae4e273..6b8f3e9c60 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -85,7 +85,7 @@ def __call__(self, circuit: Circuit): Returns: (:class:`qibo.models.circuit.Circuit`): equivalent circuit with native gates. """ - translated_circuit = circuit.__class__(circuit.nqubits) + translated_circuit = Circuit(**circuit.init_kwargs) for gate in circuit.queue: translated_circuit.add( translate_gate( diff --git a/tests/test_transpiler_pipeline.py b/tests/test_transpiler_pipeline.py index ce8afee66d..94d2c4b539 100644 --- a/tests/test_transpiler_pipeline.py +++ b/tests/test_transpiler_pipeline.py @@ -237,6 +237,7 @@ def test_custom_passes_restict(gates, placer, routing): final_layout=final_layout, native_gates=NativeGates.default(), ) + assert transpiled_circ.wire_names == ["q1", "q2", "q3"] def test_custom_passes_multiple_placer(): diff --git a/tests/test_transpiler_router.py b/tests/test_transpiler_router.py index 2cf2364fe9..7a7ef17583 100644 --- a/tests/test_transpiler_router.py +++ b/tests/test_transpiler_router.py @@ -348,6 +348,7 @@ def test_restrict_qubits(router_algorithm): ) assert_connectivity(restricted_connectivity, routed_circ) assert_placement(routed_circ, final_layout, connectivity=restricted_connectivity) + assert routed_circ.wire_names == ["q0", "q2", "q3"] def test_star_error_multi_qubit(): From d5f8ab14a2ede5b39e0117b02550ff8fbc138b3d Mon Sep 17 00:00:00 2001 From: Canoming Date: Wed, 7 Feb 2024 19:32:06 +0800 Subject: [PATCH 158/200] fix math rendering in docs --- .../code-examples/tutorials/quantum_networks/README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/doc/source/code-examples/tutorials/quantum_networks/README.md b/doc/source/code-examples/tutorials/quantum_networks/README.md index 349fc10fa0..e0b074640c 100644 --- a/doc/source/code-examples/tutorials/quantum_networks/README.md +++ b/doc/source/code-examples/tutorials/quantum_networks/README.md @@ -12,18 +12,14 @@ A physically implementable quantum network is described by a semi-positive defin A simple example is a quantum channel $\Gamma: \mathcal{H}_ 0 \to \mathcal{H}_ 1$, where $\mathcal{H}_ 0$ is the input system and $\mathcal{H}_ 1$ is the output system. The quantum channel is a linear map, such that it maps any input quantum state to an output quantum state, which is a sufficient and necessary condition for the map to be physical. A Hermitian operator $J^\Gamma$ acting on $\mathcal{H}_ 0\otimes \mathcal{H}_ 1$ is associated with a quantum channel $\Gamma$, if $J^\Gamma$ satisfies the following conditions: -$$ -J^\Gamma \geq 0, \quad \text{and} \quad \text{Tr}_ {\mathcal{H}_ 1} J^\Gamma = \mathbb{I}_ {\mathcal{H} _0} \ . -$$ +$$J^\Gamma \geq 0, \quad \text{and} \quad \text{Tr}_ {\mathcal{H}_ 1} J^\Gamma = \mathbb{I}_ {\mathcal{H} _0} .$$ The first condition is called *complete positivity*, and the second condition is called *trace-preserving*. In particular, the second condition ensures that the information of the input system is only accessible through the output system. In particular, a quantum state $\rho$ may be also considered as a quantum network, where the input system is the trivial system $\mathbb{C}$, and the output system is the quantum system $\mathcal{H}$. The constraints on the quantum channels are then equivalent to the constraints on the quantum states: -$$ -\rho \geq 0, \quad \text{and} \quad \text{Tr} \rho = \mathbb{I}_ \mathbb{C} = 1\ . -$$ +$$\rho \geq 0, \quad \text{and} \quad \text{Tr} \rho = \mathbb{I}_ \mathbb{C} = 1\ .$$ > For more details, see G. Chiribella *et al.*, *Theoretical framework for quantum networks*, > [Physical Review A 80.2 (2009): 022339](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.80.022339). @@ -116,7 +112,7 @@ Choi2 is unital: False Choi3 is unital: False ``` -However, the mixture of the three operators are unital. +However, the mixture of the three operators is unital. As the matrices are orthogonal, they are the extreme points of the convex set of the unital channels. Therefore, this mixed channel is not a mixed unitary channel. From 66e82fc809ff0f33138ad7ad695626e133314847 Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 8 Feb 2024 08:27:03 +0400 Subject: [PATCH 159/200] doc: New badges --- .github/workflows/publish.yml | 2 +- README.md | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1399089483..c0b9fdf544 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,4 @@ -name: Deploy docs +name: docs on: workflow_dispatch: diff --git a/README.md b/README.md index bdb1e6f4f8..d53c014e3c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ ![Logo](https://github.com/qiboteam/qibo/blob/master/doc/source/_static/qibo_logo_dark.svg) -![Tests](https://github.com/qiboteam/qibo/workflows/Tests/badge.svg) [![codecov](https://codecov.io/gh/qiboteam/qibo/branch/master/graph/badge.svg?token=1EKZKVEVX0)](https://codecov.io/gh/qiboteam/qibo) -[![DOI](https://zenodo.org/badge/241307936.svg)](https://zenodo.org/badge/latestdoi/241307936) -[![Matrix](https://img.shields.io/matrix/qibo%3Amatrix.org?logo=matrix)](https://matrix.to/#/#qibo:matrix.org) +![PyPI - Version](https://img.shields.io/pypi/v/qibo) +![PyPI - Python Version](https://img.shields.io/pypi/pyversions/qibo) Qibo is an open-source full stack API for quantum simulation and quantum hardware control. @@ -15,6 +14,8 @@ Some of the key features of Qibo are: ## Documentation +[![docs](https://github.com/qiboteam/qibo/actions/workflows/publish.yml/badge.svg)](https://qibo.science/qibo/stable/) + Qibo documentation is available [here](https://qibo.science). ## Minimum Working Examples @@ -49,14 +50,15 @@ result = c(nshots=100) In both cases, the simulation will run in a single device CPU or GPU in double precision `complex128`. ## Citation policy - +[![arXiv](https://img.shields.io/badge/arXiv-2009.01845-b31b1b.svg)](https://arxiv.org/abs/2009.01845) +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3997195.svg)](https://doi.org/10.5281/zenodo.3997195) If you use the package please refer to [the documentation](https://qibo.science/qibo/stable/appendix/citing-qibo.html#publications) for citation instructions. ## Contacts To get in touch with the community and the developers, consider joining the Qibo workspace on Matrix: -https://matrix.to/#/#qibo:matrix.org +[![Matrix](https://img.shields.io/matrix/qibo%3Amatrix.org?logo=matrix)](https://matrix.to/#/#qibo:matrix.org) ## Supporters and collaborators From 9040a3867b23f9777dd65e09a00791ae43c7756e Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 8 Feb 2024 08:28:00 +0400 Subject: [PATCH 160/200] doc: Add newline --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d53c014e3c..2235daa833 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ In both cases, the simulation will run in a single device CPU or GPU in double p ## Citation policy [![arXiv](https://img.shields.io/badge/arXiv-2009.01845-b31b1b.svg)](https://arxiv.org/abs/2009.01845) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3997195.svg)](https://doi.org/10.5281/zenodo.3997195) + If you use the package please refer to [the documentation](https://qibo.science/qibo/stable/appendix/citing-qibo.html#publications) for citation instructions. ## Contacts From 8423e90c3878d3a140980863f17d3ffd253f9754 Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 8 Feb 2024 09:07:33 +0400 Subject: [PATCH 161/200] fix: Use latest zenodo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2235daa833..59f68ed2d9 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ In both cases, the simulation will run in a single device CPU or GPU in double p ## Citation policy [![arXiv](https://img.shields.io/badge/arXiv-2009.01845-b31b1b.svg)](https://arxiv.org/abs/2009.01845) -[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3997195.svg)](https://doi.org/10.5281/zenodo.3997195) +[![DOI](https://zenodo.org/badge/3997195.svg)](https://zenodo.org/badge/latestdoi/3997195) If you use the package please refer to [the documentation](https://qibo.science/qibo/stable/appendix/citing-qibo.html#publications) for citation instructions. From 34640c1922518d07eca9ca86f660f194746b77fe Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 8 Feb 2024 12:46:38 +0400 Subject: [PATCH 162/200] fix: Fix DOI --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59f68ed2d9..46a64fe115 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ In both cases, the simulation will run in a single device CPU or GPU in double p ## Citation policy [![arXiv](https://img.shields.io/badge/arXiv-2009.01845-b31b1b.svg)](https://arxiv.org/abs/2009.01845) -[![DOI](https://zenodo.org/badge/3997195.svg)](https://zenodo.org/badge/latestdoi/3997195) +[![DOI](https://zenodo.org/badge/241307936.svg)](https://zenodo.org/badge/latestdoi/241307936) If you use the package please refer to [the documentation](https://qibo.science/qibo/stable/appendix/citing-qibo.html#publications) for citation instructions. From 43f708d8bda5dcbf5a67c9777ee7406103c2cac8 Mon Sep 17 00:00:00 2001 From: MatteoRobbiati Date: Thu, 8 Feb 2024 11:25:33 +0100 Subject: [PATCH 163/200] update backends and ecosystem diagrams --- doc/source/getting-started/backends.svg | 3506 +---------------------- doc/source/qibo_ecosystem.svg | 10 +- 2 files changed, 11 insertions(+), 3505 deletions(-) diff --git a/doc/source/getting-started/backends.svg b/doc/source/getting-started/backends.svg index f41f94df97..10890f53b9 100644 --- a/doc/source/getting-started/backends.svg +++ b/doc/source/getting-started/backends.svg @@ -1,3500 +1,6 @@ - - - - - - image/svg+xml - - - - - - - - +
    Qibo backends
    Simulating on classical hardware
    Clifford
    Qibotn
    Qibojit
    tensorflow
    numpy
    CPU/lightweight
    CPU/GPU high performance
    Specialized
    Executing on quantum hardware
    Qibolab
    diff --git a/doc/source/qibo_ecosystem.svg b/doc/source/qibo_ecosystem.svg index c3ace1030f..5da2b6f483 100644 --- a/doc/source/qibo_ecosystem.svg +++ b/doc/source/qibo_ecosystem.svg @@ -1,13 +1,13 @@ -
    Qibo
    Language API
    Quantum annealing
    Quantum circuits
    Quantum information
    Implementation
    Simulation
    Clifford
    Specialized in Clifford circuits simulation
    Qibotn
    TensorNetwork simulator
    Qibojit
    Efficient device-agnostic simulation with custom operators
    tensorflow
    Simulation of hybrid QML with automatic differentiation
    numpy
    Lightweight, fits +well with any CPU
    Quantum hardware
    Qibocal
    Characterization
    Calibration
    Validation
    Qibolab
    Control drivers
    Convert gates to pulses
    Transpiler
    = backends
    = tools
    RFSoCs
    Application packages
    Qibosoq
    Qibochem
    From 16c8ea90366c4f0da75324463dbf543072900b74 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Fri, 9 Feb 2024 10:14:13 +0400 Subject: [PATCH 164/200] fix --- src/qibo/quantum_info/random_ensembles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index f8da6a6825..b1be867620 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -579,7 +579,7 @@ def random_clifford( Args: nqubits (int): number of qubits. return_circuit (bool, optional): if ``True``, returns a :class:`qibo.models.Circuit` - object. If ``False``, returns an ``ndarray`` object. Defaults to ``False``. + object. If ``False``, returns an ``ndarray`` object. Defaults to ``True``. density_matrix (bool, optional): used when ``return_circuit=True``. If `True`, the circuit would evolve density matrices. Defaults to ``False``. seed (int or :class:`numpy.random.Generator`, optional): Either a generator of From ed3d652dd9830a95263e0f325f417c81fbb1e23e Mon Sep 17 00:00:00 2001 From: MatteoRobbiati Date: Fri, 9 Feb 2024 09:15:06 +0100 Subject: [PATCH 165/200] fix quantum info box --- doc/source/qibo_ecosystem.svg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/qibo_ecosystem.svg b/doc/source/qibo_ecosystem.svg index 5da2b6f483..032c2a7431 100644 --- a/doc/source/qibo_ecosystem.svg +++ b/doc/source/qibo_ecosystem.svg @@ -1,4 +1,4 @@ -
    Qibo
    Language API
    Quantum annealing
    Quantum circuits
    Quantum information
    Implementation
    Simulation
    Clifford
    Specialized in Clifford circuits simulation
    Qibotn
    TensorNetwork simulator
    Qibojit
    Efficient device-agnostic simulation with custom operators
    tensorflow
    Simulation of hybrid QML with automatic differentiation
    numpy
    Lightweight, fits +well with any CPU
    Quantum hardware
    Qibocal
    Characterization
    Calibration
    Validation
    Qibolab
    Control drivers
    Convert gates to pulses
    Transpiler
    = backends
    = tools
    RFSoCs
    Application packages
    Qibosoq
    Qibochem
    From 457cb71764c2f26b2f19bb6461299c2797e8b8f0 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 10 Feb 2024 11:05:33 +0400 Subject: [PATCH 166/200] tensorflow --- src/qibo/backends/tensorflow.py | 163 +++++++++++--------------------- 1 file changed, 54 insertions(+), 109 deletions(-) diff --git a/src/qibo/backends/tensorflow.py b/src/qibo/backends/tensorflow.py index cc2a9a9bb0..d29443e57c 100644 --- a/src/qibo/backends/tensorflow.py +++ b/src/qibo/backends/tensorflow.py @@ -20,142 +20,87 @@ def __init__(self, dtype): self.tf = tf self.np = tnp + def _get_numpy_gate(self, name, params): + matrix = getattr(NumpyMatrices(self.dtype), name)(*params) + return self.tf.cast(matrix, dtype=self.dtype) + def RX(self, theta): - cos = self.np.cos(theta / 2.0) + 0j - isin = -1j * self.np.sin(theta / 2.0) - return self.tf.cast([[cos, isin], [isin, cos]], dtype=self.dtype) + return self._get_numpy_gate("RX", [theta]) def RY(self, theta): - cos = self.np.cos(theta / 2.0) + 0j - sin = self.np.sin(theta / 2.0) + 0j - return self.tf.cast([[cos, -sin], [sin, cos]], dtype=self.dtype) + return self._get_numpy_gate("RY", [theta]) def RZ(self, theta): - phase = self.np.exp(0.5j * theta) - return self.tf.cast([[self.np.conj(phase), 0], [0, phase]], dtype=self.dtype) + return self._get_numpy_gate("RZ", [theta]) + + def GPI(self, phi): + return self._get_numpy_gate("GPI", [phi]) + + def GPI2(self, phi): + return self._get_numpy_gate("GPI2", [phi]) def U1(self, theta): - phase = self.np.exp(1j * theta) - return self.tf.cast([[1, 0], [0, phase]], dtype=self.dtype) + return self._get_numpy_gate("U1", [theta]) def U2(self, phi, lam): - eplus = self.np.exp(1j * (phi + lam) / 2.0) - eminus = self.np.exp(1j * (phi - lam) / 2.0) - return self.tf.cast( - [[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]], - dtype=self.dtype, - ) / self.np.sqrt(2) + return self._get_numpy_gate("U2", [phi, lam]) def U3(self, theta, phi, lam): - cost = self.np.cos(theta / 2) - sint = self.np.sin(theta / 2) - eplus = self.np.exp(1j * (phi + lam) / 2.0) - eminus = self.np.exp(1j * (phi - lam) / 2.0) - return self.tf.cast( - [ - [self.np.conj(eplus) * cost, -self.np.conj(eminus) * sint], - [eminus * sint, eplus * cost], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("U3", [theta, phi, lam]) + + def U1q(self, theta, phi): + return self._get_numpy_gate("U1q", [theta, phi]) def CRX(self, theta): - r = self.RX(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("CRX", [theta]) def CRY(self, theta): - r = self.RY(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("CRY", [theta]) def CRZ(self, theta): - r = self.RZ(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("CRZ", [theta]) def CU1(self, theta): - r = self.U1(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("CU1", [theta]) def CU2(self, phi, lam): - r = self.U2(phi, lam) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("CU2", [phi, lam]) def CU3(self, theta, phi, lam): - r = self.U3(theta, phi, lam) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("CU3", [theta, phi, lam]) def fSim(self, theta, phi): - cost = self.np.cos(theta) + 0j - isint = -1j * self.np.sin(theta) - phase = self.np.exp(-1j * phi) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, cost, isint, 0], - [0, isint, cost, 0], - [0, 0, 0, phase], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("fSim", [theta, phi]) def GeneralizedfSim(self, u, phi): - phase = self.np.exp(-1j * phi) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, u[0, 0], u[0, 1], 0], - [0, u[1, 0], u[1, 1], 0], - [0, 0, 0, phase], - ], - dtype=self.dtype, - ) + return self._get_numpy_gate("GeneralizedfSim", [u, phi]) + + def RXX(self, theta): + return self._get_numpy_gate("RXX", [theta]) + + def RYY(self, theta): + return self._get_numpy_gate("RYY", [theta]) + + def RZZ(self, theta): + return self._get_numpy_gate("RZZ", [theta]) + + def RZX(self, theta): + return self._get_numpy_gate("RZX", [theta]) + + def RXXYY(self, theta): + return self._get_numpy_gate("RXXYY", [theta]) + + def MS(self, phi0, phi1, theta): + return self._get_numpy_gate("MS", [phi0, phi1, theta]) + + def GIVENS(self, theta): + return self._get_numpy_gate("GIVENS", [theta]) + + def RBS(self, theta): + return self._get_numpy_gate("RBS", [theta]) + + def DEUTSCH(self, theta): + return self._get_numpy_gate("DEUTSCH", [theta]) def Unitary(self, u): return self.tf.cast(u, dtype=self.dtype) From 15c707d29405e5d5d9acd7c942e5e8dffc2ede89 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sat, 10 Feb 2024 12:34:10 +0400 Subject: [PATCH 167/200] revert changes and add gates properly --- src/qibo/backends/tensorflow.py | 246 ++++++++++++++++++++++++++++---- 1 file changed, 216 insertions(+), 30 deletions(-) diff --git a/src/qibo/backends/tensorflow.py b/src/qibo/backends/tensorflow.py index d29443e57c..2761a35588 100644 --- a/src/qibo/backends/tensorflow.py +++ b/src/qibo/backends/tensorflow.py @@ -20,87 +20,273 @@ def __init__(self, dtype): self.tf = tf self.np = tnp - def _get_numpy_gate(self, name, params): - matrix = getattr(NumpyMatrices(self.dtype), name)(*params) - return self.tf.cast(matrix, dtype=self.dtype) - def RX(self, theta): - return self._get_numpy_gate("RX", [theta]) + cos = self.np.cos(theta / 2.0) + 0j + isin = -1j * self.np.sin(theta / 2.0) + return self.tf.cast([[cos, isin], [isin, cos]], dtype=self.dtype) def RY(self, theta): - return self._get_numpy_gate("RY", [theta]) + cos = self.np.cos(theta / 2.0) + 0j + sin = self.np.sin(theta / 2.0) + 0j + return self.tf.cast([[cos, -sin], [sin, cos]], dtype=self.dtype) def RZ(self, theta): - return self._get_numpy_gate("RZ", [theta]) + phase = self.np.exp(0.5j * theta) + return self.tf.cast([[self.np.conj(phase), 0], [0, phase]], dtype=self.dtype) def GPI(self, phi): - return self._get_numpy_gate("GPI", [phi]) + phase = self.np.exp(1.0j * phi) + return self.tf.cast([[0, self.np.conj(phase)], [phase, 0]], dtype=self.dtype) def GPI2(self, phi): - return self._get_numpy_gate("GPI2", [phi]) + phase = self.np.exp(1.0j * phi) + return self.tf.cast( + [[1, -1.0j * self.np.conj(phase)], [-1.0j * phase, 1]], dtype=self.dtype + ) / self.np.sqrt(2) def U1(self, theta): - return self._get_numpy_gate("U1", [theta]) + phase = self.np.exp(1j * theta) + return self.tf.cast([[1, 0], [0, phase]], dtype=self.dtype) def U2(self, phi, lam): - return self._get_numpy_gate("U2", [phi, lam]) + eplus = self.np.exp(1j * (phi + lam) / 2.0) + eminus = self.np.exp(1j * (phi - lam) / 2.0) + return self.tf.cast( + [[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]], + dtype=self.dtype, + ) / self.np.sqrt(2) def U3(self, theta, phi, lam): - return self._get_numpy_gate("U3", [theta, phi, lam]) + cost = self.np.cos(theta / 2) + sint = self.np.sin(theta / 2) + eplus = self.np.exp(1j * (phi + lam) / 2.0) + eminus = self.np.exp(1j * (phi - lam) / 2.0) + return self.tf.cast( + [ + [self.np.conj(eplus) * cost, -self.np.conj(eminus) * sint], + [eminus * sint, eplus * cost], + ], + dtype=self.dtype, + ) def U1q(self, theta, phi): - return self._get_numpy_gate("U1q", [theta, phi]) + return self.U3(theta, phi - self.np.pi / 2, self.np.pi / 2 - phi) def CRX(self, theta): - return self._get_numpy_gate("CRX", [theta]) + r = self.RX(theta) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, r[0, 0], r[0, 1]], + [0, 0, r[1, 0], r[1, 1]], + ], + dtype=self.dtype, + ) def CRY(self, theta): - return self._get_numpy_gate("CRY", [theta]) + r = self.RY(theta) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, r[0, 0], r[0, 1]], + [0, 0, r[1, 0], r[1, 1]], + ], + dtype=self.dtype, + ) def CRZ(self, theta): - return self._get_numpy_gate("CRZ", [theta]) + r = self.RZ(theta) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, r[0, 0], r[0, 1]], + [0, 0, r[1, 0], r[1, 1]], + ], + dtype=self.dtype, + ) def CU1(self, theta): - return self._get_numpy_gate("CU1", [theta]) + r = self.U1(theta) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, r[0, 0], r[0, 1]], + [0, 0, r[1, 0], r[1, 1]], + ], + dtype=self.dtype, + ) def CU2(self, phi, lam): - return self._get_numpy_gate("CU2", [phi, lam]) + r = self.U2(phi, lam) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, r[0, 0], r[0, 1]], + [0, 0, r[1, 0], r[1, 1]], + ], + dtype=self.dtype, + ) def CU3(self, theta, phi, lam): - return self._get_numpy_gate("CU3", [theta, phi, lam]) + r = self.U3(theta, phi, lam) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, r[0, 0], r[0, 1]], + [0, 0, r[1, 0], r[1, 1]], + ], + dtype=self.dtype, + ) def fSim(self, theta, phi): - return self._get_numpy_gate("fSim", [theta, phi]) + cost = self.np.cos(theta) + 0j + isint = -1j * self.np.sin(theta) + phase = self.np.exp(-1j * phi) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, cost, isint, 0], + [0, isint, cost, 0], + [0, 0, 0, phase], + ], + dtype=self.dtype, + ) def GeneralizedfSim(self, u, phi): - return self._get_numpy_gate("GeneralizedfSim", [u, phi]) + phase = self.np.exp(-1j * phi) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, u[0, 0], u[0, 1], 0], + [0, u[1, 0], u[1, 1], 0], + [0, 0, 0, phase], + ], + dtype=self.dtype, + ) def RXX(self, theta): - return self._get_numpy_gate("RXX", [theta]) + cos = self.np.cos(theta / 2.0) + 0j + isin = -1j * self.np.sin(theta / 2.0) + return self.tf.cast( + [ + [cos, 0, 0, isin], + [0, cos, isin, 0], + [0, isin, cos, 0], + [isin, 0, 0, cos], + ], + dtype=self.dtype, + ) def RYY(self, theta): - return self._get_numpy_gate("RYY", [theta]) + cos = self.np.cos(theta / 2.0) + 0j + isin = -1j * self.np.sin(theta / 2.0) + return self.tf.cast( + [ + [cos, 0, 0, -isin], + [0, cos, isin, 0], + [0, isin, cos, 0], + [-isin, 0, 0, cos], + ], + dtype=self.dtype, + ) def RZZ(self, theta): - return self._get_numpy_gate("RZZ", [theta]) + phase = self.np.exp(0.5j * theta) + return self.tf.cast( + [ + [self.np.conj(phase), 0, 0, 0], + [0, phase, 0, 0], + [0, 0, phase, 0], + [0, 0, 0, self.np.conj(phase)], + ], + dtype=self.dtype, + ) def RZX(self, theta): - return self._get_numpy_gate("RZX", [theta]) + cos, sin = self.np.cos(theta / 2), self.np.sin(theta / 2) + return self.tf.cast( + [ + [cos, -1j * sin, 0, 0], + [-1j * sin, cos, 0, 0], + [0, 0, cos, 1j * sin], + [0, 0, 1j * sin, cos], + ], + dtype=self.dtype, + ) def RXXYY(self, theta): - return self._get_numpy_gate("RXXYY", [theta]) + cos, sin = self.np.cos(theta / 2), self.np.sin(theta / 2) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, cos, -1j * sin, 0], + [0, -1j * sin, cos, 0], + [0, 0, 0, 1], + ], + dtype=self.dtype, + ) def MS(self, phi0, phi1, theta): - return self._get_numpy_gate("MS", [phi0, phi1, theta]) + plus = self.np.exp(1.0j * (phi0 + phi1)) + minus = self.np.exp(1.0j * (phi0 - phi1)) + + return self.tf.cast( + [ + [ + self.np.cos(theta / 2), + 0, + 0, + -1.0j * self.np.conj(plus) * self.np.sin(theta / 2), + ], + [ + 0, + self.np.cos(theta / 2), + -1.0j * self.np.conj(minus) * self.np.sin(theta / 2), + 0, + ], + [0, -1.0j * minus * self.np.sin(theta / 2), self.np.cos(theta / 2), 0], + [-1.0j * plus * self.np.sin(theta / 2), 0, 0, self.np.cos(theta / 2)], + ], + dtype=self.dtype, + ) def GIVENS(self, theta): - return self._get_numpy_gate("GIVENS", [theta]) + return self.tf.cast( + [ + [1, 0, 0, 0], + [0, self.np.cos(theta), -self.np.sin(theta), 0], + [0, self.np.sin(theta), self.np.cos(theta), 0], + [0, 0, 0, 1], + ], + dtype=self.dtype, + ) def RBS(self, theta): - return self._get_numpy_gate("RBS", [theta]) + return self.GIVENS(-theta) def DEUTSCH(self, theta): - return self._get_numpy_gate("DEUTSCH", [theta]) + sin = self.np.sin(theta) + 0j # 0j necessary for right tensorflow dtype + cos = self.np.cos(theta) + return self.tf.cast( + [ + [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, 1j * cos, sin], + [0, 0, 0, 0, 0, 0, sin, 1j * cos], + ], + dtype=self.dtype, + ) + def Unitary(self, u): return self.tf.cast(u, dtype=self.dtype) From 4b3ac59a65cb246d0182e0fc976df8e32ad33a92 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 10 Feb 2024 08:34:38 +0000 Subject: [PATCH 168/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/tensorflow.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qibo/backends/tensorflow.py b/src/qibo/backends/tensorflow.py index 2761a35588..2f61234534 100644 --- a/src/qibo/backends/tensorflow.py +++ b/src/qibo/backends/tensorflow.py @@ -287,7 +287,6 @@ def DEUTSCH(self, theta): dtype=self.dtype, ) - def Unitary(self, u): return self.tf.cast(u, dtype=self.dtype) From a8109744649ab7cf169523fcbe32d207bc809b19 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 11 Feb 2024 10:18:51 +0400 Subject: [PATCH 169/200] fix bug --- src/qibo/backends/tensorflow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qibo/backends/tensorflow.py b/src/qibo/backends/tensorflow.py index 2f61234534..939c2385b5 100644 --- a/src/qibo/backends/tensorflow.py +++ b/src/qibo/backends/tensorflow.py @@ -209,7 +209,7 @@ def RZZ(self, theta): ) def RZX(self, theta): - cos, sin = self.np.cos(theta / 2), self.np.sin(theta / 2) + cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j return self.tf.cast( [ [cos, -1j * sin, 0, 0], @@ -221,7 +221,7 @@ def RZX(self, theta): ) def RXXYY(self, theta): - cos, sin = self.np.cos(theta / 2), self.np.sin(theta / 2) + cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j return self.tf.cast( [ [1, 0, 0, 0], @@ -272,7 +272,7 @@ def RBS(self, theta): def DEUTSCH(self, theta): sin = self.np.sin(theta) + 0j # 0j necessary for right tensorflow dtype - cos = self.np.cos(theta) + cos = self.np.cos(theta) + 0j return self.tf.cast( [ [1, 0, 0, 0, 0, 0, 0, 0], From 7b03730beeb199e744f11d6f9a3d64dfb3735240 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 11 Feb 2024 10:42:13 +0400 Subject: [PATCH 170/200] fix bug --- src/qibo/backends/tensorflow.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qibo/backends/tensorflow.py b/src/qibo/backends/tensorflow.py index 939c2385b5..c57f7db8cf 100644 --- a/src/qibo/backends/tensorflow.py +++ b/src/qibo/backends/tensorflow.py @@ -235,23 +235,23 @@ def RXXYY(self, theta): def MS(self, phi0, phi1, theta): plus = self.np.exp(1.0j * (phi0 + phi1)) minus = self.np.exp(1.0j * (phi0 - phi1)) - + cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j return self.tf.cast( [ [ - self.np.cos(theta / 2), + cos, 0, 0, - -1.0j * self.np.conj(plus) * self.np.sin(theta / 2), + -1.0j * self.np.conj(plus) * sin, ], [ 0, - self.np.cos(theta / 2), - -1.0j * self.np.conj(minus) * self.np.sin(theta / 2), + cos, + -1.0j * self.np.conj(minus) * sin, 0, ], - [0, -1.0j * minus * self.np.sin(theta / 2), self.np.cos(theta / 2), 0], - [-1.0j * plus * self.np.sin(theta / 2), 0, 0, self.np.cos(theta / 2)], + [0, -1.0j * minus * sin, cos, 0], + [-1.0j * plus * sin, 0, 0, cos], ], dtype=self.dtype, ) From 85f26bc518229454cd7ce1ccc5acdcfea25bb15e Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Sun, 11 Feb 2024 10:45:31 +0400 Subject: [PATCH 171/200] pre-commit --- src/qibo/backends/tensorflow.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/qibo/backends/tensorflow.py b/src/qibo/backends/tensorflow.py index c57f7db8cf..a710f0c165 100644 --- a/src/qibo/backends/tensorflow.py +++ b/src/qibo/backends/tensorflow.py @@ -238,18 +238,8 @@ def MS(self, phi0, phi1, theta): cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j return self.tf.cast( [ - [ - cos, - 0, - 0, - -1.0j * self.np.conj(plus) * sin, - ], - [ - 0, - cos, - -1.0j * self.np.conj(minus) * sin, - 0, - ], + [cos, 0, 0, -1.0j * self.np.conj(plus) * sin], + [0, cos, -1.0j * self.np.conj(minus) * sin, 0], [0, -1.0j * minus * sin, cos, 0], [-1.0j * plus * sin, 0, 0, cos], ], From 7816653a9d9d62ecc63ccbd257efa838a3a887c0 Mon Sep 17 00:00:00 2001 From: scarrazza Date: Mon, 12 Feb 2024 19:26:31 +0100 Subject: [PATCH 172/200] adding doi --- doc/source/appendix/citing-qibo.rst | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/source/appendix/citing-qibo.rst b/doc/source/appendix/citing-qibo.rst index 40f8a3b456..7d08dc2e2d 100644 --- a/doc/source/appendix/citing-qibo.rst +++ b/doc/source/appendix/citing-qibo.rst @@ -69,8 +69,28 @@ Peer-Reviewed Articles * S. Efthymiou, A. Orgaz-Fuertes, R. Carobene, J. Cereijo, A. Pasquale, S. Ramos-Calderer, S. Bordoni, D. Fuentes-Ruiz, A. Candido, E. Pedicillo, M. Robbiati, Y.P. Tan, J. Wilkens, I. Roth, J.I. Latorre, S. Carrazza, *Qibolab: - an open-source hybrid quantum operating system* (2023), (`arXiv:2308.06313`_). + an open-source hybrid quantum operating system* (2023), + `doi:10.22331/q-2024-02-12-1247`_, (`arXiv:2308.06313`_). + In *BibTeX* format: + + .. code-block:: text + + @article{qibolab_paper, + doi = {10.22331/q-2024-02-12-1247}, + url = {https://doi.org/10.22331/q-2024-02-12-1247}, + title = {Qibolab: an open-source hybrid quantum operating system}, + author = {Efthymiou, Stavros and Orgaz-Fuertes, Alvaro and Carobene, Rodolfo and Cereijo, Juan and Pasquale, Andrea and Ramos-Calderer, Sergi and Bordoni, Simone and Fuentes-Ruiz, David and Candido, Alessandro and Pedicillo, Edoardo and Robbiati, Matteo and Tan, Yuanzheng Paul and Wilkens, Jadwiga and Roth, Ingo and Latorre, Jos{\'{e}} Ignacio and Carrazza, Stefano}, + journal = {{Quantum}}, + issn = {2521-327X}, + publisher = {{Verein zur F{\"{o}}rderung des Open Access Publizierens in den Quantenwissenschaften}}, + volume = {8}, + pages = {1247}, + month = feb, + year = {2024} + } + +.. _`doi:10.22331/q-2024-02-12-1247`: https://doi.org/10.22331/q-2024-02-12-1247 .. _`arXiv:2308.06313`: https://arxiv.org/abs/2308.06313 * R. Carobene, A. Candido, J. Serrano, A.O-Fuertes, A. Giachero, S. Carrazza, From dd0614753c5305914e9113b702315d10cc4398c1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:23:41 +0000 Subject: [PATCH 173/200] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 24.1.1 → 24.2.0](https://github.com/psf/black/compare/24.1.1...24.2.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 28dfdd0dfc..b8632cdd54 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: check-yaml - id: debug-statements - repo: https://github.com/psf/black - rev: 24.1.1 + rev: 24.2.0 hooks: - id: black - repo: https://github.com/pycqa/isort From f944957ea3ae23acb1a3891702e9b0f1f7608652 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 13 Feb 2024 11:20:46 +0400 Subject: [PATCH 174/200] stavros' suggestion --- src/qibo/backends/npmatrices.py | 96 ++++++------ src/qibo/backends/tensorflow.py | 260 +------------------------------- 2 files changed, 46 insertions(+), 310 deletions(-) diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index ee65e90275..6cdbeb3973 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -1,5 +1,7 @@ from functools import cached_property +from scipy.linalg import block_diag + from qibo.config import raise_error @@ -12,6 +14,9 @@ def __init__(self, dtype): self.dtype = dtype self.np = np + def _cast(self, x, dtype): + return self.np.array(x, dtype=dtype) + @cached_property def H(self): return self.np.array([[1, 1], [1, -1]], dtype=self.dtype) / self.np.sqrt(2) @@ -66,35 +71,35 @@ def M(self): # pragma: no cover def RX(self, theta): cos = self.np.cos(theta / 2.0) + 0j isin = -1j * self.np.sin(theta / 2.0) - return self.np.array([[cos, isin], [isin, cos]], dtype=self.dtype) + return self._cast([[cos, isin], [isin, cos]], dtype=self.dtype) def RY(self, theta): cos = self.np.cos(theta / 2.0) + 0j - sin = self.np.sin(theta / 2.0) - return self.np.array([[cos, -sin], [sin, cos]], dtype=self.dtype) + sin = self.np.sin(theta / 2.0) + 0j + return self._cast([[cos, -sin], [sin, cos]], dtype=self.dtype) def RZ(self, theta): phase = self.np.exp(0.5j * theta) - return self.np.array([[self.np.conj(phase), 0], [0, phase]], dtype=self.dtype) + return self._cast([[self.np.conj(phase), 0], [0, phase]], dtype=self.dtype) def GPI(self, phi): phase = self.np.exp(1.0j * phi) - return self.np.array([[0, self.np.conj(phase)], [phase, 0]], dtype=self.dtype) + return self._cast([[0, self.np.conj(phase)], [phase, 0]], dtype=self.dtype) def GPI2(self, phi): phase = self.np.exp(1.0j * phi) - return self.np.array( + return self._cast( [[1, -1.0j * self.np.conj(phase)], [-1.0j * phase, 1]], dtype=self.dtype ) / self.np.sqrt(2) def U1(self, theta): phase = self.np.exp(1j * theta) - return self.np.array([[1, 0], [0, phase]], dtype=self.dtype) + return self._cast([[1, 0], [0, phase]], dtype=self.dtype) def U2(self, phi, lam): eplus = self.np.exp(1j * (phi + lam) / 2.0) eminus = self.np.exp(1j * (phi - lam) / 2.0) - return self.np.array( + return self._cast( [[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]], dtype=self.dtype, ) / self.np.sqrt(2) @@ -104,7 +109,7 @@ def U3(self, theta, phi, lam): sint = self.np.sin(theta / 2) eplus = self.np.exp(1j * (phi + lam) / 2.0) eminus = self.np.exp(1j * (phi - lam) / 2.0) - return self.np.array( + return self._cast( [ [self.np.conj(eplus) * cost, -self.np.conj(eminus) * sint], [eminus * sint, eplus * cost], @@ -153,34 +158,28 @@ def CSXDG(self): return self.np.transpose(self.np.conj(self.CSX)) def CRX(self, theta): - m = self.np.eye(4, dtype=self.dtype) - m[2:, 2:] = self.RX(theta) - return m + identity = [[1.0, 0.0], [0.0, 1.0]] + return block_diag(identity, self.RX(theta)) def CRY(self, theta): - m = self.np.eye(4, dtype=self.dtype) - m[2:, 2:] = self.RY(theta) - return m + identity = [[1.0, 0.0], [0.0, 1.0]] + return block_diag(identity, self.RY(theta)) def CRZ(self, theta): - m = self.np.eye(4, dtype=self.dtype) - m[2:, 2:] = self.RZ(theta) - return m + identity = [[1.0, 0.0], [0.0, 1.0]] + return block_diag(identity, self.RZ(theta)) def CU1(self, theta): - m = self.np.eye(4, dtype=self.dtype) - m[2:, 2:] = self.U1(theta) - return m + identity = [[1.0, 0.0], [0.0, 1.0]] + return block_diag(identity, self.U1(theta)) def CU2(self, phi, lam): - m = self.np.eye(4, dtype=self.dtype) - m[2:, 2:] = self.U2(phi, lam) - return m + identity = [[1.0, 0.0], [0.0, 1.0]] + return block_diag(identity, self.U2(phi, lam)) def CU3(self, theta, phi, lam): - m = self.np.eye(4, dtype=self.dtype) - m[2:, 2:] = self.U3(theta, phi, lam) - return m + identity = [[1.0, 0.0], [0.0, 1.0]] + return block_diag(identity, self.U3(theta, phi, lam)) @cached_property def SWAP(self): @@ -228,7 +227,7 @@ def fSim(self, theta, phi): cost = self.np.cos(theta) + 0j isint = -1j * self.np.sin(theta) phase = self.np.exp(-1j * phi) - return self.np.array( + return self._cast( [ [1, 0, 0, 0], [0, cost, isint, 0], @@ -255,7 +254,7 @@ def SYC(self): def GeneralizedfSim(self, u, phi): phase = self.np.exp(-1j * phi) - return self.np.array( + return self._cast( [ [1, 0, 0, 0], [0, complex(u[0, 0]), complex(u[0, 1]), 0], @@ -268,7 +267,7 @@ def GeneralizedfSim(self, u, phi): def RXX(self, theta): cos = self.np.cos(theta / 2.0) + 0j isin = -1j * self.np.sin(theta / 2.0) - return self.np.array( + return self._cast( [ [cos, 0, 0, isin], [0, cos, isin, 0], @@ -281,7 +280,7 @@ def RXX(self, theta): def RYY(self, theta): cos = self.np.cos(theta / 2.0) + 0j isin = -1j * self.np.sin(theta / 2.0) - return self.np.array( + return self._cast( [ [cos, 0, 0, -isin], [0, cos, isin, 0], @@ -293,7 +292,7 @@ def RYY(self, theta): def RZZ(self, theta): phase = self.np.exp(0.5j * theta) - return self.np.array( + return self._cast( [ [self.np.conj(phase), 0, 0, 0], [0, phase, 0, 0], @@ -304,8 +303,8 @@ def RZZ(self, theta): ) def RZX(self, theta): - cos, sin = self.np.cos(theta / 2), self.np.sin(theta / 2) - return self.np.array( + cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j + return self._cast( [ [cos, -1j * sin, 0, 0], [-1j * sin, cos, 0, 0], @@ -316,8 +315,8 @@ def RZX(self, theta): ) def RXXYY(self, theta): - cos, sin = self.np.cos(theta / 2), self.np.sin(theta / 2) - return self.np.array( + cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j + return self._cast( [ [1, 0, 0, 0], [0, cos, -1j * sin, 0], @@ -330,29 +329,20 @@ def RXXYY(self, theta): def MS(self, phi0, phi1, theta): plus = self.np.exp(1.0j * (phi0 + phi1)) minus = self.np.exp(1.0j * (phi0 - phi1)) - - return self.np.array( + cos = self.np.cos(theta / 2) + 0j + sin = self.np.sin(theta / 2) + 0j + return self._cast( [ - [ - self.np.cos(theta / 2), - 0, - 0, - -1.0j * self.np.conj(plus) * self.np.sin(theta / 2), - ], - [ - 0, - self.np.cos(theta / 2), - -1.0j * self.np.conj(minus) * self.np.sin(theta / 2), - 0, - ], - [0, -1.0j * minus * self.np.sin(theta / 2), self.np.cos(theta / 2), 0], - [-1.0j * plus * self.np.sin(theta / 2), 0, 0, self.np.cos(theta / 2)], + [cos, 0, 0, -1.0j * self.np.conj(plus) * sin], + [0, cos, -1.0j * self.np.conj(minus) * sin, 0], + [0, -1.0j * minus * sin, cos, 0], + [-1.0j * plus * sin, 0, 0, cos], ], dtype=self.dtype, ) def GIVENS(self, theta): - return self.np.array( + return self._cast( [ [1, 0, 0, 0], [0, self.np.cos(theta), -self.np.sin(theta), 0], diff --git a/src/qibo/backends/tensorflow.py b/src/qibo/backends/tensorflow.py index a710f0c165..6490b37d9e 100644 --- a/src/qibo/backends/tensorflow.py +++ b/src/qibo/backends/tensorflow.py @@ -20,265 +20,11 @@ def __init__(self, dtype): self.tf = tf self.np = tnp - def RX(self, theta): - cos = self.np.cos(theta / 2.0) + 0j - isin = -1j * self.np.sin(theta / 2.0) - return self.tf.cast([[cos, isin], [isin, cos]], dtype=self.dtype) - - def RY(self, theta): - cos = self.np.cos(theta / 2.0) + 0j - sin = self.np.sin(theta / 2.0) + 0j - return self.tf.cast([[cos, -sin], [sin, cos]], dtype=self.dtype) - - def RZ(self, theta): - phase = self.np.exp(0.5j * theta) - return self.tf.cast([[self.np.conj(phase), 0], [0, phase]], dtype=self.dtype) - - def GPI(self, phi): - phase = self.np.exp(1.0j * phi) - return self.tf.cast([[0, self.np.conj(phase)], [phase, 0]], dtype=self.dtype) - - def GPI2(self, phi): - phase = self.np.exp(1.0j * phi) - return self.tf.cast( - [[1, -1.0j * self.np.conj(phase)], [-1.0j * phase, 1]], dtype=self.dtype - ) / self.np.sqrt(2) - - def U1(self, theta): - phase = self.np.exp(1j * theta) - return self.tf.cast([[1, 0], [0, phase]], dtype=self.dtype) - - def U2(self, phi, lam): - eplus = self.np.exp(1j * (phi + lam) / 2.0) - eminus = self.np.exp(1j * (phi - lam) / 2.0) - return self.tf.cast( - [[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]], - dtype=self.dtype, - ) / self.np.sqrt(2) - - def U3(self, theta, phi, lam): - cost = self.np.cos(theta / 2) - sint = self.np.sin(theta / 2) - eplus = self.np.exp(1j * (phi + lam) / 2.0) - eminus = self.np.exp(1j * (phi - lam) / 2.0) - return self.tf.cast( - [ - [self.np.conj(eplus) * cost, -self.np.conj(eminus) * sint], - [eminus * sint, eplus * cost], - ], - dtype=self.dtype, - ) - - def U1q(self, theta, phi): - return self.U3(theta, phi - self.np.pi / 2, self.np.pi / 2 - phi) - - def CRX(self, theta): - r = self.RX(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) - - def CRY(self, theta): - r = self.RY(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) - - def CRZ(self, theta): - r = self.RZ(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) - - def CU1(self, theta): - r = self.U1(theta) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) - - def CU2(self, phi, lam): - r = self.U2(phi, lam) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) - - def CU3(self, theta, phi, lam): - r = self.U3(theta, phi, lam) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, r[0, 0], r[0, 1]], - [0, 0, r[1, 0], r[1, 1]], - ], - dtype=self.dtype, - ) - - def fSim(self, theta, phi): - cost = self.np.cos(theta) + 0j - isint = -1j * self.np.sin(theta) - phase = self.np.exp(-1j * phi) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, cost, isint, 0], - [0, isint, cost, 0], - [0, 0, 0, phase], - ], - dtype=self.dtype, - ) - - def GeneralizedfSim(self, u, phi): - phase = self.np.exp(-1j * phi) - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, u[0, 0], u[0, 1], 0], - [0, u[1, 0], u[1, 1], 0], - [0, 0, 0, phase], - ], - dtype=self.dtype, - ) - - def RXX(self, theta): - cos = self.np.cos(theta / 2.0) + 0j - isin = -1j * self.np.sin(theta / 2.0) - return self.tf.cast( - [ - [cos, 0, 0, isin], - [0, cos, isin, 0], - [0, isin, cos, 0], - [isin, 0, 0, cos], - ], - dtype=self.dtype, - ) - - def RYY(self, theta): - cos = self.np.cos(theta / 2.0) + 0j - isin = -1j * self.np.sin(theta / 2.0) - return self.tf.cast( - [ - [cos, 0, 0, -isin], - [0, cos, isin, 0], - [0, isin, cos, 0], - [-isin, 0, 0, cos], - ], - dtype=self.dtype, - ) - - def RZZ(self, theta): - phase = self.np.exp(0.5j * theta) - return self.tf.cast( - [ - [self.np.conj(phase), 0, 0, 0], - [0, phase, 0, 0], - [0, 0, phase, 0], - [0, 0, 0, self.np.conj(phase)], - ], - dtype=self.dtype, - ) - - def RZX(self, theta): - cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j - return self.tf.cast( - [ - [cos, -1j * sin, 0, 0], - [-1j * sin, cos, 0, 0], - [0, 0, cos, 1j * sin], - [0, 0, 1j * sin, cos], - ], - dtype=self.dtype, - ) - - def RXXYY(self, theta): - cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, cos, -1j * sin, 0], - [0, -1j * sin, cos, 0], - [0, 0, 0, 1], - ], - dtype=self.dtype, - ) - - def MS(self, phi0, phi1, theta): - plus = self.np.exp(1.0j * (phi0 + phi1)) - minus = self.np.exp(1.0j * (phi0 - phi1)) - cos, sin = self.np.cos(theta / 2) + 0j, self.np.sin(theta / 2) + 0j - return self.tf.cast( - [ - [cos, 0, 0, -1.0j * self.np.conj(plus) * sin], - [0, cos, -1.0j * self.np.conj(minus) * sin, 0], - [0, -1.0j * minus * sin, cos, 0], - [-1.0j * plus * sin, 0, 0, cos], - ], - dtype=self.dtype, - ) - - def GIVENS(self, theta): - return self.tf.cast( - [ - [1, 0, 0, 0], - [0, self.np.cos(theta), -self.np.sin(theta), 0], - [0, self.np.sin(theta), self.np.cos(theta), 0], - [0, 0, 0, 1], - ], - dtype=self.dtype, - ) - - def RBS(self, theta): - return self.GIVENS(-theta) - - def DEUTSCH(self, theta): - sin = self.np.sin(theta) + 0j # 0j necessary for right tensorflow dtype - cos = self.np.cos(theta) + 0j - return self.tf.cast( - [ - [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, 1j * cos, sin], - [0, 0, 0, 0, 0, 0, sin, 1j * cos], - ], - dtype=self.dtype, - ) + def _cast(self, x, dtype): + return self.tf.cast(x, dtype=dtype) def Unitary(self, u): - return self.tf.cast(u, dtype=self.dtype) + return self._cast(u, dtype=self.dtype) class TensorflowBackend(NumpyBackend): From a773410ce5890e1ca1b51a0bedf574b1ee342fde Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 13 Feb 2024 12:59:22 +0400 Subject: [PATCH 175/200] fix controlled gates --- src/qibo/backends/npmatrices.py | 63 +++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index 6cdbeb3973..12600e8b39 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -1,7 +1,5 @@ from functools import cached_property -from scipy.linalg import block_diag - from qibo.config import raise_error @@ -158,28 +156,65 @@ def CSXDG(self): return self.np.transpose(self.np.conj(self.CSX)) def CRX(self, theta): - identity = [[1.0, 0.0], [0.0, 1.0]] - return block_diag(identity, self.RX(theta)) + cos = self.np.cos(theta / 2.0) + 0j + isin = -1j * self.np.sin(theta / 2.0) + matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, cos, isin], + [0, 0, isin, cos], + ] + return self._cast(matrix, dtype=self.dtype) def CRY(self, theta): - identity = [[1.0, 0.0], [0.0, 1.0]] - return block_diag(identity, self.RY(theta)) + cos = self.np.cos(theta / 2.0) + 0j + sin = self.np.sin(theta / 2.0) + 0j + matrix = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, cos, -sin], [0, 0, sin, cos]] + return self._cast(matrix, dtype=self.dtype) def CRZ(self, theta): - identity = [[1.0, 0.0], [0.0, 1.0]] - return block_diag(identity, self.RZ(theta)) + phase = self.np.exp(0.5j * theta) + matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, self.np.conj(phase), 0], + [0, 0, 0, phase], + ] + return self._cast(matrix, dtype=self.dtype) def CU1(self, theta): - identity = [[1.0, 0.0], [0.0, 1.0]] - return block_diag(identity, self.U1(theta)) + phase = self.np.exp(1j * theta) + matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, phase], + ] + return self._cast(matrix, dtype=self.dtype) def CU2(self, phi, lam): - identity = [[1.0, 0.0], [0.0, 1.0]] - return block_diag(identity, self.U2(phi, lam)) + eplus = self.np.exp(1j * (phi + lam) / 2.0) / self.np.sqrt(2) + eminus = self.np.exp(1j * (phi - lam) / 2.0) / self.np.sqrt(2) + matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, self.np.conj(eplus), -self.np.conj(eminus)], + [0, 0, eminus, eplus], + ] + return self._cast(matrix, dtype=self.dtype) def CU3(self, theta, phi, lam): - identity = [[1.0, 0.0], [0.0, 1.0]] - return block_diag(identity, self.U3(theta, phi, lam)) + cost = self.np.cos(theta / 2) + sint = self.np.sin(theta / 2) + eplus = self.np.exp(1j * (phi + lam) / 2.0) + eminus = self.np.exp(1j * (phi - lam) / 2.0) + matrix = [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, self.np.conj(eplus) * cost, -self.np.conj(eminus) * sint], + [0, 0, eminus * sint, eplus * cost], + ] + return self._cast(matrix, dtype=self.dtype) @cached_property def SWAP(self): From afedc609dd03ac6a9c9a3edc1f29a34b4da15dbc Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 13 Feb 2024 14:18:56 +0400 Subject: [PATCH 176/200] fix coverage --- tests/test_quantum_info_quantum_networks.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_quantum_info_quantum_networks.py b/tests/test_quantum_info_quantum_networks.py index 9345ee3ede..1f20a97b45 100644 --- a/tests/test_quantum_info_quantum_networks.py +++ b/tests/test_quantum_info_quantum_networks.py @@ -28,6 +28,13 @@ def test_errors(backend): matrix = random_density_matrix(2**3, backend=backend) net = QuantumNetwork(matrix, (2,) * 3, backend=backend) + comb_partition = (2,) * 4 + comb_sys_out = (False, True) * 2 + comb = random_density_matrix(2**4, backend=backend) + comb_choi = QuantumNetwork( + comb, comb_partition, system_output=comb_sys_out, backend=backend + ) + with pytest.raises(TypeError): QuantumNetwork(channel.to_choi(backend=backend), partition=True) @@ -91,6 +98,18 @@ def test_errors(backend): with pytest.raises(NotImplementedError): net @ network + with pytest.raises(ValueError): + network @ net + + with pytest.raises(ValueError): + network @ QuantumNetwork(comb, (16, 16), pure=True, backend=backend) + + with pytest.raises(ValueError): + comb_choi @ QuantumNetwork(comb, (16, 16), pure=True, backend=backend) + + with pytest.raises(ValueError): + comb_choi @ net + with pytest.raises(ValueError): QuantumNetwork(matrix, (1, 2), backend=backend) From d180c71159bd056f55be2c3f95edf97f4c317e0f Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 13 Feb 2024 16:35:03 +0400 Subject: [PATCH 177/200] fix seed --- tests/test_quantum_info_clifford.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quantum_info_clifford.py b/tests/test_quantum_info_clifford.py index 3290aefc31..d6e12b3a36 100644 --- a/tests/test_quantum_info_clifford.py +++ b/tests/test_quantum_info_clifford.py @@ -68,7 +68,7 @@ def test_clifford_to_circuit(backend, nqubits, algorithm): if backend.__class__.__name__ == "TensorflowBackend": pytest.skip("CliffordBackend not defined for Tensorflow engine.") - clifford = random_clifford(nqubits, backend=backend) + clifford = random_clifford(nqubits, seed=10, backend=backend) symplectic_matrix_original = Clifford.from_circuit( clifford, engine=backend From 90826ff1cd2804857de7ecc67489941f5cf7e09a Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Tue, 13 Feb 2024 17:00:32 +0400 Subject: [PATCH 178/200] backend agnostic matrix definitions --- src/qibo/backends/npmatrices.py | 78 ++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index 12600e8b39..ba7f14640d 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -17,51 +17,53 @@ def _cast(self, x, dtype): @cached_property def H(self): - return self.np.array([[1, 1], [1, -1]], dtype=self.dtype) / self.np.sqrt(2) + return self._cast([[1, 1], [1, -1]], dtype=self.dtype) / self.np.sqrt(2) @cached_property def X(self): - return self.np.array([[0, 1], [1, 0]], dtype=self.dtype) + return self._cast([[0, 1], [1, 0]], dtype=self.dtype) @cached_property def Y(self): - return self.np.array([[0, -1j], [1j, 0]], dtype=self.dtype) + return self._cast([[0, -1j], [1j, 0]], dtype=self.dtype) @cached_property def Z(self): - return self.np.array([[1, 0], [0, -1]], dtype=self.dtype) + return self._cast([[1, 0], [0, -1]], dtype=self.dtype) @cached_property def SX(self): - return self.np.array([[1 + 1j, 1 - 1j], [1 - 1j, 1 + 1j]], dtype=self.dtype) / 2 + return self._cast([[1 + 1j, 1 - 1j], [1 - 1j, 1 + 1j]], dtype=self.dtype) / 2 @cached_property def SXDG(self): - return self.np.transpose(self.np.conj(self.SX)) + return self._cast([[1 - 1j, 1 + 1j], [1 + 1j, 1 - 1j]], dtype=self.dtype) / 2 @cached_property def S(self): - return self.np.array([[1, 0], [0, 1j]], dtype=self.dtype) + return self._cast([[1, 0], [0, 1j]], dtype=self.dtype) @cached_property def SDG(self): - return self.np.conj(self.S) + return self._cast([[1, 0], [0, -1j]], dtype=self.dtype) @cached_property def T(self): - return self.np.array( + return self._cast( [[1, 0], [0, self.np.exp(1j * self.np.pi / 4.0)]], dtype=self.dtype ) @cached_property def TDG(self): - return self.np.conj(self.T) + return self._cast( + [[1, 0], [0, self.np.exp(-1j * self.np.pi / 4.0)]], dtype=self.dtype + ) def I(self, n=2): - return self.np.eye(n, dtype=self.dtype) + return self._cast(self.np.eye(n, dtype=self.dtype), dtype=self.dtype) def Align(self, n=2): - return self.I(n) + return self._cast(self.I(n), dtype=self.dtype) def M(self): # pragma: no cover raise_error(NotImplementedError) @@ -98,9 +100,10 @@ def U2(self, phi, lam): eplus = self.np.exp(1j * (phi + lam) / 2.0) eminus = self.np.exp(1j * (phi - lam) / 2.0) return self._cast( - [[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]], + [[self.np.conj(eplus), -self.np.conj(eminus)], [eminus, eplus]] + / self.np.sqrt(2), dtype=self.dtype, - ) / self.np.sqrt(2) + ) def U3(self, theta, phi, lam): cost = self.np.cos(theta / 2) @@ -116,24 +119,26 @@ def U3(self, theta, phi, lam): ) def U1q(self, theta, phi): - return self.U3(theta, phi - self.np.pi / 2, self.np.pi / 2 - phi) + return self._cast( + self.U3(theta, phi - self.np.pi / 2, self.np.pi / 2 - phi), dtype=self.dtype + ) @cached_property def CNOT(self): - return self.np.array( + return self._cast( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]], dtype=self.dtype ) @cached_property def CY(self): - return self.np.array( + return self._cast( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]], dtype=self.dtype, ) @cached_property def CZ(self): - return self.np.array( + return self._cast( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]], dtype=self.dtype ) @@ -141,7 +146,7 @@ def CZ(self): def CSX(self): a = (1 + 1j) / 2 b = self.np.conj(a) - return self.np.array( + return self._cast( [ [1, 0, 0, 0], [0, 1, 0, 0], @@ -153,7 +158,17 @@ def CSX(self): @cached_property def CSXDG(self): - return self.np.transpose(self.np.conj(self.CSX)) + a = (1 - 1j) / 2 + b = self.np.conj(a) + return self._cast( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, a, b], + [0, 0, b, a], + ], + dtype=self.dtype, + ) def CRX(self, theta): cos = self.np.cos(theta / 2.0) + 0j @@ -218,19 +233,19 @@ def CU3(self, theta, phi, lam): @cached_property def SWAP(self): - return self.np.array( + return self._cast( [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=self.dtype ) @cached_property def iSWAP(self): - return self.np.array( + return self._cast( [[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]], dtype=self.dtype ) @cached_property def SiSWAP(self): - return self.np.array( + return self._cast( [ [1, 0, 0, 0], [0, 1 / self.np.sqrt(2), 1j / self.np.sqrt(2), 0], @@ -242,7 +257,7 @@ def SiSWAP(self): @cached_property def SiSWAPDG(self): - return self.np.array( + return self._cast( [ [1, 0, 0, 0], [0, 1 / self.np.sqrt(2), -1j / self.np.sqrt(2), 0], @@ -254,7 +269,7 @@ def SiSWAPDG(self): @cached_property def FSWAP(self): - return self.np.array( + return self._cast( [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, -1]], dtype=self.dtype ) @@ -277,7 +292,7 @@ def SYC(self): cost = self.np.cos(self.np.pi / 2) + 0j isint = -1j * self.np.sin(self.np.pi / 2) phase = self.np.exp(-1j * self.np.pi / 6) - return self.np.array( + return self._cast( [ [1, 0, 0, 0], [0, cost, isint, 0], @@ -392,14 +407,14 @@ def RBS(self, theta): @cached_property def ECR(self): - return self.np.array( + return self._cast( [[0, 0, 1, 1j], [0, 0, 1j, 1], [1, -1j, 0, 0], [-1j, 1, 0, 0]], dtype=self.dtype, ) / self.np.sqrt(2) @cached_property def TOFFOLI(self): - return self.np.array( + return self._cast( [ [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], @@ -409,13 +424,14 @@ def TOFFOLI(self): [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0], - ] + ], + dtype=self.dtype, ) def DEUTSCH(self, theta): sin = self.np.sin(theta) + 0j # 0j necessary for right tensorflow dtype - cos = self.np.cos(theta) - return self.np.array( + cos = self.np.cos(theta) + 0j + return self._cast( [ [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], From 0a1407f3f0d77ad35c655e78fdd4944a048567b2 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 13 Feb 2024 19:17:15 +0400 Subject: [PATCH 179/200] two seeds --- tests/test_quantum_info_clifford.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_quantum_info_clifford.py b/tests/test_quantum_info_clifford.py index d6e12b3a36..cc32aadcde 100644 --- a/tests/test_quantum_info_clifford.py +++ b/tests/test_quantum_info_clifford.py @@ -62,13 +62,14 @@ def test_clifford_from_circuit(backend, measurement): backend.assert_allclose(obj.probabilities(), result.probabilities()) +@pytest.mark.parametrize("seed", [None, 10]) @pytest.mark.parametrize("algorithm", ["AG04", "BM20"]) @pytest.mark.parametrize("nqubits", [1, 2, 3, 10, 50]) def test_clifford_to_circuit(backend, nqubits, algorithm): if backend.__class__.__name__ == "TensorflowBackend": pytest.skip("CliffordBackend not defined for Tensorflow engine.") - clifford = random_clifford(nqubits, seed=10, backend=backend) + clifford = random_clifford(nqubits, seed=seed, backend=backend) symplectic_matrix_original = Clifford.from_circuit( clifford, engine=backend From cf95b450820ccd5a6be90107fe17107eb26de432 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Tue, 13 Feb 2024 19:17:57 +0400 Subject: [PATCH 180/200] fix test --- tests/test_quantum_info_clifford.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quantum_info_clifford.py b/tests/test_quantum_info_clifford.py index cc32aadcde..7ca2577087 100644 --- a/tests/test_quantum_info_clifford.py +++ b/tests/test_quantum_info_clifford.py @@ -65,7 +65,7 @@ def test_clifford_from_circuit(backend, measurement): @pytest.mark.parametrize("seed", [None, 10]) @pytest.mark.parametrize("algorithm", ["AG04", "BM20"]) @pytest.mark.parametrize("nqubits", [1, 2, 3, 10, 50]) -def test_clifford_to_circuit(backend, nqubits, algorithm): +def test_clifford_to_circuit(backend, nqubits, algorithm, seed): if backend.__class__.__name__ == "TensorflowBackend": pytest.skip("CliffordBackend not defined for Tensorflow engine.") From f4ca928850b59777a0c102a0d6d1518297eb0688 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 14 Feb 2024 08:32:04 +0400 Subject: [PATCH 181/200] fix seed --- tests/test_quantum_info_clifford.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quantum_info_clifford.py b/tests/test_quantum_info_clifford.py index 7ca2577087..ebde9aff5c 100644 --- a/tests/test_quantum_info_clifford.py +++ b/tests/test_quantum_info_clifford.py @@ -62,7 +62,7 @@ def test_clifford_from_circuit(backend, measurement): backend.assert_allclose(obj.probabilities(), result.probabilities()) -@pytest.mark.parametrize("seed", [None, 10]) +@pytest.mark.parametrize("seed", [1, 10]) @pytest.mark.parametrize("algorithm", ["AG04", "BM20"]) @pytest.mark.parametrize("nqubits", [1, 2, 3, 10, 50]) def test_clifford_to_circuit(backend, nqubits, algorithm, seed): From 19583bcc2931c989bb6802c836e0cf9b96f87dae Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 14 Feb 2024 13:05:02 +0400 Subject: [PATCH 182/200] fix `tensorflow` issues --- src/qibo/backends/npmatrices.py | 36 +++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index ba7f14640d..fd7c78db1e 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -25,7 +25,7 @@ def X(self): @cached_property def Y(self): - return self._cast([[0, -1j], [1j, 0]], dtype=self.dtype) + return self._cast([[0j, -1j], [1j, 0j]], dtype=self.dtype) @cached_property def Z(self): @@ -41,11 +41,11 @@ def SXDG(self): @cached_property def S(self): - return self._cast([[1, 0], [0, 1j]], dtype=self.dtype) + return self._cast([[1 + 0j, 0j], [0j, 1j]], dtype=self.dtype) @cached_property def SDG(self): - return self._cast([[1, 0], [0, -1j]], dtype=self.dtype) + return self._cast([[1 + 0j, 0j], [0j, -1j]], dtype=self.dtype) @cached_property def T(self): @@ -132,7 +132,12 @@ def CNOT(self): @cached_property def CY(self): return self._cast( - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]], + [ + [1 + 0j, 0j, 0j, 0j], + [0j, 1 + 0j, 0j, 0j], + [0j, 0j, 0j, -1j], + [0j, 0j, 1j, 0j], + ], dtype=self.dtype, ) @@ -247,10 +252,10 @@ def iSWAP(self): def SiSWAP(self): return self._cast( [ - [1, 0, 0, 0], - [0, 1 / self.np.sqrt(2), 1j / self.np.sqrt(2), 0], - [0, 1j / self.np.sqrt(2), 1 / self.np.sqrt(2), 0], - [0, 0, 0, 1], + [1 + 0j, 0j, 0j, 0j], + [0j, 1 / self.np.sqrt(2) + 0j, 1j / self.np.sqrt(2), 0j], + [0j, 1j / self.np.sqrt(2), 1 / self.np.sqrt(2) + 0j, 0j], + [0j, 0j, 0j, 1 + 0j], ], dtype=self.dtype, ) @@ -259,10 +264,10 @@ def SiSWAP(self): def SiSWAPDG(self): return self._cast( [ - [1, 0, 0, 0], - [0, 1 / self.np.sqrt(2), -1j / self.np.sqrt(2), 0], - [0, -1j / self.np.sqrt(2), 1 / self.np.sqrt(2), 0], - [0, 0, 0, 1], + [1 + 0j, 0j, 0j, 0j], + [0j, 1 / self.np.sqrt(2) + 0j, -1j / self.np.sqrt(2), 0j], + [0j, -1j / self.np.sqrt(2), 1 / self.np.sqrt(2) + 0j, 0j], + [0j, 0j, 0j, 1 + 0j], ], dtype=self.dtype, ) @@ -408,7 +413,12 @@ def RBS(self, theta): @cached_property def ECR(self): return self._cast( - [[0, 0, 1, 1j], [0, 0, 1j, 1], [1, -1j, 0, 0], [-1j, 1, 0, 0]], + [ + [0j, 0j, 1 + 0j, 1j], + [0j, 0j, 1j, 1 + 0j], + [1 + 0j, -1j, 0j, 0j], + [-1j, 1 + 0j, 0j, 0j], + ], dtype=self.dtype, ) / self.np.sqrt(2) From ee34da2f25e2d0a2b9f20b48a911c7982a18a699 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 14 Feb 2024 14:58:39 +0400 Subject: [PATCH 183/200] avoid raise_error in block decomposition --- src/qibo/transpiler/blocks.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/qibo/transpiler/blocks.py b/src/qibo/transpiler/blocks.py index 5b881d9e06..6e2b1122a2 100644 --- a/src/qibo/transpiler/blocks.py +++ b/src/qibo/transpiler/blocks.py @@ -65,8 +65,8 @@ def fuse(self, block, name: Optional[str] = None): (:class:`qibo.transpiler.blocks.Block`): fusion of the two input blocks. """ if not self.qubits == block.qubits: - raise BlockingError( - "In order to fuse two blocks their qubits must coincide." + raise_error( + BlockingError, "In order to fuse two blocks their qubits must coincide." ) return Block(qubits=self.qubits, gates=self.gates + block.gates, name=name) @@ -200,12 +200,11 @@ def block_decomposition(circuit: Circuit, fuse: bool = True): remove_list = [first_block] if len(initial_blocks[1:]) > 0: for second_block in initial_blocks[1:]: - try: + if second_block.qubits == first_block.qubits: first_block = first_block.fuse(second_block) remove_list.append(second_block) - except BlockingError: - if not first_block.commute(second_block): - break + elif not first_block.commute(second_block): + break blocks.append(first_block) _remove_gates(initial_blocks, remove_list) From 783f9082d5aa7beb26f97d227332059bf298951d Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 14 Feb 2024 14:40:55 +0400 Subject: [PATCH 184/200] ... --- src/qibo/backends/npmatrices.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index fd7c78db1e..09a794cef6 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -163,6 +163,7 @@ def CSX(self): @cached_property def CSXDG(self): + # return self.np.conj(self.CSX) a = (1 - 1j) / 2 b = self.np.conj(a) return self._cast( From 2984d2dc7fd38e08442d0c0f2e5340744a27254e Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 14 Feb 2024 15:06:04 +0400 Subject: [PATCH 185/200] test with qibojit update --- pyproject.toml | 6 +++--- src/qibo/backends/npmatrices.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bb2b539695..bdcd37e76b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,7 @@ dill = "^0.3.6" pytest-cov = "^4.0.0" pylint = "^3.0.3" matplotlib = "^3.7.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git", brach = "sxdg" } tensorflow = { version = "^2.14.1", markers = "sys_platform == 'linux'" } [tool.poe.tasks] @@ -79,7 +79,7 @@ optional = true [tool.poetry.group.cuda11.dependencies] cupy-cuda11x = "^12.0.0" cuquantum-python-cu11 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git"} [tool.poetry.group.cuda12] optional = true @@ -87,7 +87,7 @@ optional = true [tool.poetry.group.cuda12.dependencies] cupy-cuda12x = "^12.0.0" cuquantum-python-cu12 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git"} [tool.pylint.reports] output-format = "colorized" diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index 09a794cef6..fd7c78db1e 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -163,7 +163,6 @@ def CSX(self): @cached_property def CSXDG(self): - # return self.np.conj(self.CSX) a = (1 - 1j) / 2 b = self.np.conj(a) return self._cast( From ba5ae244110f7b1dc29d2589e8b0a1466b055e13 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 14 Feb 2024 16:10:14 +0400 Subject: [PATCH 186/200] update tests dependency --- poetry.lock | 1448 ++++++++++++++++++++++++------------------------ pyproject.toml | 6 +- 2 files changed, 736 insertions(+), 718 deletions(-) diff --git a/poetry.lock b/poetry.lock index d9f70f1364..ef54e2c382 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,24 +2,24 @@ [[package]] name = "absl-py" -version = "2.0.0" +version = "2.1.0" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." optional = false python-versions = ">=3.7" files = [ - {file = "absl-py-2.0.0.tar.gz", hash = "sha256:d9690211c5fcfefcdd1a45470ac2b5c5acd45241c3af71eed96bc5441746c0d5"}, - {file = "absl_py-2.0.0-py3-none-any.whl", hash = "sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3"}, + {file = "absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff"}, + {file = "absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308"}, ] [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] @@ -46,13 +46,13 @@ trio = ["trio (>=0.23)"] [[package]] name = "astroid" -version = "3.0.2" +version = "3.0.3" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.8.0" files = [ - {file = "astroid-3.0.2-py3-none-any.whl", hash = "sha256:d6e62862355f60e716164082d6b4b041d38e2a8cf1c7cd953ded5108bac8ff5c"}, - {file = "astroid-3.0.2.tar.gz", hash = "sha256:4a61cf0a59097c7bb52689b0fd63717cd2a8a14dc9f1eee97b82d814881c8c91"}, + {file = "astroid-3.0.3-py3-none-any.whl", hash = "sha256:92fcf218b89f449cdf9f7b39a269f8d5d617b27be68434912e11e79203963a17"}, + {file = "astroid-3.0.3.tar.gz", hash = "sha256:4148645659b08b70d72460ed1921158027a9e53ae8b7234149b1400eddacbb93"}, ] [package.dependencies] @@ -124,19 +124,22 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] @@ -171,13 +174,13 @@ files = [ [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -557,13 +560,13 @@ files = [ [[package]] name = "comm" -version = "0.2.0" +version = "0.2.1" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" files = [ - {file = "comm-0.2.0-py3-none-any.whl", hash = "sha256:2da8d9ebb8dd7bfc247adaff99f24dce705638a8042b85cb995066793e391001"}, - {file = "comm-0.2.0.tar.gz", hash = "sha256:a517ea2ca28931c7007a7a99c562a0fa5883cfb48963140cf642c41c948498be"}, + {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, + {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, ] [package.dependencies] @@ -651,63 +654,63 @@ test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.3.4" +version = "7.4.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aff2bd3d585969cc4486bfc69655e862028b689404563e6b549e6a8244f226df"}, - {file = "coverage-7.3.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4353923f38d752ecfbd3f1f20bf7a3546993ae5ecd7c07fd2f25d40b4e54571"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea473c37872f0159294f7073f3fa72f68b03a129799f3533b2bb44d5e9fa4f82"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5214362abf26e254d749fc0c18af4c57b532a4bfde1a057565616dd3b8d7cc94"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f99b7d3f7a7adfa3d11e3a48d1a91bb65739555dd6a0d3fa68aa5852d962e5b1"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:74397a1263275bea9d736572d4cf338efaade2de9ff759f9c26bcdceb383bb49"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f154bd866318185ef5865ace5be3ac047b6d1cc0aeecf53bf83fe846f4384d5d"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e0d84099ea7cba9ff467f9c6f747e3fc3906e2aadac1ce7b41add72e8d0a3712"}, - {file = "coverage-7.3.4-cp310-cp310-win32.whl", hash = "sha256:3f477fb8a56e0c603587b8278d9dbd32e54bcc2922d62405f65574bd76eba78a"}, - {file = "coverage-7.3.4-cp310-cp310-win_amd64.whl", hash = "sha256:c75738ce13d257efbb6633a049fb2ed8e87e2e6c2e906c52d1093a4d08d67c6b"}, - {file = "coverage-7.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:997aa14b3e014339d8101b9886063c5d06238848905d9ad6c6eabe533440a9a7"}, - {file = "coverage-7.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a9c5bc5db3eb4cd55ecb8397d8e9b70247904f8eca718cc53c12dcc98e59fc8"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27ee94f088397d1feea3cb524e4313ff0410ead7d968029ecc4bc5a7e1d34fbf"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ce03e25e18dd9bf44723e83bc202114817f3367789052dc9e5b5c79f40cf59d"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85072e99474d894e5df582faec04abe137b28972d5e466999bc64fc37f564a03"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a877810ef918d0d345b783fc569608804f3ed2507bf32f14f652e4eaf5d8f8d0"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9ac17b94ab4ca66cf803f2b22d47e392f0977f9da838bf71d1f0db6c32893cb9"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:36d75ef2acab74dc948d0b537ef021306796da551e8ac8b467810911000af66a"}, - {file = "coverage-7.3.4-cp311-cp311-win32.whl", hash = "sha256:47ee56c2cd445ea35a8cc3ad5c8134cb9bece3a5cb50bb8265514208d0a65928"}, - {file = "coverage-7.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:11ab62d0ce5d9324915726f611f511a761efcca970bd49d876cf831b4de65be5"}, - {file = "coverage-7.3.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:33e63c578f4acce1b6cd292a66bc30164495010f1091d4b7529d014845cd9bee"}, - {file = "coverage-7.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:782693b817218169bfeb9b9ba7f4a9f242764e180ac9589b45112571f32a0ba6"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c4277ddaad9293454da19121c59f2d850f16bcb27f71f89a5c4836906eb35ef"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d892a19ae24b9801771a5a989fb3e850bd1ad2e2b6e83e949c65e8f37bc67a1"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3024ec1b3a221bd10b5d87337d0373c2bcaf7afd86d42081afe39b3e1820323b"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1c3e9d2bbd6f3f79cfecd6f20854f4dc0c6e0ec317df2b265266d0dc06535f1"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e91029d7f151d8bf5ab7d8bfe2c3dbefd239759d642b211a677bc0709c9fdb96"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6879fe41c60080aa4bb59703a526c54e0412b77e649a0d06a61782ecf0853ee1"}, - {file = "coverage-7.3.4-cp312-cp312-win32.whl", hash = "sha256:fd2f8a641f8f193968afdc8fd1697e602e199931012b574194052d132a79be13"}, - {file = "coverage-7.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:d1d0ce6c6947a3a4aa5479bebceff2c807b9f3b529b637e2b33dea4468d75fc7"}, - {file = "coverage-7.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:36797b3625d1da885b369bdaaa3b0d9fb8865caed3c2b8230afaa6005434aa2f"}, - {file = "coverage-7.3.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfed0ec4b419fbc807dec417c401499ea869436910e1ca524cfb4f81cf3f60e7"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f97ff5a9fc2ca47f3383482858dd2cb8ddbf7514427eecf5aa5f7992d0571429"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607b6c6b35aa49defaebf4526729bd5238bc36fe3ef1a417d9839e1d96ee1e4c"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8e258dcc335055ab59fe79f1dec217d9fb0cdace103d6b5c6df6b75915e7959"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a02ac7c51819702b384fea5ee033a7c202f732a2a2f1fe6c41e3d4019828c8d3"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b710869a15b8caf02e31d16487a931dbe78335462a122c8603bb9bd401ff6fb2"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6a23ae9348a7a92e7f750f9b7e828448e428e99c24616dec93a0720342f241d"}, - {file = "coverage-7.3.4-cp38-cp38-win32.whl", hash = "sha256:758ebaf74578b73f727acc4e8ab4b16ab6f22a5ffd7dd254e5946aba42a4ce76"}, - {file = "coverage-7.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:309ed6a559bc942b7cc721f2976326efbfe81fc2b8f601c722bff927328507dc"}, - {file = "coverage-7.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aefbb29dc56317a4fcb2f3857d5bce9b881038ed7e5aa5d3bcab25bd23f57328"}, - {file = "coverage-7.3.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:183c16173a70caf92e2dfcfe7c7a576de6fa9edc4119b8e13f91db7ca33a7923"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a4184dcbe4f98d86470273e758f1d24191ca095412e4335ff27b417291f5964"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93698ac0995516ccdca55342599a1463ed2e2d8942316da31686d4d614597ef9"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb220b3596358a86361139edce40d97da7458412d412e1e10c8e1970ee8c09ab"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5b14abde6f8d969e6b9dd8c7a013d9a2b52af1235fe7bebef25ad5c8f47fa18"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:610afaf929dc0e09a5eef6981edb6a57a46b7eceff151947b836d869d6d567c1"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d6ed790728fb71e6b8247bd28e77e99d0c276dff952389b5388169b8ca7b1c28"}, - {file = "coverage-7.3.4-cp39-cp39-win32.whl", hash = "sha256:c15fdfb141fcf6a900e68bfa35689e1256a670db32b96e7a931cab4a0e1600e5"}, - {file = "coverage-7.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:38d0b307c4d99a7aca4e00cad4311b7c51b7ac38fb7dea2abe0d182dd4008e05"}, - {file = "coverage-7.3.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b1e0f25ae99cf247abfb3f0fac7ae25739e4cd96bf1afa3537827c576b4847e5"}, - {file = "coverage-7.3.4.tar.gz", hash = "sha256:020d56d2da5bc22a0e00a5b0d54597ee91ad72446fa4cf1b97c35022f6b6dbf0"}, + {file = "coverage-7.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7"}, + {file = "coverage-7.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b"}, + {file = "coverage-7.4.1-cp310-cp310-win32.whl", hash = "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016"}, + {file = "coverage-7.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6"}, + {file = "coverage-7.4.1-cp311-cp311-win32.whl", hash = "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5"}, + {file = "coverage-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc"}, + {file = "coverage-7.4.1-cp312-cp312-win32.whl", hash = "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74"}, + {file = "coverage-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad"}, + {file = "coverage-7.4.1-cp38-cp38-win32.whl", hash = "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042"}, + {file = "coverage-7.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35"}, + {file = "coverage-7.4.1-cp39-cp39-win32.whl", hash = "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c"}, + {file = "coverage-7.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a"}, + {file = "coverage-7.4.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166"}, + {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"}, ] [package.dependencies] @@ -854,7 +857,6 @@ python-versions = "*" files = [ {file = "cutensor_cu11-1.7.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:c5598670f4f31906d725f5ea852f0df675522e3ff5a7bf886057eab36497062d"}, {file = "cutensor_cu11-1.7.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:67b6c7427d9ab50cb82e01360948bd1b23d73775b5767ab92071c7afcfec4b8b"}, - {file = "cutensor_cu11-1.7.0-py3-none-win_amd64.whl", hash = "sha256:d173b3d0fd51cf761b371a4d4be9a3afd3ef230a55ae4336ae31e905336480e1"}, ] [[package]] @@ -866,7 +868,6 @@ python-versions = "*" files = [ {file = "cutensor_cu12-1.7.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:515caa2406e09ffe9c6524328b7da2106169811665f7684836052753a30dda27"}, {file = "cutensor_cu12-1.7.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:29bdde551788fd3a611992026a5bb422831069e38fd44ab920af5aa00cffa12c"}, - {file = "cutensor_cu12-1.7.0-py3-none-win_amd64.whl", hash = "sha256:e1a9a759a615a64d1b8c6d2b8ffd925deb805750c28481b1a8310d05f35ce229"}, ] [[package]] @@ -899,32 +900,32 @@ cutensor-cu12 = ">=1.6.1,<2" [[package]] name = "cvxpy" -version = "1.4.1" +version = "1.4.2" description = "A domain-specific language for modeling convex optimization problems in Python." optional = false python-versions = ">=3.8" files = [ - {file = "cvxpy-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:03588055b660c043848f5281fe24dbd21f005b34bd8bd3b56906d8ad457c14ae"}, - {file = "cvxpy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:315609ff96adeda4970471b349bc19d44ff4043e15630cf5ac70c029658fe8fc"}, - {file = "cvxpy-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55e08ffb973d62b3fabc675ad464cb6013ea5ce69799f330b33a084a2e580d8d"}, - {file = "cvxpy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f1482558b785f2db51c76b9c6e91cc85dbd146675b126a799e7d7aab5b15354"}, - {file = "cvxpy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:2f84687d15d11f9b49ca902f20103a2076efd47773c399cace71237ef53cdadc"}, - {file = "cvxpy-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d6bfbd535fdaabc5fa55f28de7a1d40f3a803a27fe3fec86e90700fa159a3afc"}, - {file = "cvxpy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:71a95aaccf22431fd25a63bcb12d583e1b0baeaeb4fafa3e25857cec03b9e2f3"}, - {file = "cvxpy-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bae3bf31e4eb6ed6407f78c6bc3c7bc4b4145cdbbb9ba8c61c3fc541d7067"}, - {file = "cvxpy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41cfaecf86f85162ca53c7be7377b4143e316204fb9b6a7df8b7a08c826e3806"}, - {file = "cvxpy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:edf66010e49b64d3f2dd1a7abde8fa3e615ce7a2b3eb185ab744b0beb3a6adb9"}, - {file = "cvxpy-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6b0f17dca85b2a410e73f5d84b28f35f57a20cfec1b0adc9b16f0f8aabff9961"}, - {file = "cvxpy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9318c4e679b3db470e76e7f23cce362b038bd2d68c4a7326a7c21577ddbdc542"}, - {file = "cvxpy-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46ef722c8d1590875e86360d5781703dfcbd08be73eb98a2fc91a280870064"}, - {file = "cvxpy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57593a852c563ce77bdb075a3e75f23d36d4b3162ebf3199b54cc7fe75088ef2"}, - {file = "cvxpy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:db89b55025514bad821b1f1781bed373cbb6aa22fe84420431efd510dbe7f858"}, - {file = "cvxpy-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:372c0825cc6e6bb03ecc550d83718761a1bbdbbb48010fec6f9718581ebd45b5"}, - {file = "cvxpy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163caffd7f7f27b6cb151f4ccff283068e063c3673158793048761690cbe4bbe"}, - {file = "cvxpy-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f24067c54979b09910aea0a03256247121d8a8169538facf087c1923e9e2701a"}, - {file = "cvxpy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a3ec054279880a9ebf5fd9d2ac4109acf944b8c45ea8b24e461680e34f3d7b5"}, - {file = "cvxpy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:d220a7ee55907da9b55b98e5238d03735118d03b82855ba87b872cb2e6977367"}, - {file = "cvxpy-1.4.1.tar.gz", hash = "sha256:7a9ef34e3c57ff8c844d86f0a3834fb5575af19233947639de0ba577c6122e3e"}, + {file = "cvxpy-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:06231c0b2a65f7c8ba32c2772576c24e93e1ca964444b90c6bad366b9c0a5bdc"}, + {file = "cvxpy-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f257971b007261d53ec7f50618f0c6a511387dd7df6cd686d2647c3fa91da0eb"}, + {file = "cvxpy-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38c2191d4142baac206ac590ba9e5cb1c6e025ac95d0a746692c9cf8d1afd46e"}, + {file = "cvxpy-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9d006f76925127cd42b80e2d98c950a8339f8204b4c23fa25af83d895e95fa"}, + {file = "cvxpy-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:2a09ebd8f7a8b6b5d026d03295daee0780e2f6847fbe6f207e9764045ffbbfc9"}, + {file = "cvxpy-1.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:079fe6aeaeec2ddf6163ff8ca6510afd5c2b66ea391605791a77b51e534b935e"}, + {file = "cvxpy-1.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8419dffcadefc16e6fcbe8a088068c29edb1f28ea90582f075a96f21ae7ff11"}, + {file = "cvxpy-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6551ef3b325d707e98f920dd120ebaa968f3ac3484c21f8567f2081967d26f0"}, + {file = "cvxpy-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea513f4bf83491a1c9e5366faa4ca9fc21ec9522c30bcd55e49de9bb85fe9a2"}, + {file = "cvxpy-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:78560a02607d16fbb26db6306e7ce6d8e4fcda49cf04578d199ac050c2e74daa"}, + {file = "cvxpy-1.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9817cf8da86641e2d322911844e86b8e7b1d93d9b2d57ae6d33e84be430e1e04"}, + {file = "cvxpy-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:32999d550a923c9448d973ef9d3ab75d73e1bdf56102fc32fe7ccb5e0cb5d7a3"}, + {file = "cvxpy-1.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213b465450f4254226e6c18c70e25e911ae2c60176621f1bc2d9a0eb874288db"}, + {file = "cvxpy-1.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec30efa81d1f79f668b0fa6e8ac654047db7a3e844ab16022e1b5dcf52177192"}, + {file = "cvxpy-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:779c19be964f7a586337fd4d017c7a0202bf845e08b04a174850f962b45b2a00"}, + {file = "cvxpy-1.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bb1d6af8406efa1de0408d0a76c248da3185cade49f45c443239772830b7d6bb"}, + {file = "cvxpy-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:63102885fdfd3eae716c042ee7aad9439d0b71ba22e5432c85f0e35056fcb159"}, + {file = "cvxpy-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20015b82117c0253ca803c4e174010067bda0eedb539503ba58b98e00acdd0f2"}, + {file = "cvxpy-1.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f73ff4f0e7bff1e438dc2b02490d7a8e1027c421057a7971b4ca4982c28d60"}, + {file = "cvxpy-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b7cfc6be34b288acade31b58a1e88b119487165d0ed877db9decf7fd676502f6"}, + {file = "cvxpy-1.4.2.tar.gz", hash = "sha256:0a386a5788dbd78b7b20dd071524ec636c8fa72b3628e69f1abc714c8f9811e5"}, ] [package.dependencies] @@ -1011,17 +1012,18 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "dill" -version = "0.3.7" +version = "0.3.8" description = "serialize all of Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, - {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, + {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, + {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, ] [package.extras] graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "docutils" @@ -1050,27 +1052,30 @@ dev-env = ["black (==22.3.0)", "isort (==5.7.*)", "mypy (==0.931.*)", "pylint (= [[package]] name = "ecos" -version = "2.0.12" +version = "2.0.13" description = "This is the Python package for ECOS: Embedded Cone Solver. See Github page for more information." optional = false python-versions = "*" files = [ - {file = "ecos-2.0.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:835298a299c88c207b3402fba60ad9b5688b59bbbf2ac34a46de5b37165d773a"}, - {file = "ecos-2.0.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608bc822ee8e070927ab3519169b13a1a0fe88f3d562212d6b5dbb1039776360"}, - {file = "ecos-2.0.12-cp310-cp310-win_amd64.whl", hash = "sha256:5184a9d8521ad1af90ffcd9902a6fa75c7bc473f37d30d86f97beda1033dfca2"}, - {file = "ecos-2.0.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eba07599084724eedc20b2862d5580eebebb09609f4740baadc78401cb99827c"}, - {file = "ecos-2.0.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4979dc2d1cb6667e371a45a61887068505c1305437eef104ed6ef16f4b6aa0e3"}, - {file = "ecos-2.0.12-cp311-cp311-win_amd64.whl", hash = "sha256:da8fbbca3feb83a9e27075d29b3765417d0c80af8ea83cbdc4a558cae7b564af"}, - {file = "ecos-2.0.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f70e4547966f530fd7715756f7a65d5b9b90b312b9d37f243ef9356c05e7d74c"}, - {file = "ecos-2.0.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:617be25d74222849622b0f82b94a11abcf1fae78ccaf69977b328321ee6ffa0b"}, - {file = "ecos-2.0.12-cp37-cp37m-win_amd64.whl", hash = "sha256:29d00164eaea66ed54697a3b361c575284a8bca54f2623381a0635806c7303a7"}, - {file = "ecos-2.0.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4e86671397d1d2cd7cccff8a9c45be0541b0c60af8b92a0ff3581c9ed869db67"}, - {file = "ecos-2.0.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:858a4dd3177bdc8cc6e362031732f5177b62138a1e4ef91c0dc3c6bd7d2d1248"}, - {file = "ecos-2.0.12-cp38-cp38-win_amd64.whl", hash = "sha256:528b02f53835bd1baeb2e23f8153b8d6cc2b3704e1768be6a1a972f542241670"}, - {file = "ecos-2.0.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e42bd4c19af6e04f76ccc85d941b1f1adc7faeee4d06d482395a6beb7bec895"}, - {file = "ecos-2.0.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6def54336a15b5a49bc3bfcaa36035e8557cae8a4853b17ca84f5a29c93bcaea"}, - {file = "ecos-2.0.12-cp39-cp39-win_amd64.whl", hash = "sha256:7af08941552fce108bd80145cdb6be7fa74477a20bacdac170800442cc7027d4"}, - {file = "ecos-2.0.12.tar.gz", hash = "sha256:f48816d73b87ae325556ea537b7c8743187311403c80e3832035224156337c4e"}, + {file = "ecos-2.0.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a1c1acf33b70f8657c25f07ec8d7b59bb01dbad39f072fa61fc956c2166ed979"}, + {file = "ecos-2.0.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ea88ee2c94192004d6be9c55a3c79f184eaba3bbf31474229045a1b0a8a1536"}, + {file = "ecos-2.0.13-cp310-cp310-win_amd64.whl", hash = "sha256:df8ae7fce79be9e5f79f0511c51a4824795de5154847fabe1a0288bc2ea349d3"}, + {file = "ecos-2.0.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88dd628bc6e77a069165fa5f50340e2856795c28e00e3fce213a04d7c41c584a"}, + {file = "ecos-2.0.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b2c969c7e22fd8a1d1cd0a90f4325d90572da23e2e923b0da6138ce62503d0"}, + {file = "ecos-2.0.13-cp311-cp311-win_amd64.whl", hash = "sha256:936890fb85a186360a5c8f228dd19acb760e234b38c598d0b46ab29644e31dfc"}, + {file = "ecos-2.0.13-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62ed497ab56017f1d7264eb56223826a984462b1d84fb850d10f0bec3490877d"}, + {file = "ecos-2.0.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf2b1384012bee9e58e5a2373905d3644f74a0ea000b307a239366fe7850c29c"}, + {file = "ecos-2.0.13-cp312-cp312-win_amd64.whl", hash = "sha256:2c1ea09069e32185912506f946bb6d1f144841ba1d1cd0217c67f72cbdf7a8fd"}, + {file = "ecos-2.0.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9f4a76a3e1165359e1704ec6b1b89d487858ec0d838d62a7268133d88221914"}, + {file = "ecos-2.0.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c2d4e0d3ada1a619ddd62fbf48ccbe9b738fdbef119945fe2a05566d03b85a"}, + {file = "ecos-2.0.13-cp37-cp37m-win_amd64.whl", hash = "sha256:84c72e1e5ffa41cd38352dcf0a8c25418f5bf04ed76a576db0daaf9a69f5568f"}, + {file = "ecos-2.0.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1979f1f17ec7f1a0fc45964d02d762393f9f427d965fe8a893e7b1476a9023c3"}, + {file = "ecos-2.0.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:059e6c29c89f47a490353e4f9336e96350a5102a97e1d8a2aaff796bcbe50058"}, + {file = "ecos-2.0.13-cp38-cp38-win_amd64.whl", hash = "sha256:30c7d0cce6c830da5b9ea25af0d47b203255639524eb4d03d1331c600958c834"}, + {file = "ecos-2.0.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42c15f1d79eb2ada532e9781b4aeb3ed84b1c7e38239ba4d6502c6a092d5b1"}, + {file = "ecos-2.0.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32fb33185f6dd94a1c798bc481eb86c9f4e832efec91f6ab0584e2fc26fd375e"}, + {file = "ecos-2.0.13-cp39-cp39-win_amd64.whl", hash = "sha256:68995ab12d363576dddb2d1f91ead3b9c8a8ca61f29000f0b1daef1b4e7b5b64"}, + {file = "ecos-2.0.13.tar.gz", hash = "sha256:f2a9dc108ade7faf6f6f4fad245f4714b7293c8767d2a351ead59428a94a98b9"}, ] [package.dependencies] @@ -1122,13 +1127,13 @@ pyrepl = ">=0.8.2" [[package]] name = "fastjsonschema" -version = "2.19.0" +version = "2.19.1" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.19.0-py3-none-any.whl", hash = "sha256:b9fd1a2dd6971dbc7fee280a95bd199ae0dd9ce22beb91cc75e9c1c528a5170e"}, - {file = "fastjsonschema-2.19.0.tar.gz", hash = "sha256:e25df6647e1bc4a26070b700897b07b542ec898dd4f1f6ea013e7f6a88417225"}, + {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, + {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, ] [package.extras] @@ -1231,60 +1236,60 @@ files = [ [[package]] name = "fonttools" -version = "4.47.0" +version = "4.48.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d2404107626f97a221dc1a65b05396d2bb2ce38e435f64f26ed2369f68675d9"}, - {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01f409be619a9a0f5590389e37ccb58b47264939f0e8d58bfa1f3ba07d22671"}, - {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d986b66ff722ef675b7ee22fbe5947a41f60a61a4da15579d5e276d897fbc7fa"}, - {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8acf6dd0434b211b3bd30d572d9e019831aae17a54016629fa8224783b22df8"}, - {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:495369c660e0c27233e3c572269cbe520f7f4978be675f990f4005937337d391"}, - {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c59227d7ba5b232281c26ae04fac2c73a79ad0e236bca5c44aae904a18f14faf"}, - {file = "fonttools-4.47.0-cp310-cp310-win32.whl", hash = "sha256:59a6c8b71a245800e923cb684a2dc0eac19c56493e2f896218fcf2571ed28984"}, - {file = "fonttools-4.47.0-cp310-cp310-win_amd64.whl", hash = "sha256:52c82df66201f3a90db438d9d7b337c7c98139de598d0728fb99dab9fd0495ca"}, - {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:854421e328d47d70aa5abceacbe8eef231961b162c71cbe7ff3f47e235e2e5c5"}, - {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:511482df31cfea9f697930f61520f6541185fa5eeba2fa760fe72e8eee5af88b"}, - {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0e2c88c8c985b7b9a7efcd06511fb0a1fe3ddd9a6cd2895ef1dbf9059719d7"}, - {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7a0a8848726956e9d9fb18c977a279013daadf0cbb6725d2015a6dd57527992"}, - {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e869da810ae35afb3019baa0d0306cdbab4760a54909c89ad8904fa629991812"}, - {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dd23848f877c3754f53a4903fb7a593ed100924f9b4bff7d5a4e2e8a7001ae11"}, - {file = "fonttools-4.47.0-cp311-cp311-win32.whl", hash = "sha256:bf1810635c00f7c45d93085611c995fc130009cec5abdc35b327156aa191f982"}, - {file = "fonttools-4.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:61df4dee5d38ab65b26da8efd62d859a1eef7a34dcbc331299a28e24d04c59a7"}, - {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e3f4d61f3a8195eac784f1d0c16c0a3105382c1b9a74d99ac4ba421da39a8826"}, - {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:174995f7b057e799355b393e97f4f93ef1f2197cbfa945e988d49b2a09ecbce8"}, - {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea592e6a09b71cb7a7661dd93ac0b877a6228e2d677ebacbad0a4d118494c86d"}, - {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40bdbe90b33897d9cc4a39f8e415b0fcdeae4c40a99374b8a4982f127ff5c767"}, - {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:843509ae9b93db5aaf1a6302085e30bddc1111d31e11d724584818f5b698f500"}, - {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9acfa1cdc479e0dde528b61423855913d949a7f7fe09e276228298fef4589540"}, - {file = "fonttools-4.47.0-cp312-cp312-win32.whl", hash = "sha256:66c92ec7f95fd9732550ebedefcd190a8d81beaa97e89d523a0d17198a8bda4d"}, - {file = "fonttools-4.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8fa20748de55d0021f83754b371432dca0439e02847962fc4c42a0e444c2d78"}, - {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c75e19971209fbbce891ebfd1b10c37320a5a28e8d438861c21d35305aedb81c"}, - {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e79f1a3970d25f692bbb8c8c2637e621a66c0d60c109ab48d4a160f50856deff"}, - {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:562681188c62c024fe2c611b32e08b8de2afa00c0c4e72bed47c47c318e16d5c"}, - {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a77a60315c33393b2bd29d538d1ef026060a63d3a49a9233b779261bad9c3f71"}, - {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4fabb8cc9422efae1a925160083fdcbab8fdc96a8483441eb7457235df625bd"}, - {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a78dba8c2a1e9d53a0fb5382979f024200dc86adc46a56cbb668a2249862fda"}, - {file = "fonttools-4.47.0-cp38-cp38-win32.whl", hash = "sha256:e6b968543fde4119231c12c2a953dcf83349590ca631ba8216a8edf9cd4d36a9"}, - {file = "fonttools-4.47.0-cp38-cp38-win_amd64.whl", hash = "sha256:4a9a51745c0439516d947480d4d884fa18bd1458e05b829e482b9269afa655bc"}, - {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62d8ddb058b8e87018e5dc26f3258e2c30daad4c87262dfeb0e2617dd84750e6"}, - {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dde0eab40faaa5476133123f6a622a1cc3ac9b7af45d65690870620323308b4"}, - {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4da089f6dfdb822293bde576916492cd708c37c2501c3651adde39804630538"}, - {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:253bb46bab970e8aae254cebf2ae3db98a4ef6bd034707aa68a239027d2b198d"}, - {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1193fb090061efa2f9e2d8d743ae9850c77b66746a3b32792324cdce65784154"}, - {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:084511482dd265bce6dca24c509894062f0117e4e6869384d853f46c0e6d43be"}, - {file = "fonttools-4.47.0-cp39-cp39-win32.whl", hash = "sha256:97620c4af36e4c849e52661492e31dc36916df12571cb900d16960ab8e92a980"}, - {file = "fonttools-4.47.0-cp39-cp39-win_amd64.whl", hash = "sha256:e77bdf52185bdaf63d39f3e1ac3212e6cfa3ab07d509b94557a8902ce9c13c82"}, - {file = "fonttools-4.47.0-py3-none-any.whl", hash = "sha256:d6477ba902dd2d7adda7f0fd3bfaeb92885d45993c9e1928c9f28fc3961415f7"}, - {file = "fonttools-4.47.0.tar.gz", hash = "sha256:ec13a10715eef0e031858c1c23bfaee6cba02b97558e4a7bfa089dba4a8c2ebf"}, + {file = "fonttools-4.48.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:702ae93058c81f46461dc4b2c79f11d3c3d8fd7296eaf8f75b4ba5bbf813cd5f"}, + {file = "fonttools-4.48.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97f0a49fa6aa2d6205c6f72f4f98b74ef4b9bfdcb06fd78e6fe6c7af4989b63e"}, + {file = "fonttools-4.48.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3260db55f1843e57115256e91247ad9f68cb02a434b51262fe0019e95a98738"}, + {file = "fonttools-4.48.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e740a7602c2bb71e1091269b5dbe89549749a8817dc294b34628ffd8b2bf7124"}, + {file = "fonttools-4.48.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4108b1d247953dd7c90ec8f457a2dec5fceb373485973cc852b14200118a51ee"}, + {file = "fonttools-4.48.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56339ec557f0c342bddd7c175f5e41c45fc21282bee58a86bd9aa322bec715f2"}, + {file = "fonttools-4.48.1-cp310-cp310-win32.whl", hash = "sha256:bff5b38d0e76eb18e0b8abbf35d384e60b3371be92f7be36128ee3e67483b3ec"}, + {file = "fonttools-4.48.1-cp310-cp310-win_amd64.whl", hash = "sha256:f7449493886da6a17472004d3818cc050ba3f4a0aa03fb47972e4fa5578e6703"}, + {file = "fonttools-4.48.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18b35fd1a850ed7233a99bbd6774485271756f717dac8b594958224b54118b61"}, + {file = "fonttools-4.48.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cad5cfd044ea2e306fda44482b3dd32ee47830fa82dfa4679374b41baa294f5f"}, + {file = "fonttools-4.48.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f30e605c7565d0da6f0aec75a30ec372072d016957cd8fc4469721a36ea59b7"}, + {file = "fonttools-4.48.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee76fd81a8571c68841d6ef0da750d5ff08ff2c5f025576473016f16ac3bcf7"}, + {file = "fonttools-4.48.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5057ade278e67923000041e2b195c9ea53e87f227690d499b6a4edd3702f7f01"}, + {file = "fonttools-4.48.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b10633aafc5932995a391ec07eba5e79f52af0003a1735b2306b3dab8a056d48"}, + {file = "fonttools-4.48.1-cp311-cp311-win32.whl", hash = "sha256:0d533f89819f9b3ee2dbedf0fed3825c425850e32bdda24c558563c71be0064e"}, + {file = "fonttools-4.48.1-cp311-cp311-win_amd64.whl", hash = "sha256:d20588466367f05025bb1efdf4e5d498ca6d14bde07b6928b79199c588800f0a"}, + {file = "fonttools-4.48.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0a2417547462e468edf35b32e3dd06a6215ac26aa6316b41e03b8eeaf9f079ea"}, + {file = "fonttools-4.48.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cf5a0cd974f85a80b74785db2d5c3c1fd6cc09a2ba3c837359b2b5da629ee1b0"}, + {file = "fonttools-4.48.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0452fcbfbce752ba596737a7c5ec5cf76bc5f83847ce1781f4f90eab14ece252"}, + {file = "fonttools-4.48.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578c00f93868f64a4102ecc5aa600a03b49162c654676c3fadc33de2ddb88a81"}, + {file = "fonttools-4.48.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:63dc592a16cd08388d8c4c7502b59ac74190b23e16dfc863c69fe1ea74605b68"}, + {file = "fonttools-4.48.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9b58638d8a85e3a1b32ec0a91d9f8171a877b4b81c408d4cb3257d0dee63e092"}, + {file = "fonttools-4.48.1-cp312-cp312-win32.whl", hash = "sha256:d10979ef14a8beaaa32f613bb698743f7241d92f437a3b5e32356dfb9769c65d"}, + {file = "fonttools-4.48.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdfd7557d1bd294a200bd211aa665ca3b02998dcc18f8211a5532da5b8fad5c5"}, + {file = "fonttools-4.48.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3cdb9a92521b81bf717ebccf592bd0292e853244d84115bfb4db0c426de58348"}, + {file = "fonttools-4.48.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b4ec6d42a7555f5ae35f3b805482f0aad0f1baeeef54859492ea3b782959d4a"}, + {file = "fonttools-4.48.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:902e9c4e9928301912f34a6638741b8ae0b64824112b42aaf240e06b735774b1"}, + {file = "fonttools-4.48.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8c8b54bd1420c184a995f980f1a8076f87363e2bb24239ef8c171a369d85a31"}, + {file = "fonttools-4.48.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:12ee86abca46193359ea69216b3a724e90c66ab05ab220d39e3fc068c1eb72ac"}, + {file = "fonttools-4.48.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6978bade7b6c0335095bdd0bd97f8f3d590d2877b370f17e03e0865241694eb5"}, + {file = "fonttools-4.48.1-cp38-cp38-win32.whl", hash = "sha256:bcd77f89fc1a6b18428e7a55dde8ef56dae95640293bfb8f4e929929eba5e2a2"}, + {file = "fonttools-4.48.1-cp38-cp38-win_amd64.whl", hash = "sha256:f40441437b039930428e04fb05ac3a132e77458fb57666c808d74a556779e784"}, + {file = "fonttools-4.48.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0d2b01428f7da26f229a5656defc824427b741e454b4e210ad2b25ed6ea2aed4"}, + {file = "fonttools-4.48.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:df48798f9a4fc4c315ab46e17873436c8746f5df6eddd02fad91299b2af7af95"}, + {file = "fonttools-4.48.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2eb4167bde04e172a93cf22c875d8b0cff76a2491f67f5eb069566215302d45d"}, + {file = "fonttools-4.48.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c900508c46274d32d308ae8e82335117f11aaee1f7d369ac16502c9a78930b0a"}, + {file = "fonttools-4.48.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:594206b31c95fcfa65f484385171fabb4ec69f7d2d7f56d27f17db26b7a31814"}, + {file = "fonttools-4.48.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:292922dc356d7f11f5063b4111a8b719efb8faea92a2a88ed296408d449d8c2e"}, + {file = "fonttools-4.48.1-cp39-cp39-win32.whl", hash = "sha256:4709c5bf123ba10eac210d2d5c9027d3f472591d9f1a04262122710fa3d23199"}, + {file = "fonttools-4.48.1-cp39-cp39-win_amd64.whl", hash = "sha256:63c73b9dd56a94a3cbd2f90544b5fca83666948a9e03370888994143b8d7c070"}, + {file = "fonttools-4.48.1-py3-none-any.whl", hash = "sha256:e3e33862fc5261d46d9aae3544acb36203b1a337d00bdb5d3753aae50dac860e"}, + {file = "fonttools-4.48.1.tar.gz", hash = "sha256:8b8a45254218679c7f1127812761e7854ed5c8e34349aebf581e8c9204e7495a"}, ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0,<5)"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] @@ -1334,13 +1339,13 @@ files = [ [[package]] name = "google-api-core" -version = "2.15.0" +version = "2.17.0" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.15.0.tar.gz", hash = "sha256:abc978a72658f14a2df1e5e12532effe40f94f868f6e23d95133bd6abcca35ca"}, - {file = "google_api_core-2.15.0-py3-none-any.whl", hash = "sha256:2aa56d2be495551e66bbff7f729b790546f87d5c90e74781aa77233bcb395a8a"}, + {file = "google-api-core-2.17.0.tar.gz", hash = "sha256:de7ef0450faec7c75e0aea313f29ac870fdc44cfaec9d6499a9a17305980ef66"}, + {file = "google_api_core-2.17.0-py3-none-any.whl", hash = "sha256:08ed79ed8e93e329de5e3e7452746b734e6bf8438d8d64dd3319d21d3164890c"}, ] [package.dependencies] @@ -1364,13 +1369,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.25.2" +version = "2.27.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.25.2.tar.gz", hash = "sha256:42f707937feb4f5e5a39e6c4f343a17300a459aaf03141457ba505812841cc40"}, - {file = "google_auth-2.25.2-py2.py3-none-any.whl", hash = "sha256:473a8dfd0135f75bb79d878436e568f2695dce456764bf3a02b6f8c540b1d256"}, + {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, + {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, ] [package.dependencies] @@ -1387,13 +1392,13 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-auth-oauthlib" -version = "1.0.0" +version = "1.2.0" description = "Google Authentication Library" optional = false python-versions = ">=3.6" files = [ - {file = "google-auth-oauthlib-1.0.0.tar.gz", hash = "sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5"}, - {file = "google_auth_oauthlib-1.0.0-py2.py3-none-any.whl", hash = "sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb"}, + {file = "google-auth-oauthlib-1.2.0.tar.gz", hash = "sha256:292d2d3783349f2b0734a0a0207b1e1e322ac193c2c09d8f7c613fb7cc501ea8"}, + {file = "google_auth_oauthlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:297c1ce4cb13a99b5834c74a1fe03252e1e499716718b190f56bcb9c4abc4faf"}, ] [package.dependencies] @@ -1437,84 +1442,84 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "grpcio" -version = "1.60.0" +version = "1.60.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.60.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:d020cfa595d1f8f5c6b343530cd3ca16ae5aefdd1e832b777f9f0eb105f5b139"}, - {file = "grpcio-1.60.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b98f43fcdb16172dec5f4b49f2fece4b16a99fd284d81c6bbac1b3b69fcbe0ff"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:20e7a4f7ded59097c84059d28230907cd97130fa74f4a8bfd1d8e5ba18c81491"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452ca5b4afed30e7274445dd9b441a35ece656ec1600b77fff8c216fdf07df43"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43e636dc2ce9ece583b3e2ca41df5c983f4302eabc6d5f9cd04f0562ee8ec1ae"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e306b97966369b889985a562ede9d99180def39ad42c8014628dd3cc343f508"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f897c3b127532e6befdcf961c415c97f320d45614daf84deba0a54e64ea2457b"}, - {file = "grpcio-1.60.0-cp310-cp310-win32.whl", hash = "sha256:b87efe4a380887425bb15f220079aa8336276398dc33fce38c64d278164f963d"}, - {file = "grpcio-1.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:a9c7b71211f066908e518a2ef7a5e211670761651039f0d6a80d8d40054047df"}, - {file = "grpcio-1.60.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:fb464479934778d7cc5baf463d959d361954d6533ad34c3a4f1d267e86ee25fd"}, - {file = "grpcio-1.60.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4b44d7e39964e808b071714666a812049765b26b3ea48c4434a3b317bac82f14"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:90bdd76b3f04bdb21de5398b8a7c629676c81dfac290f5f19883857e9371d28c"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91229d7203f1ef0ab420c9b53fe2ca5c1fbeb34f69b3bc1b5089466237a4a134"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b36a2c6d4920ba88fa98075fdd58ff94ebeb8acc1215ae07d01a418af4c0253"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:297eef542156d6b15174a1231c2493ea9ea54af8d016b8ca7d5d9cc65cfcc444"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:87c9224acba0ad8bacddf427a1c2772e17ce50b3042a789547af27099c5f751d"}, - {file = "grpcio-1.60.0-cp311-cp311-win32.whl", hash = "sha256:95ae3e8e2c1b9bf671817f86f155c5da7d49a2289c5cf27a319458c3e025c320"}, - {file = "grpcio-1.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:467a7d31554892eed2aa6c2d47ded1079fc40ea0b9601d9f79204afa8902274b"}, - {file = "grpcio-1.60.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:a7152fa6e597c20cb97923407cf0934e14224af42c2b8d915f48bc3ad2d9ac18"}, - {file = "grpcio-1.60.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:7db16dd4ea1b05ada504f08d0dca1cd9b926bed3770f50e715d087c6f00ad748"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:b0571a5aef36ba9177e262dc88a9240c866d903a62799e44fd4aae3f9a2ec17e"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fd9584bf1bccdfff1512719316efa77be235469e1e3295dce64538c4773840b"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6a478581b1a1a8fdf3318ecb5f4d0cda41cacdffe2b527c23707c9c1b8fdb55"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:77c8a317f0fd5a0a2be8ed5cbe5341537d5c00bb79b3bb27ba7c5378ba77dbca"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1c30bb23a41df95109db130a6cc1b974844300ae2e5d68dd4947aacba5985aa5"}, - {file = "grpcio-1.60.0-cp312-cp312-win32.whl", hash = "sha256:2aef56e85901c2397bd557c5ba514f84de1f0ae5dd132f5d5fed042858115951"}, - {file = "grpcio-1.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:e381fe0c2aa6c03b056ad8f52f8efca7be29fb4d9ae2f8873520843b6039612a"}, - {file = "grpcio-1.60.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:92f88ca1b956eb8427a11bb8b4a0c0b2b03377235fc5102cb05e533b8693a415"}, - {file = "grpcio-1.60.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:e278eafb406f7e1b1b637c2cf51d3ad45883bb5bd1ca56bc05e4fc135dfdaa65"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:a48edde788b99214613e440fce495bbe2b1e142a7f214cce9e0832146c41e324"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de2ad69c9a094bf37c1102b5744c9aec6cf74d2b635558b779085d0263166454"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:073f959c6f570797272f4ee9464a9997eaf1e98c27cb680225b82b53390d61e6"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c826f93050c73e7769806f92e601e0efdb83ec8d7c76ddf45d514fee54e8e619"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e30be89a75ee66aec7f9e60086fadb37ff8c0ba49a022887c28c134341f7179"}, - {file = "grpcio-1.60.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b0fb2d4801546598ac5cd18e3ec79c1a9af8b8f2a86283c55a5337c5aeca4b1b"}, - {file = "grpcio-1.60.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:9073513ec380434eb8d21970e1ab3161041de121f4018bbed3146839451a6d8e"}, - {file = "grpcio-1.60.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:74d7d9fa97809c5b892449b28a65ec2bfa458a4735ddad46074f9f7d9550ad13"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1434ca77d6fed4ea312901122dc8da6c4389738bf5788f43efb19a838ac03ead"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e61e76020e0c332a98290323ecfec721c9544f5b739fab925b6e8cbe1944cf19"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675997222f2e2f22928fbba640824aebd43791116034f62006e19730715166c0"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5208a57eae445ae84a219dfd8b56e04313445d146873117b5fa75f3245bc1390"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:428d699c8553c27e98f4d29fdc0f0edc50e9a8a7590bfd294d2edb0da7be3629"}, - {file = "grpcio-1.60.0-cp38-cp38-win32.whl", hash = "sha256:83f2292ae292ed5a47cdcb9821039ca8e88902923198f2193f13959360c01860"}, - {file = "grpcio-1.60.0-cp38-cp38-win_amd64.whl", hash = "sha256:705a68a973c4c76db5d369ed573fec3367d7d196673fa86614b33d8c8e9ebb08"}, - {file = "grpcio-1.60.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c193109ca4070cdcaa6eff00fdb5a56233dc7610216d58fb81638f89f02e4968"}, - {file = "grpcio-1.60.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:676e4a44e740deaba0f4d95ba1d8c5c89a2fcc43d02c39f69450b1fa19d39590"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5ff21e000ff2f658430bde5288cb1ac440ff15c0d7d18b5fb222f941b46cb0d2"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c86343cf9ff7b2514dd229bdd88ebba760bd8973dac192ae687ff75e39ebfab"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fd3b3968ffe7643144580f260f04d39d869fcc2cddb745deef078b09fd2b328"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:30943b9530fe3620e3b195c03130396cd0ee3a0d10a66c1bee715d1819001eaf"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b10241250cb77657ab315270b064a6c7f1add58af94befa20687e7c8d8603ae6"}, - {file = "grpcio-1.60.0-cp39-cp39-win32.whl", hash = "sha256:79a050889eb8d57a93ed21d9585bb63fca881666fc709f5d9f7f9372f5e7fd03"}, - {file = "grpcio-1.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a97a681e82bc11a42d4372fe57898d270a2707f36c45c6676e49ce0d5c41353"}, - {file = "grpcio-1.60.0.tar.gz", hash = "sha256:2199165a1affb666aa24adf0c97436686d0a61bc5fc113c037701fb7c7fceb96"}, + {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, + {file = "grpcio-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb"}, + {file = "grpcio-1.60.1-cp310-cp310-win32.whl", hash = "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1"}, + {file = "grpcio-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177"}, + {file = "grpcio-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303"}, + {file = "grpcio-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce"}, + {file = "grpcio-1.60.1-cp311-cp311-win32.whl", hash = "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd"}, + {file = "grpcio-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c"}, + {file = "grpcio-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9"}, + {file = "grpcio-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05"}, + {file = "grpcio-1.60.1-cp312-cp312-win32.whl", hash = "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21"}, + {file = "grpcio-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f"}, + {file = "grpcio-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594"}, + {file = "grpcio-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e"}, + {file = "grpcio-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de"}, + {file = "grpcio-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549"}, + {file = "grpcio-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a"}, + {file = "grpcio-1.60.1-cp38-cp38-win32.whl", hash = "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929"}, + {file = "grpcio-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872"}, + {file = "grpcio-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8"}, + {file = "grpcio-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6"}, + {file = "grpcio-1.60.1-cp39-cp39-win32.whl", hash = "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804"}, + {file = "grpcio-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904"}, + {file = "grpcio-1.60.1.tar.gz", hash = "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.60.0)"] +protobuf = ["grpcio-tools (>=1.60.1)"] [[package]] name = "grpcio-status" -version = "1.60.0" +version = "1.60.1" description = "Status proto mapping for gRPC" optional = false python-versions = ">=3.6" files = [ - {file = "grpcio-status-1.60.0.tar.gz", hash = "sha256:f10e0b6db3adc0fdc244b71962814ee982996ef06186446b5695b9fa635aa1ab"}, - {file = "grpcio_status-1.60.0-py3-none-any.whl", hash = "sha256:7d383fa36e59c1e61d380d91350badd4d12ac56e4de2c2b831b050362c3c572e"}, + {file = "grpcio-status-1.60.1.tar.gz", hash = "sha256:61b5aab8989498e8aa142c20b88829ea5d90d18c18c853b9f9e6d407d37bf8b4"}, + {file = "grpcio_status-1.60.1-py3-none-any.whl", hash = "sha256:3034fdb239185b6e0f3169d08c268c4507481e4b8a434c21311a03d9eb5889a0"}, ] [package.dependencies] googleapis-common-protos = ">=1.5.5" -grpcio = ">=1.60.0" +grpcio = ">=1.60.1" protobuf = ">=4.21.6" [[package]] @@ -1660,13 +1665,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.0" +version = "7.0.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, - {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] @@ -1745,21 +1750,21 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pa [[package]] name = "ipywidgets" -version = "8.1.1" +version = "8.1.2" description = "Jupyter interactive widgets" optional = false python-versions = ">=3.7" files = [ - {file = "ipywidgets-8.1.1-py3-none-any.whl", hash = "sha256:2b88d728656aea3bbfd05d32c747cfd0078f9d7e159cf982433b58ad717eed7f"}, - {file = "ipywidgets-8.1.1.tar.gz", hash = "sha256:40211efb556adec6fa450ccc2a77d59ca44a060f4f9f136833df59c9f538e6e8"}, + {file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"}, + {file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"}, ] [package.dependencies] comm = ">=0.1.3" ipython = ">=6.1.0" -jupyterlab-widgets = ">=3.0.9,<3.1.0" +jupyterlab-widgets = ">=3.0.10,<3.1.0" traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.9,<4.1.0" +widgetsnbextension = ">=4.0.10,<4.1.0" [package.extras] test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] @@ -1880,13 +1885,13 @@ test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pyt [[package]] name = "jupyter-core" -version = "5.5.1" +version = "5.7.1" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.5.1-py3-none-any.whl", hash = "sha256:220dfb00c45f0d780ce132bb7976b58263f81a3ada6e90a9b6823785a424f739"}, - {file = "jupyter_core-5.5.1.tar.gz", hash = "sha256:1553311a97ccd12936037f36b9ab4d6ae8ceea6ad2d5c90d94a909e752178e40"}, + {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, + {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, ] [package.dependencies] @@ -1911,24 +1916,24 @@ files = [ [[package]] name = "jupyterlab-widgets" -version = "3.0.9" +version = "3.0.10" description = "Jupyter interactive widgets for JupyterLab" optional = false python-versions = ">=3.7" files = [ - {file = "jupyterlab_widgets-3.0.9-py3-none-any.whl", hash = "sha256:3cf5bdf5b897bf3bccf1c11873aa4afd776d7430200f765e0686bd352487b58d"}, - {file = "jupyterlab_widgets-3.0.9.tar.gz", hash = "sha256:6005a4e974c7beee84060fdfba341a3218495046de8ae3ec64888e5fe19fdb4c"}, + {file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"}, + {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, ] [[package]] name = "keras" -version = "2.14.0" +version = "2.15.0" description = "Deep learning for humans." optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "keras-2.14.0-py3-none-any.whl", hash = "sha256:d7429d1d2131cc7eb1f2ea2ec330227c7d9d38dab3dfdf2e78defee4ecc43fcd"}, - {file = "keras-2.14.0.tar.gz", hash = "sha256:22788bdbc86d9988794fe9703bb5205141da797c4faeeb59497c58c3d94d34ed"}, + {file = "keras-2.15.0-py3-none-any.whl", hash = "sha256:2dcc6d2e30cf9c951064b63c1f4c404b966c59caf09e01f3549138ec8ee0dd1f"}, + {file = "keras-2.15.0.tar.gz", hash = "sha256:81871d298c064dc4ac6b58440fdae67bfcf47c8d7ad28580fab401834c06a575"}, ] [[package]] @@ -2095,46 +2100,43 @@ files = [ [[package]] name = "llvmlite" -version = "0.41.1" +version = "0.42.0" description = "lightweight wrapper around basic LLVM functionality" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "llvmlite-0.41.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1e1029d47ee66d3a0c4d6088641882f75b93db82bd0e6178f7bd744ebce42b9"}, - {file = "llvmlite-0.41.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:150d0bc275a8ac664a705135e639178883293cf08c1a38de3bbaa2f693a0a867"}, - {file = "llvmlite-0.41.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1eee5cf17ec2b4198b509272cf300ee6577229d237c98cc6e63861b08463ddc6"}, - {file = "llvmlite-0.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd0338da625346538f1173a17cabf21d1e315cf387ca21b294ff209d176e244"}, - {file = "llvmlite-0.41.1-cp310-cp310-win32.whl", hash = "sha256:fa1469901a2e100c17eb8fe2678e34bd4255a3576d1a543421356e9c14d6e2ae"}, - {file = "llvmlite-0.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:2b76acee82ea0e9304be6be9d4b3840208d050ea0dcad75b1635fa06e949a0ae"}, - {file = "llvmlite-0.41.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:210e458723436b2469d61b54b453474e09e12a94453c97ea3fbb0742ba5a83d8"}, - {file = "llvmlite-0.41.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:855f280e781d49e0640aef4c4af586831ade8f1a6c4df483fb901cbe1a48d127"}, - {file = "llvmlite-0.41.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b67340c62c93a11fae482910dc29163a50dff3dfa88bc874872d28ee604a83be"}, - {file = "llvmlite-0.41.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2181bb63ef3c607e6403813421b46982c3ac6bfc1f11fa16a13eaafb46f578e6"}, - {file = "llvmlite-0.41.1-cp311-cp311-win_amd64.whl", hash = "sha256:9564c19b31a0434f01d2025b06b44c7ed422f51e719ab5d24ff03b7560066c9a"}, - {file = "llvmlite-0.41.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5940bc901fb0325970415dbede82c0b7f3e35c2d5fd1d5e0047134c2c46b3281"}, - {file = "llvmlite-0.41.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8b0a9a47c28f67a269bb62f6256e63cef28d3c5f13cbae4fab587c3ad506778b"}, - {file = "llvmlite-0.41.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8afdfa6da33f0b4226af8e64cfc2b28986e005528fbf944d0a24a72acfc9432"}, - {file = "llvmlite-0.41.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8454c1133ef701e8c050a59edd85d238ee18bb9a0eb95faf2fca8b909ee3c89a"}, - {file = "llvmlite-0.41.1-cp38-cp38-win32.whl", hash = "sha256:2d92c51e6e9394d503033ffe3292f5bef1566ab73029ec853861f60ad5c925d0"}, - {file = "llvmlite-0.41.1-cp38-cp38-win_amd64.whl", hash = "sha256:df75594e5a4702b032684d5481db3af990b69c249ccb1d32687b8501f0689432"}, - {file = "llvmlite-0.41.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04725975e5b2af416d685ea0769f4ecc33f97be541e301054c9f741003085802"}, - {file = "llvmlite-0.41.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf14aa0eb22b58c231243dccf7e7f42f7beec48970f2549b3a6acc737d1a4ba4"}, - {file = "llvmlite-0.41.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c32356f669e036eb01016e883b22add883c60739bc1ebee3a1cc0249a50828"}, - {file = "llvmlite-0.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24091a6b31242bcdd56ae2dbea40007f462260bc9bdf947953acc39dffd54f8f"}, - {file = "llvmlite-0.41.1-cp39-cp39-win32.whl", hash = "sha256:880cb57ca49e862e1cd077104375b9d1dfdc0622596dfa22105f470d7bacb309"}, - {file = "llvmlite-0.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:92f093986ab92e71c9ffe334c002f96defc7986efda18397d0f08534f3ebdc4d"}, - {file = "llvmlite-0.41.1.tar.gz", hash = "sha256:f19f767a018e6ec89608e1f6b13348fa2fcde657151137cb64e56d48598a92db"}, + {file = "llvmlite-0.42.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3366938e1bf63d26c34fbfb4c8e8d2ded57d11e0567d5bb243d89aab1eb56098"}, + {file = "llvmlite-0.42.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c35da49666a21185d21b551fc3caf46a935d54d66969d32d72af109b5e7d2b6f"}, + {file = "llvmlite-0.42.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70f44ccc3c6220bd23e0ba698a63ec2a7d3205da0d848804807f37fc243e3f77"}, + {file = "llvmlite-0.42.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763f8d8717a9073b9e0246998de89929071d15b47f254c10eef2310b9aac033d"}, + {file = "llvmlite-0.42.0-cp310-cp310-win_amd64.whl", hash = "sha256:8d90edf400b4ceb3a0e776b6c6e4656d05c7187c439587e06f86afceb66d2be5"}, + {file = "llvmlite-0.42.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ae511caed28beaf1252dbaf5f40e663f533b79ceb408c874c01754cafabb9cbf"}, + {file = "llvmlite-0.42.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81e674c2fe85576e6c4474e8c7e7aba7901ac0196e864fe7985492b737dbab65"}, + {file = "llvmlite-0.42.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb3975787f13eb97629052edb5017f6c170eebc1c14a0433e8089e5db43bcce6"}, + {file = "llvmlite-0.42.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5bece0cdf77f22379f19b1959ccd7aee518afa4afbd3656c6365865f84903f9"}, + {file = "llvmlite-0.42.0-cp311-cp311-win_amd64.whl", hash = "sha256:7e0c4c11c8c2aa9b0701f91b799cb9134a6a6de51444eff5a9087fc7c1384275"}, + {file = "llvmlite-0.42.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:08fa9ab02b0d0179c688a4216b8939138266519aaa0aa94f1195a8542faedb56"}, + {file = "llvmlite-0.42.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b2fce7d355068494d1e42202c7aff25d50c462584233013eb4470c33b995e3ee"}, + {file = "llvmlite-0.42.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebe66a86dc44634b59a3bc860c7b20d26d9aaffcd30364ebe8ba79161a9121f4"}, + {file = "llvmlite-0.42.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d47494552559e00d81bfb836cf1c4d5a5062e54102cc5767d5aa1e77ccd2505c"}, + {file = "llvmlite-0.42.0-cp312-cp312-win_amd64.whl", hash = "sha256:05cb7e9b6ce69165ce4d1b994fbdedca0c62492e537b0cc86141b6e2c78d5888"}, + {file = "llvmlite-0.42.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bdd3888544538a94d7ec99e7c62a0cdd8833609c85f0c23fcb6c5c591aec60ad"}, + {file = "llvmlite-0.42.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0936c2067a67fb8816c908d5457d63eba3e2b17e515c5fe00e5ee2bace06040"}, + {file = "llvmlite-0.42.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a78ab89f1924fc11482209f6799a7a3fc74ddc80425a7a3e0e8174af0e9e2301"}, + {file = "llvmlite-0.42.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7599b65c7af7abbc978dbf345712c60fd596aa5670496561cc10e8a71cebfb2"}, + {file = "llvmlite-0.42.0-cp39-cp39-win_amd64.whl", hash = "sha256:43d65cc4e206c2e902c1004dd5418417c4efa6c1d04df05c6c5675a27e8ca90e"}, + {file = "llvmlite-0.42.0.tar.gz", hash = "sha256:f92b09243c0cc3f457da8b983f67bd8e1295d0f5b3746c7a1861d7a99403854a"}, ] [[package]] name = "markdown" -version = "3.5.1" +version = "3.5.2" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.5.1-py3-none-any.whl", hash = "sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc"}, - {file = "Markdown-3.5.1.tar.gz", hash = "sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd"}, + {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, + {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, ] [package.dependencies] @@ -2146,71 +2148,71 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] @@ -2440,13 +2442,13 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>= [[package]] name = "nbconvert" -version = "7.13.0" +version = "7.16.0" description = "Converting Jupyter Notebooks" optional = false python-versions = ">=3.8" files = [ - {file = "nbconvert-7.13.0-py3-none-any.whl", hash = "sha256:22521cfcc10ba5755e44acb6a70d2bd8a891ce7aed6746481e10cd548b169e19"}, - {file = "nbconvert-7.13.0.tar.gz", hash = "sha256:c6f61c86fca5b28bd17f4f9a308248e59fa2b54919e1589f6cc3575c5dfec2bd"}, + {file = "nbconvert-7.16.0-py3-none-any.whl", hash = "sha256:ad3dc865ea6e2768d31b7eb6c7ab3be014927216a5ece3ef276748dd809054c7"}, + {file = "nbconvert-7.16.0.tar.gz", hash = "sha256:813e6553796362489ae572e39ba1bff978536192fb518e10826b0e8cadf03ec8"}, ] [package.dependencies] @@ -2536,81 +2538,81 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "numba" -version = "0.58.1" +version = "0.59.0" description = "compiling Python code using LLVM" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "numba-0.58.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07f2fa7e7144aa6f275f27260e73ce0d808d3c62b30cff8906ad1dec12d87bbe"}, - {file = "numba-0.58.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7bf1ddd4f7b9c2306de0384bf3854cac3edd7b4d8dffae2ec1b925e4c436233f"}, - {file = "numba-0.58.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bc2d904d0319d7a5857bd65062340bed627f5bfe9ae4a495aef342f072880d50"}, - {file = "numba-0.58.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e79b6cc0d2bf064a955934a2e02bf676bc7995ab2db929dbbc62e4c16551be6"}, - {file = "numba-0.58.1-cp310-cp310-win_amd64.whl", hash = "sha256:81fe5b51532478149b5081311b0fd4206959174e660c372b94ed5364cfb37c82"}, - {file = "numba-0.58.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bcecd3fb9df36554b342140a4d77d938a549be635d64caf8bd9ef6c47a47f8aa"}, - {file = "numba-0.58.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1eaa744f518bbd60e1f7ccddfb8002b3d06bd865b94a5d7eac25028efe0e0ff"}, - {file = "numba-0.58.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bf68df9c307fb0aa81cacd33faccd6e419496fdc621e83f1efce35cdc5e79cac"}, - {file = "numba-0.58.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:55a01e1881120e86d54efdff1be08381886fe9f04fc3006af309c602a72bc44d"}, - {file = "numba-0.58.1-cp311-cp311-win_amd64.whl", hash = "sha256:811305d5dc40ae43c3ace5b192c670c358a89a4d2ae4f86d1665003798ea7a1a"}, - {file = "numba-0.58.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea5bfcf7d641d351c6a80e8e1826eb4a145d619870016eeaf20bbd71ef5caa22"}, - {file = "numba-0.58.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e63d6aacaae1ba4ef3695f1c2122b30fa3d8ba039c8f517784668075856d79e2"}, - {file = "numba-0.58.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6fe7a9d8e3bd996fbe5eac0683227ccef26cba98dae6e5cee2c1894d4b9f16c1"}, - {file = "numba-0.58.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:898af055b03f09d33a587e9425500e5be84fc90cd2f80b3fb71c6a4a17a7e354"}, - {file = "numba-0.58.1-cp38-cp38-win_amd64.whl", hash = "sha256:d3e2fe81fe9a59fcd99cc572002101119059d64d31eb6324995ee8b0f144a306"}, - {file = "numba-0.58.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c765aef472a9406a97ea9782116335ad4f9ef5c9f93fc05fd44aab0db486954"}, - {file = "numba-0.58.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e9356e943617f5e35a74bf56ff6e7cc83e6b1865d5e13cee535d79bf2cae954"}, - {file = "numba-0.58.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:240e7a1ae80eb6b14061dc91263b99dc8d6af9ea45d310751b780888097c1aaa"}, - {file = "numba-0.58.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:45698b995914003f890ad839cfc909eeb9c74921849c712a05405d1a79c50f68"}, - {file = "numba-0.58.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd3dda77955be03ff366eebbfdb39919ce7c2620d86c906203bed92124989032"}, - {file = "numba-0.58.1.tar.gz", hash = "sha256:487ded0633efccd9ca3a46364b40006dbdaca0f95e99b8b83e778d1195ebcbaa"}, + {file = "numba-0.59.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d061d800473fb8fef76a455221f4ad649a53f5e0f96e3f6c8b8553ee6fa98fa"}, + {file = "numba-0.59.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c086a434e7d3891ce5dfd3d1e7ee8102ac1e733962098578b507864120559ceb"}, + {file = "numba-0.59.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9e20736bf62e61f8353fb71b0d3a1efba636c7a303d511600fc57648b55823ed"}, + {file = "numba-0.59.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e86e6786aec31d2002122199486e10bbc0dc40f78d76364cded375912b13614c"}, + {file = "numba-0.59.0-cp310-cp310-win_amd64.whl", hash = "sha256:0307ee91b24500bb7e64d8a109848baf3a3905df48ce142b8ac60aaa406a0400"}, + {file = "numba-0.59.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d540f69a8245fb714419c2209e9af6104e568eb97623adc8943642e61f5d6d8e"}, + {file = "numba-0.59.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1192d6b2906bf3ff72b1d97458724d98860ab86a91abdd4cfd9328432b661e31"}, + {file = "numba-0.59.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90efb436d3413809fcd15298c6d395cb7d98184350472588356ccf19db9e37c8"}, + {file = "numba-0.59.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd3dac45e25d927dcb65d44fb3a973994f5add2b15add13337844afe669dd1ba"}, + {file = "numba-0.59.0-cp311-cp311-win_amd64.whl", hash = "sha256:753dc601a159861808cc3207bad5c17724d3b69552fd22768fddbf302a817a4c"}, + {file = "numba-0.59.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ce62bc0e6dd5264e7ff7f34f41786889fa81a6b860662f824aa7532537a7bee0"}, + {file = "numba-0.59.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8cbef55b73741b5eea2dbaf1b0590b14977ca95a13a07d200b794f8f6833a01c"}, + {file = "numba-0.59.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:70d26ba589f764be45ea8c272caa467dbe882b9676f6749fe6f42678091f5f21"}, + {file = "numba-0.59.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e125f7d69968118c28ec0eed9fbedd75440e64214b8d2eac033c22c04db48492"}, + {file = "numba-0.59.0-cp312-cp312-win_amd64.whl", hash = "sha256:4981659220b61a03c1e557654027d271f56f3087448967a55c79a0e5f926de62"}, + {file = "numba-0.59.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe4d7562d1eed754a7511ed7ba962067f198f86909741c5c6e18c4f1819b1f47"}, + {file = "numba-0.59.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6feb1504bb432280f900deaf4b1dadcee68812209500ed3f81c375cbceab24dc"}, + {file = "numba-0.59.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:944faad25ee23ea9dda582bfb0189fb9f4fc232359a80ab2a028b94c14ce2b1d"}, + {file = "numba-0.59.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5516a469514bfae52a9d7989db4940653a5cbfac106f44cb9c50133b7ad6224b"}, + {file = "numba-0.59.0-cp39-cp39-win_amd64.whl", hash = "sha256:32bd0a41525ec0b1b853da244808f4e5333867df3c43c30c33f89cf20b9c2b63"}, + {file = "numba-0.59.0.tar.gz", hash = "sha256:12b9b064a3e4ad00e2371fc5212ef0396c80f41caec9b5ec391c8b04b6eaf2a8"}, ] [package.dependencies] -llvmlite = "==0.41.*" +llvmlite = "==0.42.*" numpy = ">=1.22,<1.27" [[package]] name = "numpy" -version = "1.26.2" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, - {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, - {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, - {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, - {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, - {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, - {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, - {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, - {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, - {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, - {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] @@ -2649,42 +2651,46 @@ tests = ["pytest", "pytest-cov", "pytest-pep8"] [[package]] name = "osqp" -version = "0.6.3" +version = "0.6.5" description = "OSQP: The Operator Splitting QP Solver" optional = false python-versions = "*" files = [ - {file = "osqp-0.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7d923c836f1d07115057e595245ccc1694ecae730a1affda78fc6f3c8d239"}, - {file = "osqp-0.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dfda08c38c3521012740a73ef782f97dfc54a41deae4b0bc4afd18d0e74da0"}, - {file = "osqp-0.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7eafa3f3e82dd36c52f3f4ef19a95142405c807c272c4b53c5971c53535d7804"}, - {file = "osqp-0.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:3cbb6efdaffb7387dc0037dfe3259d4803e5ad7217e6f20fb605c92953214b9d"}, - {file = "osqp-0.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b2049b2c42565dcaa63ddca1c4028b1fb20aab141453f5d77e8ff5b1a99a2cf"}, - {file = "osqp-0.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:146b89f2cfbf59eaeb2c47e3a312f2034138df78d80ce052364810dc0ef70fc4"}, - {file = "osqp-0.6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0084e3d733c75687d68bc133bc380ce471dfe6f7724af2718a43491782eec8d6"}, - {file = "osqp-0.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:1b573fe1cd0e82239a279c58817c1d365187ef862e928b2b9c828c3c516ad3c2"}, - {file = "osqp-0.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c3951ef505177b858c6cd34de980346014cae3d2234c93db960b12c5885f9a2"}, - {file = "osqp-0.6.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc18f87c9549032c163ce590a5e32079df94ee656c8fb357ba607aa9d78fab81"}, - {file = "osqp-0.6.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07b1a4b538aab629b0fae69f644b7e76f81f94d65230014d482e296dacd046b"}, - {file = "osqp-0.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:60abec3593870990b16f00bd5017096a7091fb00b68d0db3383fc048ca8e55c9"}, - {file = "osqp-0.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b73bdd9589901841af83c5ed6a4092b4fac5a0beff9e32682d8526d1f16a728c"}, - {file = "osqp-0.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d9f611823af4a8b241c86805920e5382cd65c7f94fd3615b4eef999ed94c7c"}, - {file = "osqp-0.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30fbc3b3c028c06a6c5f1e66be7b7106ad48a29e0dc5bd82393f82dd68235ef8"}, - {file = "osqp-0.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fe57e4bde071b388518ecb068f26319506dd9cb107363d3d80c12d2e59fc1e81"}, - {file = "osqp-0.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:41f304d1d7f91af07d8f0b01e5af29ec3bb8824f0102c7fd8b13b497be120da4"}, - {file = "osqp-0.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea7d8c92bcdf4fef98d777f13d39060d425ef2e8778ed487c96a6fa10848cdea"}, - {file = "osqp-0.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f3a3c6d2708868e5e3fe2da300d6523cbf68a3d8734ce9c5043db37391969f5"}, - {file = "osqp-0.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:1c548a0b3691850e7e22f3624a128d8af33416d70a9b5976a47d4d832028dcd8"}, - {file = "osqp-0.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:387e7abd737dfe32c9ec00ad74af25328cdd0d0f634d79530655c040a5cb9590"}, - {file = "osqp-0.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1445e10a94e01698e13c87a7debf6ac1a15f3acd1f8f6340cb1ad945db4732b"}, - {file = "osqp-0.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0441c10f7fe5f46692a9b44a57138977bb112ae3f8127151671968c5d9ec5dbb"}, - {file = "osqp-0.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:b15e65a307fbbabf60248bb9bc204e61d5d4ae64e00427a69e2dad9622f4c29d"}, - {file = "osqp-0.6.3.tar.gz", hash = "sha256:03e460e683ec2ce0f839353ddfa3c4c8ffa509ab8cf6a2b2afbb586fa453e180"}, + {file = "osqp-0.6.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e8024dba07281111af39e71bff6449fb22a37bf3358aa0c7fd1daa6bca692c99"}, + {file = "osqp-0.6.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a68e247f2bbb53e87f1c1ca80ff3fc86b781f771d6da2a2ecd2f6e7492c802f3"}, + {file = "osqp-0.6.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e81e299637eb2342e30eb2df0ec45dc243683af0a71676c9b45b9337bb05da97"}, + {file = "osqp-0.6.5-cp310-cp310-win_amd64.whl", hash = "sha256:42425632927d983cbe935067783b944ebd4959e9eb6611da8401007b66a0c841"}, + {file = "osqp-0.6.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a7b180db09be1c3e3cb4109396b894f481ca9c6e160a530acd71f1769610f96c"}, + {file = "osqp-0.6.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:648f4beff10c16620f3b95e86dee702052d587b847ddbd5d8f71ad39ac36db3a"}, + {file = "osqp-0.6.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7649d56d775662e0a5d1665ed220d585f904d14a49cc6931bf27725bb9c4b2e0"}, + {file = "osqp-0.6.5-cp311-cp311-win_amd64.whl", hash = "sha256:b033b7aec973a655cfec4558e0c4fc92ee9f914bcb0a669e0156398d8ddbef8f"}, + {file = "osqp-0.6.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5c344619465e625aac6d13812d442dd31d4a9ab243e39abb5938c3f6116409b0"}, + {file = "osqp-0.6.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:000ad48aa071ecc4c75ebc39d1291752fe3a9937a30d00fff5dc61663ec67eeb"}, + {file = "osqp-0.6.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a36a40df69db5195fba613341663db2c7dcf977eb75b9578a8fd7682bbe02324"}, + {file = "osqp-0.6.5-cp312-cp312-win_amd64.whl", hash = "sha256:3d8212db7c55af1961ccce4a32fd382bfe34e2198664ea3f81cc47eef8d0f288"}, + {file = "osqp-0.6.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ca7d80c0767b1350cd74e4f1446ec51661152690d38b1382ceccdfccd757afce"}, + {file = "osqp-0.6.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b15e2b96d4d9b2eff37a05405372c69cf17ada3d1e42c5e28cbdbd053189ab5"}, + {file = "osqp-0.6.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a41600e34ece7156606fd3620987fdf224b0a35c857540cb5bf45072f5c022b"}, + {file = "osqp-0.6.5-cp36-cp36m-win_amd64.whl", hash = "sha256:8c38574b35a3ddfb794aafee9bc5a74635160b9fc52bbc89ae6164fe207556de"}, + {file = "osqp-0.6.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d06f614e3be1b1f3cd68569b2dc3628c2fdef1e7c4b992672fe05efb1add9801"}, + {file = "osqp-0.6.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a6b995e0a022bd1c33d20d8846d9a068df89cec288b905b5cdfdb98a2ffae8"}, + {file = "osqp-0.6.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09de9b53e7513ee4ade3024ce9f36ef993d916118d0927cce740d086882ea92c"}, + {file = "osqp-0.6.5-cp37-cp37m-win_amd64.whl", hash = "sha256:1f80f85d515ef29b90fb34f137857e75d4fcf21a715d644f54d2cf9494567fab"}, + {file = "osqp-0.6.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de9b9e96001e8f0b2e474106ac75e220fd9279e1635b107b836a6035795e8d07"}, + {file = "osqp-0.6.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fe545d7a87a46cfc57dfb9f0aa2788d2f29e0c71dc1ac57e92f9c9d93064753"}, + {file = "osqp-0.6.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49ab020b5fd7abb5da99e01e47bf81f817ba1df6895e3d3ba4893722cc24d9b6"}, + {file = "osqp-0.6.5-cp38-cp38-win_amd64.whl", hash = "sha256:5d1b5ed6fc4faea94117a0abe140fefe980449b29d3907bd2e6ec1c18eca3d43"}, + {file = "osqp-0.6.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dca127b7a333ce53fb430fc441b2e0aee2df619693d967277a8f8fd095e95007"}, + {file = "osqp-0.6.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ec902844defedf7c5a5ed482b93286d1735a65b71bb27c93e18c929f313c93d"}, + {file = "osqp-0.6.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25a9e1e8f1db38094dc7ee544e603e31fe7bf1b2a3fc75c78c1d39a727e2540"}, + {file = "osqp-0.6.5-cp39-cp39-win_amd64.whl", hash = "sha256:6dce90d8c4ad551489a452573ea819e089e1e1c3b23bbd8f155bb6059ce8ef36"}, + {file = "osqp-0.6.5.tar.gz", hash = "sha256:b2810aee7be2373add8b6c0be5ad99b810288774abca421751cb032d6a5aedef"}, ] [package.dependencies] numpy = ">=1.7" qdldl = "*" -scipy = ">=0.13.2" +scipy = ">=0.13.2,<1.12.0" [[package]] name = "packaging" @@ -2699,36 +2705,40 @@ files = [ [[package]] name = "pandas" -version = "2.1.4" +version = "2.2.0" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bdec823dc6ec53f7a6339a0e34c68b144a7a1fd28d80c260534c39c62c5bf8c9"}, - {file = "pandas-2.1.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:294d96cfaf28d688f30c918a765ea2ae2e0e71d3536754f4b6de0ea4a496d034"}, - {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b728fb8deba8905b319f96447a27033969f3ea1fea09d07d296c9030ab2ed1d"}, - {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00028e6737c594feac3c2df15636d73ace46b8314d236100b57ed7e4b9ebe8d9"}, - {file = "pandas-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:426dc0f1b187523c4db06f96fb5c8d1a845e259c99bda74f7de97bd8a3bb3139"}, - {file = "pandas-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:f237e6ca6421265643608813ce9793610ad09b40154a3344a088159590469e46"}, - {file = "pandas-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7d852d16c270e4331f6f59b3e9aa23f935f5c4b0ed2d0bc77637a8890a5d092"}, - {file = "pandas-2.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7d5f2f54f78164b3d7a40f33bf79a74cdee72c31affec86bfcabe7e0789821"}, - {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa6e92e639da0d6e2017d9ccff563222f4eb31e4b2c3cf32a2a392fc3103c0d"}, - {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d797591b6846b9db79e65dc2d0d48e61f7db8d10b2a9480b4e3faaddc421a171"}, - {file = "pandas-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2d3e7b00f703aea3945995ee63375c61b2e6aa5aa7871c5d622870e5e137623"}, - {file = "pandas-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:dc9bf7ade01143cddc0074aa6995edd05323974e6e40d9dbde081021ded8510e"}, - {file = "pandas-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:482d5076e1791777e1571f2e2d789e940dedd927325cc3cb6d0800c6304082f6"}, - {file = "pandas-2.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8a706cfe7955c4ca59af8c7a0517370eafbd98593155b48f10f9811da440248b"}, - {file = "pandas-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0513a132a15977b4a5b89aabd304647919bc2169eac4c8536afb29c07c23540"}, - {file = "pandas-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9f17f2b6fc076b2a0078862547595d66244db0f41bf79fc5f64a5c4d635bead"}, - {file = "pandas-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:45d63d2a9b1b37fa6c84a68ba2422dc9ed018bdaa668c7f47566a01188ceeec1"}, - {file = "pandas-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:f69b0c9bb174a2342818d3e2778584e18c740d56857fc5cdb944ec8bbe4082cf"}, - {file = "pandas-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3f06bda01a143020bad20f7a85dd5f4a1600112145f126bc9e3e42077c24ef34"}, - {file = "pandas-2.1.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab5796839eb1fd62a39eec2916d3e979ec3130509930fea17fe6f81e18108f6a"}, - {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbaf9e8d3a63a9276d707b4d25930a262341bca9874fcb22eff5e3da5394732"}, - {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebfd771110b50055712b3b711b51bee5d50135429364d0498e1213a7adc2be8"}, - {file = "pandas-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ea107e0be2aba1da619cc6ba3f999b2bfc9669a83554b1904ce3dd9507f0860"}, - {file = "pandas-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:d65148b14788b3758daf57bf42725caa536575da2b64df9964c563b015230984"}, - {file = "pandas-2.1.4.tar.gz", hash = "sha256:fcb68203c833cc735321512e13861358079a96c174a61f5116a1de89c58c0ef7"}, + {file = "pandas-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8108ee1712bb4fa2c16981fba7e68b3f6ea330277f5ca34fa8d557e986a11670"}, + {file = "pandas-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:736da9ad4033aeab51d067fc3bd69a0ba36f5a60f66a527b3d72e2030e63280a"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e0b4fc3ddceb56ec8a287313bc22abe17ab0eb184069f08fc6a9352a769b18"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20404d2adefe92aed3b38da41d0847a143a09be982a31b85bc7dd565bdba0f4e"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ea3ee3f125032bfcade3a4cf85131ed064b4f8dd23e5ce6fa16473e48ebcaf5"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9670b3ac00a387620489dfc1bca66db47a787f4e55911f1293063a78b108df1"}, + {file = "pandas-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a946f210383c7e6d16312d30b238fd508d80d927014f3b33fb5b15c2f895430"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1b438fa26b208005c997e78672f1aa8138f67002e833312e6230f3e57fa87d5"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ce2fbc8d9bf303ce54a476116165220a1fedf15985b09656b4b4275300e920b"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2707514a7bec41a4ab81f2ccce8b382961a29fbe9492eab1305bb075b2b1ff4f"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85793cbdc2d5bc32620dc8ffa715423f0c680dacacf55056ba13454a5be5de88"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfd6c2491dc821b10c716ad6776e7ab311f7df5d16038d0b7458bc0b67dc10f3"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a146b9dcacc3123aa2b399df1a284de5f46287a4ab4fbfc237eac98a92ebcb71"}, + {file = "pandas-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbc1b53c0e1fdf16388c33c3cca160f798d38aea2978004dd3f4d3dec56454c9"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a41d06f308a024981dcaa6c41f2f2be46a6b186b902c94c2674e8cb5c42985bc"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:159205c99d7a5ce89ecfc37cb08ed179de7783737cea403b295b5eda8e9c56d1"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1e1f3861ea9132b32f2133788f3b14911b68102d562715d71bd0013bc45440"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:761cb99b42a69005dec2b08854fb1d4888fdf7b05db23a8c5a099e4b886a2106"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a20628faaf444da122b2a64b1e5360cde100ee6283ae8effa0d8745153809a2e"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f5be5d03ea2073627e7111f61b9f1f0d9625dc3c4d8dda72cc827b0c58a1d042"}, + {file = "pandas-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a626795722d893ed6aacb64d2401d017ddc8a2341b49e0384ab9bf7112bdec30"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f66419d4a41132eb7e9a73dcec9486cf5019f52d90dd35547af11bc58f8637d"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57abcaeda83fb80d447f28ab0cc7b32b13978f6f733875ebd1ed14f8fbc0f4ab"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60f1f7dba3c2d5ca159e18c46a34e7ca7247a73b5dd1a22b6d59707ed6b899a"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb61dc8567b798b969bcc1fc964788f5a68214d333cade8319c7ab33e2b5d88a"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52826b5f4ed658fa2b729264d63f6732b8b29949c7fd234510d57c61dbeadfcd"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bde2bc699dbd80d7bc7f9cab1e23a95c4375de615860ca089f34e7c64f4a8de7"}, + {file = "pandas-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3de918a754bbf2da2381e8a3dcc45eede8cd7775b047b923f9006d5f876802ae"}, + {file = "pandas-2.2.0.tar.gz", hash = "sha256:30b83f7c3eb217fb4d1b494a57a2fda5444f17834f5df2de6b2ffff68dc3c8e2"}, ] [package.dependencies] @@ -2738,41 +2748,41 @@ numpy = [ ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" -tzdata = ">=2022.1" +tzdata = ">=2022.7" [package.extras] -all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] -aws = ["s3fs (>=2022.05.0)"] -clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] -compression = ["zstandard (>=0.17.0)"] -computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] -feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2022.05.0)"] -gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] -hdf5 = ["tables (>=3.7.0)"] -html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] -mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] -parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] -plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] -spss = ["pyreadstat (>=1.1.5)"] -sql-other = ["SQLAlchemy (>=1.4.36)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.8.0)"] +xml = ["lxml (>=4.9.2)"] [[package]] name = "pandocfilters" -version = "1.5.0" +version = "1.5.1" description = "Utilities for writing pandoc filters in python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, - {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, + {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, + {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, ] [[package]] @@ -2911,28 +2921,28 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.1.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -2983,47 +2993,47 @@ testing = ["google-api-core[grpc] (>=1.31.5)"] [[package]] name = "protobuf" -version = "4.25.1" +version = "4.25.2" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.1-cp310-abi3-win32.whl", hash = "sha256:193f50a6ab78a970c9b4f148e7c750cfde64f59815e86f686c22e26b4fe01ce7"}, - {file = "protobuf-4.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:3497c1af9f2526962f09329fd61a36566305e6c72da2590ae0d7d1322818843b"}, - {file = "protobuf-4.25.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:0bf384e75b92c42830c0a679b0cd4d6e2b36ae0cf3dbb1e1dfdda48a244f4bcd"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:0f881b589ff449bf0b931a711926e9ddaad3b35089cc039ce1af50b21a4ae8cb"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:ca37bf6a6d0046272c152eea90d2e4ef34593aaa32e8873fc14c16440f22d4b7"}, - {file = "protobuf-4.25.1-cp38-cp38-win32.whl", hash = "sha256:abc0525ae2689a8000837729eef7883b9391cd6aa7950249dcf5a4ede230d5dd"}, - {file = "protobuf-4.25.1-cp38-cp38-win_amd64.whl", hash = "sha256:1484f9e692091450e7edf418c939e15bfc8fc68856e36ce399aed6889dae8bb0"}, - {file = "protobuf-4.25.1-cp39-cp39-win32.whl", hash = "sha256:8bdbeaddaac52d15c6dce38c71b03038ef7772b977847eb6d374fc86636fa510"}, - {file = "protobuf-4.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:becc576b7e6b553d22cbdf418686ee4daa443d7217999125c045ad56322dda10"}, - {file = "protobuf-4.25.1-py3-none-any.whl", hash = "sha256:a19731d5e83ae4737bb2a089605e636077ac001d18781b3cf489b9546c7c80d6"}, - {file = "protobuf-4.25.1.tar.gz", hash = "sha256:57d65074b4f5baa4ab5da1605c02be90ac20c8b40fb137d6a8df9f416b0d0ce2"}, + {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, + {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, + {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, + {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, + {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, + {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, + {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, + {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, + {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, ] [[package]] name = "psutil" -version = "5.9.7" +version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "psutil-5.9.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7"}, - {file = "psutil-5.9.7-cp27-none-win32.whl", hash = "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c"}, - {file = "psutil-5.9.7-cp27-none-win_amd64.whl", hash = "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6"}, - {file = "psutil-5.9.7-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe"}, - {file = "psutil-5.9.7-cp36-cp36m-win32.whl", hash = "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9"}, - {file = "psutil-5.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e"}, - {file = "psutil-5.9.7-cp37-abi3-win32.whl", hash = "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68"}, - {file = "psutil-5.9.7-cp37-abi3-win_amd64.whl", hash = "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414"}, - {file = "psutil-5.9.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340"}, - {file = "psutil-5.9.7.tar.gz", hash = "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c"}, + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, ] [package.extras] @@ -3151,47 +3161,47 @@ files = [ [[package]] name = "pydantic" -version = "1.10.13" +version = "1.10.14" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:efff03cc7a4f29d9009d1c96ceb1e7a70a65cfe86e89d34e4a5f2ab1e5693737"}, - {file = "pydantic-1.10.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ecea2b9d80e5333303eeb77e180b90e95eea8f765d08c3d278cd56b00345d01"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1740068fd8e2ef6eb27a20e5651df000978edce6da6803c2bef0bc74540f9548"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84bafe2e60b5e78bc64a2941b4c071a4b7404c5c907f5f5a99b0139781e69ed8"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc0898c12f8e9c97f6cd44c0ed70d55749eaf783716896960b4ecce2edfd2d69"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:654db58ae399fe6434e55325a2c3e959836bd17a6f6a0b6ca8107ea0571d2e17"}, - {file = "pydantic-1.10.13-cp310-cp310-win_amd64.whl", hash = "sha256:75ac15385a3534d887a99c713aa3da88a30fbd6204a5cd0dc4dab3d770b9bd2f"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c553f6a156deb868ba38a23cf0df886c63492e9257f60a79c0fd8e7173537653"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e08865bc6464df8c7d61439ef4439829e3ab62ab1669cddea8dd00cd74b9ffe"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31647d85a2013d926ce60b84f9dd5300d44535a9941fe825dc349ae1f760df9"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:210ce042e8f6f7c01168b2d84d4c9eb2b009fe7bf572c2266e235edf14bacd80"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8ae5dd6b721459bfa30805f4c25880e0dd78fc5b5879f9f7a692196ddcb5a580"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f8e81fc5fb17dae698f52bdd1c4f18b6ca674d7068242b2aff075f588301bbb0"}, - {file = "pydantic-1.10.13-cp311-cp311-win_amd64.whl", hash = "sha256:61d9dce220447fb74f45e73d7ff3b530e25db30192ad8d425166d43c5deb6df0"}, - {file = "pydantic-1.10.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4b03e42ec20286f052490423682016fd80fda830d8e4119f8ab13ec7464c0132"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59ef915cac80275245824e9d771ee939133be38215555e9dc90c6cb148aaeb5"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a1f9f747851338933942db7af7b6ee8268568ef2ed86c4185c6ef4402e80ba8"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:97cce3ae7341f7620a0ba5ef6cf043975cd9d2b81f3aa5f4ea37928269bc1b87"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854223752ba81e3abf663d685f105c64150873cc6f5d0c01d3e3220bcff7d36f"}, - {file = "pydantic-1.10.13-cp37-cp37m-win_amd64.whl", hash = "sha256:b97c1fac8c49be29486df85968682b0afa77e1b809aff74b83081cc115e52f33"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c958d053453a1c4b1c2062b05cd42d9d5c8eb67537b8d5a7e3c3032943ecd261"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c5370a7edaac06daee3af1c8b1192e305bc102abcbf2a92374b5bc793818599"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6f6e7305244bddb4414ba7094ce910560c907bdfa3501e9db1a7fd7eaea127"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3a3c792a58e1622667a2837512099eac62490cdfd63bd407993aaf200a4cf1f"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c636925f38b8db208e09d344c7aa4f29a86bb9947495dd6b6d376ad10334fb78"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:678bcf5591b63cc917100dc50ab6caebe597ac67e8c9ccb75e698f66038ea953"}, - {file = "pydantic-1.10.13-cp38-cp38-win_amd64.whl", hash = "sha256:6cf25c1a65c27923a17b3da28a0bdb99f62ee04230c931d83e888012851f4e7f"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ef467901d7a41fa0ca6db9ae3ec0021e3f657ce2c208e98cd511f3161c762c6"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968ac42970f57b8344ee08837b62f6ee6f53c33f603547a55571c954a4225691"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9849f031cf8a2f0a928fe885e5a04b08006d6d41876b8bbd2fc68a18f9f2e3fd"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56e3ff861c3b9c6857579de282ce8baabf443f42ffba355bf070770ed63e11e1"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f00790179497767aae6bcdc36355792c79e7bbb20b145ff449700eb076c5f96"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:75b297827b59bc229cac1a23a2f7a4ac0031068e5be0ce385be1462e7e17a35d"}, - {file = "pydantic-1.10.13-cp39-cp39-win_amd64.whl", hash = "sha256:e70ca129d2053fb8b728ee7d1af8e553a928d7e301a311094b8a0501adc8763d"}, - {file = "pydantic-1.10.13-py3-none-any.whl", hash = "sha256:b87326822e71bd5f313e7d3bfdc77ac3247035ac10b0c0618bd99dcf95b1e687"}, - {file = "pydantic-1.10.13.tar.gz", hash = "sha256:32c8b48dcd3b2ac4e78b0ba4af3a2c2eb6048cb75202f0ea7b34feb740efc340"}, + {file = "pydantic-1.10.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4fcec873f90537c382840f330b90f4715eebc2bc9925f04cb92de593eae054"}, + {file = "pydantic-1.10.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e3a76f571970fcd3c43ad982daf936ae39b3e90b8a2e96c04113a369869dc87"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d886bd3c3fbeaa963692ef6b643159ccb4b4cefaf7ff1617720cbead04fd1d"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:798a3d05ee3b71967844a1164fd5bdb8c22c6d674f26274e78b9f29d81770c4e"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:23d47a4b57a38e8652bcab15a658fdb13c785b9ce217cc3a729504ab4e1d6bc9"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9f674b5c3bebc2eba401de64f29948ae1e646ba2735f884d1594c5f675d6f2a"}, + {file = "pydantic-1.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:24a7679fab2e0eeedb5a8924fc4a694b3bcaac7d305aeeac72dd7d4e05ecbebf"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d578ac4bf7fdf10ce14caba6f734c178379bd35c486c6deb6f49006e1ba78a7"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa7790e94c60f809c95602a26d906eba01a0abee9cc24150e4ce2189352deb1b"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad4e10efa5474ed1a611b6d7f0d130f4aafadceb73c11d9e72823e8f508e663"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245f4f61f467cb3dfeced2b119afef3db386aec3d24a22a1de08c65038b255f"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:21efacc678a11114c765eb52ec0db62edffa89e9a562a94cbf8fa10b5db5c046"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:412ab4a3f6dbd2bf18aefa9f79c7cca23744846b31f1d6555c2ee2b05a2e14ca"}, + {file = "pydantic-1.10.14-cp311-cp311-win_amd64.whl", hash = "sha256:e897c9f35281f7889873a3e6d6b69aa1447ceb024e8495a5f0d02ecd17742a7f"}, + {file = "pydantic-1.10.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d604be0f0b44d473e54fdcb12302495fe0467c56509a2f80483476f3ba92b33c"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42c7d17706911199798d4c464b352e640cab4351efe69c2267823d619a937e5"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:596f12a1085e38dbda5cbb874d0973303e34227b400b6414782bf205cc14940c"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bfb113860e9288d0886e3b9e49d9cf4a9d48b441f52ded7d96db7819028514cc"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bc3ed06ab13660b565eed80887fcfbc0070f0aa0691fbb351657041d3e874efe"}, + {file = "pydantic-1.10.14-cp37-cp37m-win_amd64.whl", hash = "sha256:ad8c2bc677ae5f6dbd3cf92f2c7dc613507eafe8f71719727cbc0a7dec9a8c01"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c37c28449752bb1f47975d22ef2882d70513c546f8f37201e0fec3a97b816eee"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49a46a0994dd551ec051986806122767cf144b9702e31d47f6d493c336462597"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53e3819bd20a42470d6dd0fe7fc1c121c92247bca104ce608e609b59bc7a77ee"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbb503bbbbab0c588ed3cd21975a1d0d4163b87e360fec17a792f7d8c4ff29f"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:336709883c15c050b9c55a63d6c7ff09be883dbc17805d2b063395dd9d9d0022"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4ae57b4d8e3312d486e2498d42aed3ece7b51848336964e43abbf9671584e67f"}, + {file = "pydantic-1.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:dba49d52500c35cfec0b28aa8b3ea5c37c9df183ffc7210b10ff2a415c125c4a"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c66609e138c31cba607d8e2a7b6a5dc38979a06c900815495b2d90ce6ded35b4"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d986e115e0b39604b9eee3507987368ff8148222da213cd38c359f6f57b3b347"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646b2b12df4295b4c3148850c85bff29ef6d0d9621a8d091e98094871a62e5c7"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282613a5969c47c83a8710cc8bfd1e70c9223feb76566f74683af889faadc0ea"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:466669501d08ad8eb3c4fecd991c5e793c4e0bbd62299d05111d4f827cded64f"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:13e86a19dca96373dcf3190fcb8797d40a6f12f154a244a8d1e8e03b8f280593"}, + {file = "pydantic-1.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:08b6ec0917c30861e3fe71a93be1648a2aa4f62f866142ba21670b24444d7fd8"}, + {file = "pydantic-1.10.14-py3-none-any.whl", hash = "sha256:8ee853cd12ac2ddbf0ecbac1c289f95882b2d4482258048079d13be700aa114c"}, + {file = "pydantic-1.10.14.tar.gz", hash = "sha256:46f17b832fe27de7850896f3afee50ea682220dd218f7e9c88d436788419dca6"}, ] [package.dependencies] @@ -3367,13 +3377,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -3491,13 +3501,13 @@ files = [ [[package]] name = "pytz" -version = "2023.3.post1" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -3548,7 +3558,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3760,8 +3769,8 @@ scipy = "^1.10.1" [package.source] type = "git" url = "https://github.com/qiboteam/qibojit.git" -reference = "HEAD" -resolved_reference = "b32f503452127ac915b20af773e29694b5b64dd4" +reference = "sxdg" +resolved_reference = "7b819b9224b2793ff1d3786aef0e9023c1cccb6d" [[package]] name = "recommonmark" @@ -3892,13 +3901,13 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruamel-yaml" -version = "0.18.5" +version = "0.18.6" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = ">=3.7" files = [ - {file = "ruamel.yaml-0.18.5-py3-none-any.whl", hash = "sha256:a013ac02f99a69cdd6277d9664689eb1acba07069f912823177c5eced21a6ada"}, - {file = "ruamel.yaml-0.18.5.tar.gz", hash = "sha256:61917e3a35a569c1133a8f772e1226961bf5a1198bea7e23f06a0841dea1ab0e"}, + {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, + {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, ] [package.dependencies] @@ -3917,24 +3926,24 @@ python-versions = ">=3.6" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, @@ -3942,7 +3951,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, @@ -3950,7 +3959,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, @@ -3958,7 +3967,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, @@ -3969,50 +3978,65 @@ files = [ [[package]] name = "scikit-learn" -version = "1.3.2" +version = "1.4.0" description = "A set of python modules for machine learning and data mining" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "scikit-learn-1.3.2.tar.gz", hash = "sha256:a2f54c76accc15a34bfb9066e6c7a56c1e7235dda5762b990792330b52ccfb05"}, - {file = "scikit_learn-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e326c0eb5cf4d6ba40f93776a20e9a7a69524c4db0757e7ce24ba222471ee8a1"}, - {file = "scikit_learn-1.3.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:535805c2a01ccb40ca4ab7d081d771aea67e535153e35a1fd99418fcedd1648a"}, - {file = "scikit_learn-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1215e5e58e9880b554b01187b8c9390bf4dc4692eedeaf542d3273f4785e342c"}, - {file = "scikit_learn-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ee107923a623b9f517754ea2f69ea3b62fc898a3641766cb7deb2f2ce450161"}, - {file = "scikit_learn-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:35a22e8015048c628ad099da9df5ab3004cdbf81edc75b396fd0cff8699ac58c"}, - {file = "scikit_learn-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6fb6bc98f234fda43163ddbe36df8bcde1d13ee176c6dc9b92bb7d3fc842eb66"}, - {file = "scikit_learn-1.3.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:18424efee518a1cde7b0b53a422cde2f6625197de6af36da0b57ec502f126157"}, - {file = "scikit_learn-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3271552a5eb16f208a6f7f617b8cc6d1f137b52c8a1ef8edf547db0259b2c9fb"}, - {file = "scikit_learn-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4144a5004a676d5022b798d9e573b05139e77f271253a4703eed295bde0433"}, - {file = "scikit_learn-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:67f37d708f042a9b8d59551cf94d30431e01374e00dc2645fa186059c6c5d78b"}, - {file = "scikit_learn-1.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8db94cd8a2e038b37a80a04df8783e09caac77cbe052146432e67800e430c028"}, - {file = "scikit_learn-1.3.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:61a6efd384258789aa89415a410dcdb39a50e19d3d8410bd29be365bcdd512d5"}, - {file = "scikit_learn-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb06f8dce3f5ddc5dee1715a9b9f19f20d295bed8e3cd4fa51e1d050347de525"}, - {file = "scikit_learn-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b2de18d86f630d68fe1f87af690d451388bb186480afc719e5f770590c2ef6c"}, - {file = "scikit_learn-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:0402638c9a7c219ee52c94cbebc8fcb5eb9fe9c773717965c1f4185588ad3107"}, - {file = "scikit_learn-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a19f90f95ba93c1a7f7924906d0576a84da7f3b2282ac3bfb7a08a32801add93"}, - {file = "scikit_learn-1.3.2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:b8692e395a03a60cd927125eef3a8e3424d86dde9b2370d544f0ea35f78a8073"}, - {file = "scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15e1e94cc23d04d39da797ee34236ce2375ddea158b10bee3c343647d615581d"}, - {file = "scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:785a2213086b7b1abf037aeadbbd6d67159feb3e30263434139c98425e3dcfcf"}, - {file = "scikit_learn-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:64381066f8aa63c2710e6b56edc9f0894cc7bf59bd71b8ce5613a4559b6145e0"}, - {file = "scikit_learn-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6c43290337f7a4b969d207e620658372ba3c1ffb611f8bc2b6f031dc5c6d1d03"}, - {file = "scikit_learn-1.3.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:dc9002fc200bed597d5d34e90c752b74df516d592db162f756cc52836b38fe0e"}, - {file = "scikit_learn-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d08ada33e955c54355d909b9c06a4789a729977f165b8bae6f225ff0a60ec4a"}, - {file = "scikit_learn-1.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763f0ae4b79b0ff9cca0bf3716bcc9915bdacff3cebea15ec79652d1cc4fa5c9"}, - {file = "scikit_learn-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:ed932ea780517b00dae7431e031faae6b49b20eb6950918eb83bd043237950e0"}, + {file = "scikit-learn-1.4.0.tar.gz", hash = "sha256:d4373c984eba20e393216edd51a3e3eede56cbe93d4247516d205643c3b93121"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fce93a7473e2f4ee4cc280210968288d6a7d7ad8dc6fa7bb7892145e407085f9"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d77df3d1e15fc37a9329999979fa7868ba8655dbab21fe97fc7ddabac9e08cc7"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2404659fedec40eeafa310cd14d613e564d13dbf8f3c752d31c095195ec05de6"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e98632da8f6410e6fb6bf66937712c949b4010600ccd3f22a5388a83e610cc3c"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-win_amd64.whl", hash = "sha256:11b3b140f70fbc9f6a08884631ae8dd60a4bb2d7d6d1de92738ea42b740d8992"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8341eabdc754d5ab91641a7763243845e96b6d68e03e472531e88a4f1b09f21"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d1f6bce875ac2bb6b52514f67c185c564ccd299a05b65b7bab091a4c13dde12d"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c408b46b2fd61952d519ea1af2f8f0a7a703e1433923ab1704c4131520b2083b"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b465dd1dcd237b7b1dcd1a9048ccbf70a98c659474324fa708464c3a2533fad"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-win_amd64.whl", hash = "sha256:0db8e22c42f7980fe5eb22069b1f84c48966f3e0d23a01afde5999e3987a2501"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7eef6ea2ed289af40e88c0be9f7704ca8b5de18508a06897c3fe21e0905efdf"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:349669b01435bc4dbf25c6410b0892073befdaec52637d1a1d1ff53865dc8db3"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d439c584e58434d0350701bd33f6c10b309e851fccaf41c121aed55f6851d8cf"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e2427d9ef46477625ab9b55c1882844fe6fc500f418c3f8e650200182457bc"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-win_amd64.whl", hash = "sha256:d3d75343940e7bf9b85c830c93d34039fa015eeb341c5c0b4cd7a90dadfe00d4"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:76986d22e884ab062b1beecdd92379656e9d3789ecc1f9870923c178de55f9fe"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:e22446ad89f1cb7657f0d849dcdc345b48e2d10afa3daf2925fdb740f85b714c"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74812c9eabb265be69d738a8ea8d4884917a59637fcbf88a5f0e9020498bc6b3"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad2a63e0dd386b92da3270887a29b308af4d7c750d8c4995dfd9a4798691bcc"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-win_amd64.whl", hash = "sha256:53b9e29177897c37e2ff9d4ba6ca12fdb156e22523e463db05def303f5c72b5c"}, + {file = "scikit_learn-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb8f044a8f5962613ce1feb4351d66f8d784bd072d36393582f351859b065f7d"}, + {file = "scikit_learn-1.4.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:a6372c90bbf302387792108379f1ec77719c1618d88496d0df30cb8e370b4661"}, + {file = "scikit_learn-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:785ce3c352bf697adfda357c3922c94517a9376002971bc5ea50896144bc8916"}, + {file = "scikit_learn-1.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0aba2a20d89936d6e72d95d05e3bf1db55bca5c5920926ad7b92c34f5e7d3bbe"}, + {file = "scikit_learn-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:2bac5d56b992f8f06816f2cd321eb86071c6f6d44bb4b1cb3d626525820d754b"}, + {file = "scikit_learn-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27ae4b0f1b2c77107c096a7e05b33458354107b47775428d1f11b23e30a73e8a"}, + {file = "scikit_learn-1.4.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5c5c62ffb52c3ffb755eb21fa74cc2cbf2c521bd53f5c04eaa10011dbecf5f80"}, + {file = "scikit_learn-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f0d2018ac6fa055dab65fe8a485967990d33c672d55bc254c56c35287b02fab"}, + {file = "scikit_learn-1.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a8918c415c4b4bf1d60c38d32958849a9191c2428ab35d30b78354085c7c7a"}, + {file = "scikit_learn-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:80a21de63275f8bcd7877b3e781679d2ff1eddfed515a599f95b2502a3283d42"}, + {file = "scikit_learn-1.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0f33bbafb310c26b81c4d41ecaebdbc1f63498a3f13461d50ed9a2e8f24d28e4"}, + {file = "scikit_learn-1.4.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:8b6ac1442ec714b4911e5aef8afd82c691b5c88b525ea58299d455acc4e8dcec"}, + {file = "scikit_learn-1.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05fc5915b716c6cc60a438c250108e9a9445b522975ed37e416d5ea4f9a63381"}, + {file = "scikit_learn-1.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:842b7d6989f3c574685e18da6f91223eb32301d0f93903dd399894250835a6f7"}, + {file = "scikit_learn-1.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:88bcb586fdff865372df1bc6be88bb7e6f9e0aa080dab9f54f5cac7eca8e2b6b"}, + {file = "scikit_learn-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f77674647dd31f56cb12ed13ed25b6ed43a056fffef051715022d2ebffd7a7d1"}, + {file = "scikit_learn-1.4.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:833999872e2920ce00f3a50839946bdac7539454e200eb6db54898a41f4bfd43"}, + {file = "scikit_learn-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:970ec697accaef10fb4f51763f3a7b1250f9f0553cf05514d0e94905322a0172"}, + {file = "scikit_learn-1.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923d778f378ebacca2c672ab1740e5a413e437fb45ab45ab02578f8b689e5d43"}, + {file = "scikit_learn-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:1d041bc95006b545b59e458399e3175ab11ca7a03dc9a74a573ac891f5df1489"}, ] [package.dependencies] -joblib = ">=1.1.1" -numpy = ">=1.17.3,<2.0" -scipy = ">=1.5.0" +joblib = ">=1.2.0" +numpy = ">=1.19.5" +scipy = ">=1.6.0" threadpoolctl = ">=2.0.0" [package.extras] -benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.10.1)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] -tests = ["black (>=23.3.0)", "matplotlib (>=3.1.3)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.16.2)"] +benchmark = ["matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "pandas (>=1.1.5)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.15.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] +tests = ["black (>=23.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.19.12)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.17.2)"] [[package]] name = "scipy" @@ -4091,18 +4115,18 @@ scipy = "*" [[package]] name = "setuptools" -version = "69.0.2" +version = "69.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -4246,20 +4270,18 @@ markdown = ">=3.4" [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.7" +version = "1.0.8" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.7-py3-none-any.whl", hash = "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d"}, - {file = "sphinxcontrib_applehelp-1.0.7.tar.gz", hash = "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa"}, + {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, + {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] @@ -4282,38 +4304,34 @@ Sphinx = ">=2.1" [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.5" +version = "1.0.6" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.5-py3-none-any.whl", hash = "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f"}, - {file = "sphinxcontrib_devhelp-1.0.5.tar.gz", hash = "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212"}, + {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, + {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.4" +version = "2.0.5" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.4-py3-none-any.whl", hash = "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9"}, - {file = "sphinxcontrib_htmlhelp-2.0.4.tar.gz", hash = "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a"}, + {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, + {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -4332,38 +4350,34 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.6" +version = "1.0.7" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.6-py3-none-any.whl", hash = "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4"}, - {file = "sphinxcontrib_qthelp-1.0.6.tar.gz", hash = "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d"}, + {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, + {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.9" +version = "1.1.10" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"}, - {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"}, + {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, + {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] @@ -4429,22 +4443,22 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] [[package]] name = "tensorboard" -version = "2.14.1" +version = "2.15.2" description = "TensorBoard lets you watch Tensors Flow" optional = false python-versions = ">=3.9" files = [ - {file = "tensorboard-2.14.1-py3-none-any.whl", hash = "sha256:3db108fb58f023b6439880e177743c5f1e703e9eeb5fb7d597871f949f85fd58"}, + {file = "tensorboard-2.15.2-py3-none-any.whl", hash = "sha256:a6f6443728064d962caea6d34653e220e34ef8df764cb06a8212c17e1a8f0622"}, ] [package.dependencies] absl-py = ">=0.4" google-auth = ">=1.6.3,<3" -google-auth-oauthlib = ">=0.5,<1.1" +google-auth-oauthlib = ">=0.5,<2" grpcio = ">=1.48.2" markdown = ">=2.6.8" numpy = ">=1.12.0" -protobuf = ">=3.19.6" +protobuf = ">=3.19.6,<4.24.0 || >4.24.0" requests = ">=2.21.0,<3" setuptools = ">=41.0.0" six = ">1.9" @@ -4465,26 +4479,26 @@ files = [ [[package]] name = "tensorflow" -version = "2.14.1" +version = "2.15.0" description = "TensorFlow is an open source machine learning framework for everyone." optional = false python-versions = ">=3.9" files = [ - {file = "tensorflow-2.14.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f6e9ac1e53db30f1759148f731f87b9d12da5ce0f153fc49406824efd486aae7"}, - {file = "tensorflow-2.14.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:7156bf1f7311dada7dba5345b526a38e6f4e4f4b8509bee162a24342bf6571b2"}, - {file = "tensorflow-2.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5781aadad5b46e2de4e373b0ca15a852b90d58982270a6db02ec52e4986316d"}, - {file = "tensorflow-2.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a955c42164eff4d751732c1274ca4bf059db60c9e2362098ce1eed7177c3fe9"}, - {file = "tensorflow-2.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:4be5f4327a6e854f64b4dcfd08a51c5fc7cc3fea8c76c5bf5c0c3deb002d5221"}, - {file = "tensorflow-2.14.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:597dd6665a91b3d4b881f0d40277eb55b65b04567553206a46e7db9cfa067310"}, - {file = "tensorflow-2.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:9833e61423ad2726f81e3fc770558b81d5f0a454bdb2dad717c5474ea837ce91"}, - {file = "tensorflow-2.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14a48a087954722d9e73086e8ce28a14b1f9f889ea5845c7c0bf30d8747ab6e2"}, - {file = "tensorflow-2.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9aa05a98450fa5bc4efd529383b7d15c10ec12b0238a6744baa1508c4bfa4d5"}, - {file = "tensorflow-2.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:11958d12e39d44a9f5fc753fc312dd1726a8506f2d2606e01421ca4ee9dc5c55"}, - {file = "tensorflow-2.14.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d95404f78a8d5e3d2481383dbe2d2286341ccf9bc5cbb19d857c646494d860c6"}, - {file = "tensorflow-2.14.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:511c4c5bfb2af17c6ca22663f98a7267c4386bf5486fbe78ee2d21482a6fa822"}, - {file = "tensorflow-2.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f66d2990157cf27f80c730878cb8befa8ed9716223494037d31c80fbe5f64370"}, - {file = "tensorflow-2.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9ab2747f75aba0327bfe6092b963694f1001781e5d2c0d251dfeed02b0c3bba"}, - {file = "tensorflow-2.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:7f5c9215bc00ba88f1cde1399f8160a5cb865c20ad71a1d5a6869f9fad62d9a5"}, + {file = "tensorflow-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:9b248e0f4316b3a3c54cd1f83edfb7a761d473060c1972a8ea31a90d5de3aa72"}, + {file = "tensorflow-2.15.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:eaf420d8b8ec1d4bd75859be7d7545d8e7052726eed8456fdbba63718e7e07ea"}, + {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98aab454fc73ff1900314821e5bafbf20840ada2004c8caccf4d92e0e12a628"}, + {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed601b43df9b7d9bed0203b34bcb9356efd4f671eaaac1046b7166a2afee0cf8"}, + {file = "tensorflow-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:2d88f8b71f4a8d9ab9dc7c8e42b14ca0f53d1daab0f989b8f2918907c2891f41"}, + {file = "tensorflow-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1e0716622ed7af867d8b1997b00a2940f1a1587dee923ff53efa2ee506992f32"}, + {file = "tensorflow-2.15.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:124930e7d4f5d74c61a5c80d642a26c22fe0c42fdd383fe9ee5803c3ac9ed4ce"}, + {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:852efeb4d18beedac0120c4f2d4f4dccf4c090bb6740c5199d395ff609e85e98"}, + {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee8ec2b2c6c942ae65d25746e53cdc475e82d5fcbbb3009ce47f5963d69ebfc"}, + {file = "tensorflow-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:e05a48006930e4e9e68468e7affed3bbce8a1c7fe6df86500496ad1558804a78"}, + {file = "tensorflow-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:2cfcdde1ff3c01be617e99ce9783c49cb11da5796ce32a31855412bd092c0bcf"}, + {file = "tensorflow-2.15.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:896bda03f722700a9918d144aee5152a75f1be5e6c5045fd0683b8318a3fc9d9"}, + {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7697b005ce48fec8b2ee8cf25bcbd138f16b5e17f99f7c01a6ea3f2429f86c6"}, + {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fa865956d96b7614f247c36e4c22b1543ba5ce656fbe8e4f6266ae7a4917132"}, + {file = "tensorflow-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:01108746e1bbfcd48dfabf7f51ddca7693b91ea6821f6f62a27b5a5ebf0817c5"}, ] [package.dependencies] @@ -4495,60 +4509,63 @@ gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" google-pasta = ">=0.1.1" grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" -keras = ">=2.14.0,<2.15" +keras = ">=2.15.0,<2.16" libclang = ">=13.0.0" -ml-dtypes = "0.2.0" +ml-dtypes = ">=0.2.0,<0.3.0" numpy = ">=1.23.5,<2.0.0" opt-einsum = ">=2.3.2" packaging = "*" protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" setuptools = "*" six = ">=1.12.0" -tensorboard = ">=2.14,<2.15" -tensorflow-estimator = ">=2.14.0,<2.15" +tensorboard = ">=2.15,<2.16" +tensorflow-estimator = ">=2.15.0,<2.16" tensorflow-io-gcs-filesystem = ">=0.23.1" termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" [package.extras] -and-cuda = ["nvidia-cublas-cu11 (==11.11.3.6)", "nvidia-cuda-cupti-cu11 (==11.8.87)", "nvidia-cuda-nvcc-cu11 (==11.8.89)", "nvidia-cuda-runtime-cu11 (==11.8.89)", "nvidia-cudnn-cu11 (==8.7.0.84)", "nvidia-cufft-cu11 (==10.9.0.58)", "nvidia-curand-cu11 (==10.3.0.86)", "nvidia-cusolver-cu11 (==11.4.1.48)", "nvidia-cusparse-cu11 (==11.7.5.86)", "nvidia-nccl-cu11 (==2.16.5)", "tensorrt (==8.5.3.1)"] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] [[package]] name = "tensorflow-estimator" -version = "2.14.0" +version = "2.15.0" description = "TensorFlow Estimator." optional = false python-versions = ">=3.7" files = [ - {file = "tensorflow_estimator-2.14.0-py2.py3-none-any.whl", hash = "sha256:820bf57c24aa631abb1bbe4371739ed77edb11361d61381fd8e790115ac0fd57"}, + {file = "tensorflow_estimator-2.15.0-py2.py3-none-any.whl", hash = "sha256:aedf21eec7fb2dc91150fc91a1ce12bc44dbb72278a08b58e79ff87c9e28f153"}, ] [[package]] name = "tensorflow-io-gcs-filesystem" -version = "0.35.0" +version = "0.36.0" description = "TensorFlow IO" optional = false python-versions = ">=3.7, <3.12" files = [ - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:5521721b38105496d4b43a4ffb0af5b04cc4873d464f26fbceddf8d63815ce98"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd8f30908bf8b7b2a017d6b145720d105aff7f998422671b71729708ec7b2fe4"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac8f1de60fdf9c734aea967b98555e366ac8743f77bca15c49eff023f587076b"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:35b6eca7225c815d962254327195f191d88c3c9c2278a5ab23e0ac834acbadbb"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e997389bfe008210cbd97c0c738d64282a2f03ad4d0536013bb0a9efde0c283"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8fb3402fb1457482c386ea19371bc76383412ae9ea4396edb1e8adb4ba76f21"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb6bf8f5b40207ecb17e7fdc3b4fc824a8361267c14e9528c1688e16de135cb7"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:c4f786eebd98d401565374722f2e67f3878675b0d87489cbaa13c70ee6ac370a"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fce1466bdb91096b6d22e7df17358ba228bcb92db5cff83f2f9f1c68eb26788"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1856fe321fdb75f3386d92109c60db6ef097f610b450f9cc69d76444fb9980d1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:702c6df62b38095ff613c433546d9424d4f33902a5ab26b00fd26457e27a99fa"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e9b8aaca2789af356c42afda0f52380f82e5abb2f3c0b85087833fcfe03875d8"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c477aed96864ceae77d7051c3b687f28813aba7320fc5dd552164fad6ec8d1a1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be1ff92559dfa23048b01179a1827081947583f5c6f9986ccac471df8a29322a"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:72c3ca4b8c0d8dbdd970699d05a100107cf200317ad8e6a8373e2c37225cd552"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:848e8e89a0f49258c7782189c938d8d1162d989da1a80c79f95c7af3ef6006c8"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d72db1ab03edb65fa1e98d06e504ccbc64282d38ab3589afb6db66dc448d1c1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd4d946b5fa23220daa473a80e511a5fb27493d7e49d17dff0bb43bb0a31f32"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa346fd1dd9f57848b73874007440504f060fadd689fa1cc29cc49817d0eeaf3"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0a4437824424a4423cf86162cb8b21b1bec24698194332748b50bb952e62ab9f"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:31806bd7ac2db789161bc720747de22947063265561a4c17be54698fd9780b03"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc0e57976c1aa035af6281f0330cfb8dd50eee2f63412ecc84d60ff5075d29b7"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e97ff5c280eb10f699098ae21057be2b146d39e8a906cd5db91f2ea6c34e47d0"}, ] [package.extras] -tensorflow = ["tensorflow (>=2.14.0,<2.15.0)"] -tensorflow-aarch64 = ["tensorflow-aarch64 (>=2.14.0,<2.15.0)"] -tensorflow-cpu = ["tensorflow-cpu (>=2.14.0,<2.15.0)"] -tensorflow-gpu = ["tensorflow-gpu (>=2.14.0,<2.15.0)"] -tensorflow-rocm = ["tensorflow-rocm (>=2.14.0,<2.15.0)"] +tensorflow = ["tensorflow (>=2.15.0,<2.16.0)"] +tensorflow-aarch64 = ["tensorflow-aarch64 (>=2.15.0,<2.16.0)"] +tensorflow-cpu = ["tensorflow-cpu (>=2.15.0,<2.16.0)"] +tensorflow-gpu = ["tensorflow-gpu (>=2.15.0,<2.16.0)"] +tensorflow-rocm = ["tensorflow-rocm (>=2.15.0,<2.16.0)"] [[package]] name = "termcolor" @@ -4648,13 +4665,13 @@ files = [ [[package]] name = "tqdm" -version = "4.66.1" +version = "4.66.2" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, - {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, + {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, + {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, ] [package.dependencies] @@ -4668,13 +4685,13 @@ telegram = ["requests"] [[package]] name = "traitlets" -version = "5.14.0" +version = "5.14.1" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.0-py3-none-any.whl", hash = "sha256:f14949d23829023013c47df20b4a76ccd1a85effb786dc060f34de7948361b33"}, - {file = "traitlets-5.14.0.tar.gz", hash = "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772"}, + {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, + {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, ] [package.extras] @@ -4683,24 +4700,24 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "types-deprecated" -version = "1.2.9.3" +version = "1.2.9.20240106" description = "Typing stubs for Deprecated" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-Deprecated-1.2.9.3.tar.gz", hash = "sha256:ef87327adf3e3c4a4c7d8e06e58f6476710d3466ecfb53c49efb080804a70ef3"}, - {file = "types_Deprecated-1.2.9.3-py3-none-any.whl", hash = "sha256:24da9210763e5e1b3d0d4f6f8bba9ad3bb6af3fe7f6815fc37e3ede4681704f5"}, + {file = "types-Deprecated-1.2.9.20240106.tar.gz", hash = "sha256:afeb819e9a03d0a5795f18c88fe6207c48ed13c639e93281bd9d9b7bb6d34310"}, + {file = "types_Deprecated-1.2.9.20240106-py3-none-any.whl", hash = "sha256:9dcb258493b5be407574ee21e50ddac9e429072d39b576126bf1ac00764fb9a8"}, ] [[package]] name = "types-python-dateutil" -version = "2.8.19.14" +version = "2.8.19.20240106" description = "Typing stubs for python-dateutil" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-python-dateutil-2.8.19.14.tar.gz", hash = "sha256:1f4f10ac98bb8b16ade9dbee3518d9ace017821d94b057a425b069f834737f4b"}, - {file = "types_python_dateutil-2.8.19.14-py3-none-any.whl", hash = "sha256:f977b8de27787639986b4e28963263fd0e5158942b3ecef91b9335c130cb1ce9"}, + {file = "types-python-dateutil-2.8.19.20240106.tar.gz", hash = "sha256:1f8db221c3b98e6ca02ea83a58371b22c374f42ae5bbdf186db9c9a76581459f"}, + {file = "types_python_dateutil-2.8.19.20240106-py3-none-any.whl", hash = "sha256:efbbdc54590d0f16152fa103c9879c7d4a00e82078f6e2cf01769042165acaa2"}, ] [[package]] @@ -4727,40 +4744,41 @@ files = [ [[package]] name = "tzdata" -version = "2023.3" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "wcwidth" -version = "0.2.12" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, - {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -4807,13 +4825,13 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "widgetsnbextension" -version = "4.0.9" +version = "4.0.10" description = "Jupyter interactive widgets for Jupyter Notebook" optional = false python-versions = ">=3.7" files = [ - {file = "widgetsnbextension-4.0.9-py3-none-any.whl", hash = "sha256:91452ca8445beb805792f206e560c1769284267a30ceb1cec9f5bcc887d15175"}, - {file = "widgetsnbextension-4.0.9.tar.gz", hash = "sha256:3c1f5e46dc1166dfd40a42d685e6a51396fd34ff878742a3e47c6f0cc4a2a385"}, + {file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"}, + {file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"}, ] [[package]] @@ -4934,4 +4952,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "fb9a22edabc2aa704e5ba3bcbf60123f4b6c5e929a248b717b962f78c64c49f1" +content-hash = "1a0f62b568e2f3b614eb7c1b2ac6c4d1ffdd595dfed0c8fd1802884556ba739b" diff --git a/pyproject.toml b/pyproject.toml index bdcd37e76b..9dd37788e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,7 @@ dill = "^0.3.6" pytest-cov = "^4.0.0" pylint = "^3.0.3" matplotlib = "^3.7.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git", brach = "sxdg" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "sxdg" } tensorflow = { version = "^2.14.1", markers = "sys_platform == 'linux'" } [tool.poe.tasks] @@ -79,7 +79,7 @@ optional = true [tool.poetry.group.cuda11.dependencies] cupy-cuda11x = "^12.0.0" cuquantum-python-cu11 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git"} +qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "sxdg" } [tool.poetry.group.cuda12] optional = true @@ -87,7 +87,7 @@ optional = true [tool.poetry.group.cuda12.dependencies] cupy-cuda12x = "^12.0.0" cuquantum-python-cu12 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git"} +qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "sxdg" } [tool.pylint.reports] output-format = "colorized" From de96b1f69eee1be5ee366c1bbff426c516c1a9c0 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Wed, 14 Feb 2024 18:34:13 +0400 Subject: [PATCH 187/200] fix 'tensorflow' cast issue --- src/qibo/backends/npmatrices.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index fd7c78db1e..0e1e4705e3 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -245,7 +245,13 @@ def SWAP(self): @cached_property def iSWAP(self): return self._cast( - [[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]], dtype=self.dtype + [ + [1+0j, 0j, 0j, 0j], + [0j, 0j, 1j, 0j], + [0j, 1j, 0j, 0j], + [0j, 0j, 0j, 1+0j], + ], + dtype=self.dtype ) @cached_property From efa49006116fc8d57c14bbf0502ca1bd105d23bc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 14:34:38 +0000 Subject: [PATCH 188/200] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/npmatrices.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qibo/backends/npmatrices.py b/src/qibo/backends/npmatrices.py index 0e1e4705e3..4f180ef4c3 100644 --- a/src/qibo/backends/npmatrices.py +++ b/src/qibo/backends/npmatrices.py @@ -246,12 +246,12 @@ def SWAP(self): def iSWAP(self): return self._cast( [ - [1+0j, 0j, 0j, 0j], - [0j, 0j, 1j, 0j], - [0j, 1j, 0j, 0j], - [0j, 0j, 0j, 1+0j], - ], - dtype=self.dtype + [1 + 0j, 0j, 0j, 0j], + [0j, 0j, 1j, 0j], + [0j, 1j, 0j, 0j], + [0j, 0j, 0j, 1 + 0j], + ], + dtype=self.dtype, ) @cached_property From de3ea519dc10e2931f342406e9868b32f597a320 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Thu, 15 Feb 2024 12:18:40 +0400 Subject: [PATCH 189/200] remove dependency on qibojit branch --- poetry.lock | 76 +++++++++++++++++++++++++------------------------- pyproject.toml | 6 ++-- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/poetry.lock b/poetry.lock index ef54e2c382..2bb2519fdc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1339,13 +1339,13 @@ files = [ [[package]] name = "google-api-core" -version = "2.17.0" +version = "2.17.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.17.0.tar.gz", hash = "sha256:de7ef0450faec7c75e0aea313f29ac870fdc44cfaec9d6499a9a17305980ef66"}, - {file = "google_api_core-2.17.0-py3-none-any.whl", hash = "sha256:08ed79ed8e93e329de5e3e7452746b734e6bf8438d8d64dd3319d21d3164890c"}, + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, ] [package.dependencies] @@ -2217,39 +2217,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.2" +version = "3.8.3" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, - {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, - {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, - {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, - {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, - {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, - {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, - {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, - {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, - {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, - {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"}, + {file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"}, + {file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, + {file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, + {file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, + {file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, + {file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"}, + {file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"}, + {file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, + {file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, ] [package.dependencies] @@ -3769,8 +3769,8 @@ scipy = "^1.10.1" [package.source] type = "git" url = "https://github.com/qiboteam/qibojit.git" -reference = "sxdg" -resolved_reference = "7b819b9224b2793ff1d3786aef0e9023c1cccb6d" +reference = "HEAD" +resolved_reference = "aaec6564fe30b1ea11d55eea33741d1a7cde7f9d" [[package]] name = "recommonmark" @@ -4583,13 +4583,13 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "threadpoolctl" -version = "3.2.0" +version = "3.3.0" description = "threadpoolctl" optional = false python-versions = ">=3.8" files = [ - {file = "threadpoolctl-3.2.0-py3-none-any.whl", hash = "sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032"}, - {file = "threadpoolctl-3.2.0.tar.gz", hash = "sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355"}, + {file = "threadpoolctl-3.3.0-py3-none-any.whl", hash = "sha256:6155be1f4a39f31a18ea70f94a77e0ccd57dced08122ea61109e7da89883781e"}, + {file = "threadpoolctl-3.3.0.tar.gz", hash = "sha256:5dac632b4fa2d43f42130267929af3ba01399ef4bd1882918e92dbc30365d30c"}, ] [[package]] @@ -4952,4 +4952,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "1a0f62b568e2f3b614eb7c1b2ac6c4d1ffdd595dfed0c8fd1802884556ba739b" +content-hash = "fb9a22edabc2aa704e5ba3bcbf60123f4b6c5e929a248b717b962f78c64c49f1" diff --git a/pyproject.toml b/pyproject.toml index 9dd37788e0..bb2b539695 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,7 @@ dill = "^0.3.6" pytest-cov = "^4.0.0" pylint = "^3.0.3" matplotlib = "^3.7.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "sxdg" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git" } tensorflow = { version = "^2.14.1", markers = "sys_platform == 'linux'" } [tool.poe.tasks] @@ -79,7 +79,7 @@ optional = true [tool.poetry.group.cuda11.dependencies] cupy-cuda11x = "^12.0.0" cuquantum-python-cu11 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "sxdg" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git" } [tool.poetry.group.cuda12] optional = true @@ -87,7 +87,7 @@ optional = true [tool.poetry.group.cuda12.dependencies] cupy-cuda12x = "^12.0.0" cuquantum-python-cu12 = "^23.3.0" -qibojit = { git = "https://github.com/qiboteam/qibojit.git", branch = "sxdg" } +qibojit = { git = "https://github.com/qiboteam/qibojit.git" } [tool.pylint.reports] output-format = "colorized" From 208dbdb7da9a93e3c9d0ae68beea7ec6045a699a Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Thu, 15 Feb 2024 10:17:06 +0100 Subject: [PATCH 190/200] chore: Add codecov threshold, and remove PR annotations --- .github/.codecov.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/.codecov.yml b/.github/.codecov.yml index 0c6bd02622..1bf339e4b0 100644 --- a/.github/.codecov.yml +++ b/.github/.codecov.yml @@ -1,3 +1,12 @@ +coverage: + status: + project: + default: + threshold: 0.5% + +github_checks: + annotations: false + ignore: - "setup.py" - "src/qibo/tests/test_custom_functions.py" From d96e52f3e26d48b51191a703ef07a30de1492acc Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Thu, 15 Feb 2024 11:01:15 +0100 Subject: [PATCH 191/200] chore: Unhide codecov file Since already inside a hidden folder --- .github/{.codecov.yml => codecov.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{.codecov.yml => codecov.yml} (100%) diff --git a/.github/.codecov.yml b/.github/codecov.yml similarity index 100% rename from .github/.codecov.yml rename to .github/codecov.yml From 4722f501cc87229be80ad412d5a67f04cb767bef Mon Sep 17 00:00:00 2001 From: MatteoRobbiati Date: Thu, 15 Feb 2024 17:36:58 +0100 Subject: [PATCH 192/200] fix math rendering --- src/qibo/quantum_info/random_ensembles.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index b1be867620..3571274770 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -32,7 +32,8 @@ def _ppf(self, theta: float): def uniform_sampling_U3(ngates: int, seed=None, backend=None): - """Samples parameters for Haar-random :math:`U_{3}`s (:class:`qibo.gates.U3`). + """ + Samples parameters for Haar-random :math:`U_{3}` (``qibo.gates.U3``). Args: ngates (int): Total number of :math:`U_{3}`s to be sampled. From f73be7c9b730edefddab7ee1b68723589e07cf01 Mon Sep 17 00:00:00 2001 From: Matteo Robbiati <62071516+MatteoRobbiati@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:38:41 +0100 Subject: [PATCH 193/200] Update random_ensembles.py --- src/qibo/quantum_info/random_ensembles.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 3571274770..d16b77f416 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -32,8 +32,7 @@ def _ppf(self, theta: float): def uniform_sampling_U3(ngates: int, seed=None, backend=None): - """ - Samples parameters for Haar-random :math:`U_{3}` (``qibo.gates.U3``). + """Samples parameters for Haar-random :math:`U_{3}` (``qibo.gates.U3``). Args: ngates (int): Total number of :math:`U_{3}`s to be sampled. From 7e747784e82334507c975c58e40bb55955c7b4c6 Mon Sep 17 00:00:00 2001 From: scarrazza Date: Fri, 16 Feb 2024 06:09:01 +0100 Subject: [PATCH 194/200] adding missing deps --- poetry.lock | 1506 ++++++++++++++++++++++++------------------------ pyproject.toml | 6 + 2 files changed, 764 insertions(+), 748 deletions(-) diff --git a/poetry.lock b/poetry.lock index d9f70f1364..80c9adaac1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,24 +2,24 @@ [[package]] name = "absl-py" -version = "2.0.0" +version = "2.1.0" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." optional = false python-versions = ">=3.7" files = [ - {file = "absl-py-2.0.0.tar.gz", hash = "sha256:d9690211c5fcfefcdd1a45470ac2b5c5acd45241c3af71eed96bc5441746c0d5"}, - {file = "absl_py-2.0.0-py3-none-any.whl", hash = "sha256:9a28abb62774ae4e8edbe2dd4c49ffcd45a6a848952a5eccc6a49f3f0fc1e2f3"}, + {file = "absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff"}, + {file = "absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308"}, ] [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] @@ -46,13 +46,13 @@ trio = ["trio (>=0.23)"] [[package]] name = "astroid" -version = "3.0.2" +version = "3.0.3" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.8.0" files = [ - {file = "astroid-3.0.2-py3-none-any.whl", hash = "sha256:d6e62862355f60e716164082d6b4b041d38e2a8cf1c7cd953ded5108bac8ff5c"}, - {file = "astroid-3.0.2.tar.gz", hash = "sha256:4a61cf0a59097c7bb52689b0fd63717cd2a8a14dc9f1eee97b82d814881c8c91"}, + {file = "astroid-3.0.3-py3-none-any.whl", hash = "sha256:92fcf218b89f449cdf9f7b39a269f8d5d617b27be68434912e11e79203963a17"}, + {file = "astroid-3.0.3.tar.gz", hash = "sha256:4148645659b08b70d72460ed1921158027a9e53ae8b7234149b1400eddacbb93"}, ] [package.dependencies] @@ -124,19 +124,22 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] @@ -171,13 +174,13 @@ files = [ [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -557,13 +560,13 @@ files = [ [[package]] name = "comm" -version = "0.2.0" +version = "0.2.1" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" files = [ - {file = "comm-0.2.0-py3-none-any.whl", hash = "sha256:2da8d9ebb8dd7bfc247adaff99f24dce705638a8042b85cb995066793e391001"}, - {file = "comm-0.2.0.tar.gz", hash = "sha256:a517ea2ca28931c7007a7a99c562a0fa5883cfb48963140cf642c41c948498be"}, + {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, + {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, ] [package.dependencies] @@ -651,63 +654,63 @@ test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.3.4" +version = "7.4.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aff2bd3d585969cc4486bfc69655e862028b689404563e6b549e6a8244f226df"}, - {file = "coverage-7.3.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4353923f38d752ecfbd3f1f20bf7a3546993ae5ecd7c07fd2f25d40b4e54571"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea473c37872f0159294f7073f3fa72f68b03a129799f3533b2bb44d5e9fa4f82"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5214362abf26e254d749fc0c18af4c57b532a4bfde1a057565616dd3b8d7cc94"}, - {file = "coverage-7.3.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f99b7d3f7a7adfa3d11e3a48d1a91bb65739555dd6a0d3fa68aa5852d962e5b1"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:74397a1263275bea9d736572d4cf338efaade2de9ff759f9c26bcdceb383bb49"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f154bd866318185ef5865ace5be3ac047b6d1cc0aeecf53bf83fe846f4384d5d"}, - {file = "coverage-7.3.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e0d84099ea7cba9ff467f9c6f747e3fc3906e2aadac1ce7b41add72e8d0a3712"}, - {file = "coverage-7.3.4-cp310-cp310-win32.whl", hash = "sha256:3f477fb8a56e0c603587b8278d9dbd32e54bcc2922d62405f65574bd76eba78a"}, - {file = "coverage-7.3.4-cp310-cp310-win_amd64.whl", hash = "sha256:c75738ce13d257efbb6633a049fb2ed8e87e2e6c2e906c52d1093a4d08d67c6b"}, - {file = "coverage-7.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:997aa14b3e014339d8101b9886063c5d06238848905d9ad6c6eabe533440a9a7"}, - {file = "coverage-7.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a9c5bc5db3eb4cd55ecb8397d8e9b70247904f8eca718cc53c12dcc98e59fc8"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27ee94f088397d1feea3cb524e4313ff0410ead7d968029ecc4bc5a7e1d34fbf"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ce03e25e18dd9bf44723e83bc202114817f3367789052dc9e5b5c79f40cf59d"}, - {file = "coverage-7.3.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85072e99474d894e5df582faec04abe137b28972d5e466999bc64fc37f564a03"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a877810ef918d0d345b783fc569608804f3ed2507bf32f14f652e4eaf5d8f8d0"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9ac17b94ab4ca66cf803f2b22d47e392f0977f9da838bf71d1f0db6c32893cb9"}, - {file = "coverage-7.3.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:36d75ef2acab74dc948d0b537ef021306796da551e8ac8b467810911000af66a"}, - {file = "coverage-7.3.4-cp311-cp311-win32.whl", hash = "sha256:47ee56c2cd445ea35a8cc3ad5c8134cb9bece3a5cb50bb8265514208d0a65928"}, - {file = "coverage-7.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:11ab62d0ce5d9324915726f611f511a761efcca970bd49d876cf831b4de65be5"}, - {file = "coverage-7.3.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:33e63c578f4acce1b6cd292a66bc30164495010f1091d4b7529d014845cd9bee"}, - {file = "coverage-7.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:782693b817218169bfeb9b9ba7f4a9f242764e180ac9589b45112571f32a0ba6"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c4277ddaad9293454da19121c59f2d850f16bcb27f71f89a5c4836906eb35ef"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d892a19ae24b9801771a5a989fb3e850bd1ad2e2b6e83e949c65e8f37bc67a1"}, - {file = "coverage-7.3.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3024ec1b3a221bd10b5d87337d0373c2bcaf7afd86d42081afe39b3e1820323b"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1c3e9d2bbd6f3f79cfecd6f20854f4dc0c6e0ec317df2b265266d0dc06535f1"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e91029d7f151d8bf5ab7d8bfe2c3dbefd239759d642b211a677bc0709c9fdb96"}, - {file = "coverage-7.3.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6879fe41c60080aa4bb59703a526c54e0412b77e649a0d06a61782ecf0853ee1"}, - {file = "coverage-7.3.4-cp312-cp312-win32.whl", hash = "sha256:fd2f8a641f8f193968afdc8fd1697e602e199931012b574194052d132a79be13"}, - {file = "coverage-7.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:d1d0ce6c6947a3a4aa5479bebceff2c807b9f3b529b637e2b33dea4468d75fc7"}, - {file = "coverage-7.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:36797b3625d1da885b369bdaaa3b0d9fb8865caed3c2b8230afaa6005434aa2f"}, - {file = "coverage-7.3.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfed0ec4b419fbc807dec417c401499ea869436910e1ca524cfb4f81cf3f60e7"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f97ff5a9fc2ca47f3383482858dd2cb8ddbf7514427eecf5aa5f7992d0571429"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607b6c6b35aa49defaebf4526729bd5238bc36fe3ef1a417d9839e1d96ee1e4c"}, - {file = "coverage-7.3.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8e258dcc335055ab59fe79f1dec217d9fb0cdace103d6b5c6df6b75915e7959"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a02ac7c51819702b384fea5ee033a7c202f732a2a2f1fe6c41e3d4019828c8d3"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b710869a15b8caf02e31d16487a931dbe78335462a122c8603bb9bd401ff6fb2"}, - {file = "coverage-7.3.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6a23ae9348a7a92e7f750f9b7e828448e428e99c24616dec93a0720342f241d"}, - {file = "coverage-7.3.4-cp38-cp38-win32.whl", hash = "sha256:758ebaf74578b73f727acc4e8ab4b16ab6f22a5ffd7dd254e5946aba42a4ce76"}, - {file = "coverage-7.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:309ed6a559bc942b7cc721f2976326efbfe81fc2b8f601c722bff927328507dc"}, - {file = "coverage-7.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aefbb29dc56317a4fcb2f3857d5bce9b881038ed7e5aa5d3bcab25bd23f57328"}, - {file = "coverage-7.3.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:183c16173a70caf92e2dfcfe7c7a576de6fa9edc4119b8e13f91db7ca33a7923"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a4184dcbe4f98d86470273e758f1d24191ca095412e4335ff27b417291f5964"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93698ac0995516ccdca55342599a1463ed2e2d8942316da31686d4d614597ef9"}, - {file = "coverage-7.3.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb220b3596358a86361139edce40d97da7458412d412e1e10c8e1970ee8c09ab"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5b14abde6f8d969e6b9dd8c7a013d9a2b52af1235fe7bebef25ad5c8f47fa18"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:610afaf929dc0e09a5eef6981edb6a57a46b7eceff151947b836d869d6d567c1"}, - {file = "coverage-7.3.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d6ed790728fb71e6b8247bd28e77e99d0c276dff952389b5388169b8ca7b1c28"}, - {file = "coverage-7.3.4-cp39-cp39-win32.whl", hash = "sha256:c15fdfb141fcf6a900e68bfa35689e1256a670db32b96e7a931cab4a0e1600e5"}, - {file = "coverage-7.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:38d0b307c4d99a7aca4e00cad4311b7c51b7ac38fb7dea2abe0d182dd4008e05"}, - {file = "coverage-7.3.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b1e0f25ae99cf247abfb3f0fac7ae25739e4cd96bf1afa3537827c576b4847e5"}, - {file = "coverage-7.3.4.tar.gz", hash = "sha256:020d56d2da5bc22a0e00a5b0d54597ee91ad72446fa4cf1b97c35022f6b6dbf0"}, + {file = "coverage-7.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7"}, + {file = "coverage-7.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25"}, + {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c"}, + {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b"}, + {file = "coverage-7.4.1-cp310-cp310-win32.whl", hash = "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016"}, + {file = "coverage-7.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295"}, + {file = "coverage-7.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd"}, + {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1"}, + {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6"}, + {file = "coverage-7.4.1-cp311-cp311-win32.whl", hash = "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5"}, + {file = "coverage-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581"}, + {file = "coverage-7.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156"}, + {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1"}, + {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc"}, + {file = "coverage-7.4.1-cp312-cp312-win32.whl", hash = "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74"}, + {file = "coverage-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218"}, + {file = "coverage-7.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06"}, + {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60"}, + {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad"}, + {file = "coverage-7.4.1-cp38-cp38-win32.whl", hash = "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042"}, + {file = "coverage-7.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54"}, + {file = "coverage-7.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950"}, + {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756"}, + {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35"}, + {file = "coverage-7.4.1-cp39-cp39-win32.whl", hash = "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c"}, + {file = "coverage-7.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a"}, + {file = "coverage-7.4.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166"}, + {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"}, ] [package.dependencies] @@ -899,32 +902,32 @@ cutensor-cu12 = ">=1.6.1,<2" [[package]] name = "cvxpy" -version = "1.4.1" +version = "1.4.2" description = "A domain-specific language for modeling convex optimization problems in Python." optional = false python-versions = ">=3.8" files = [ - {file = "cvxpy-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:03588055b660c043848f5281fe24dbd21f005b34bd8bd3b56906d8ad457c14ae"}, - {file = "cvxpy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:315609ff96adeda4970471b349bc19d44ff4043e15630cf5ac70c029658fe8fc"}, - {file = "cvxpy-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55e08ffb973d62b3fabc675ad464cb6013ea5ce69799f330b33a084a2e580d8d"}, - {file = "cvxpy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f1482558b785f2db51c76b9c6e91cc85dbd146675b126a799e7d7aab5b15354"}, - {file = "cvxpy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:2f84687d15d11f9b49ca902f20103a2076efd47773c399cace71237ef53cdadc"}, - {file = "cvxpy-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d6bfbd535fdaabc5fa55f28de7a1d40f3a803a27fe3fec86e90700fa159a3afc"}, - {file = "cvxpy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:71a95aaccf22431fd25a63bcb12d583e1b0baeaeb4fafa3e25857cec03b9e2f3"}, - {file = "cvxpy-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bae3bf31e4eb6ed6407f78c6bc3c7bc4b4145cdbbb9ba8c61c3fc541d7067"}, - {file = "cvxpy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41cfaecf86f85162ca53c7be7377b4143e316204fb9b6a7df8b7a08c826e3806"}, - {file = "cvxpy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:edf66010e49b64d3f2dd1a7abde8fa3e615ce7a2b3eb185ab744b0beb3a6adb9"}, - {file = "cvxpy-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6b0f17dca85b2a410e73f5d84b28f35f57a20cfec1b0adc9b16f0f8aabff9961"}, - {file = "cvxpy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9318c4e679b3db470e76e7f23cce362b038bd2d68c4a7326a7c21577ddbdc542"}, - {file = "cvxpy-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46ef722c8d1590875e86360d5781703dfcbd08be73eb98a2fc91a280870064"}, - {file = "cvxpy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57593a852c563ce77bdb075a3e75f23d36d4b3162ebf3199b54cc7fe75088ef2"}, - {file = "cvxpy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:db89b55025514bad821b1f1781bed373cbb6aa22fe84420431efd510dbe7f858"}, - {file = "cvxpy-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:372c0825cc6e6bb03ecc550d83718761a1bbdbbb48010fec6f9718581ebd45b5"}, - {file = "cvxpy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163caffd7f7f27b6cb151f4ccff283068e063c3673158793048761690cbe4bbe"}, - {file = "cvxpy-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f24067c54979b09910aea0a03256247121d8a8169538facf087c1923e9e2701a"}, - {file = "cvxpy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a3ec054279880a9ebf5fd9d2ac4109acf944b8c45ea8b24e461680e34f3d7b5"}, - {file = "cvxpy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:d220a7ee55907da9b55b98e5238d03735118d03b82855ba87b872cb2e6977367"}, - {file = "cvxpy-1.4.1.tar.gz", hash = "sha256:7a9ef34e3c57ff8c844d86f0a3834fb5575af19233947639de0ba577c6122e3e"}, + {file = "cvxpy-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:06231c0b2a65f7c8ba32c2772576c24e93e1ca964444b90c6bad366b9c0a5bdc"}, + {file = "cvxpy-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f257971b007261d53ec7f50618f0c6a511387dd7df6cd686d2647c3fa91da0eb"}, + {file = "cvxpy-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38c2191d4142baac206ac590ba9e5cb1c6e025ac95d0a746692c9cf8d1afd46e"}, + {file = "cvxpy-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9d006f76925127cd42b80e2d98c950a8339f8204b4c23fa25af83d895e95fa"}, + {file = "cvxpy-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:2a09ebd8f7a8b6b5d026d03295daee0780e2f6847fbe6f207e9764045ffbbfc9"}, + {file = "cvxpy-1.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:079fe6aeaeec2ddf6163ff8ca6510afd5c2b66ea391605791a77b51e534b935e"}, + {file = "cvxpy-1.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8419dffcadefc16e6fcbe8a088068c29edb1f28ea90582f075a96f21ae7ff11"}, + {file = "cvxpy-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6551ef3b325d707e98f920dd120ebaa968f3ac3484c21f8567f2081967d26f0"}, + {file = "cvxpy-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea513f4bf83491a1c9e5366faa4ca9fc21ec9522c30bcd55e49de9bb85fe9a2"}, + {file = "cvxpy-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:78560a02607d16fbb26db6306e7ce6d8e4fcda49cf04578d199ac050c2e74daa"}, + {file = "cvxpy-1.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9817cf8da86641e2d322911844e86b8e7b1d93d9b2d57ae6d33e84be430e1e04"}, + {file = "cvxpy-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:32999d550a923c9448d973ef9d3ab75d73e1bdf56102fc32fe7ccb5e0cb5d7a3"}, + {file = "cvxpy-1.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213b465450f4254226e6c18c70e25e911ae2c60176621f1bc2d9a0eb874288db"}, + {file = "cvxpy-1.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec30efa81d1f79f668b0fa6e8ac654047db7a3e844ab16022e1b5dcf52177192"}, + {file = "cvxpy-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:779c19be964f7a586337fd4d017c7a0202bf845e08b04a174850f962b45b2a00"}, + {file = "cvxpy-1.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bb1d6af8406efa1de0408d0a76c248da3185cade49f45c443239772830b7d6bb"}, + {file = "cvxpy-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:63102885fdfd3eae716c042ee7aad9439d0b71ba22e5432c85f0e35056fcb159"}, + {file = "cvxpy-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20015b82117c0253ca803c4e174010067bda0eedb539503ba58b98e00acdd0f2"}, + {file = "cvxpy-1.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f73ff4f0e7bff1e438dc2b02490d7a8e1027c421057a7971b4ca4982c28d60"}, + {file = "cvxpy-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b7cfc6be34b288acade31b58a1e88b119487165d0ed877db9decf7fd676502f6"}, + {file = "cvxpy-1.4.2.tar.gz", hash = "sha256:0a386a5788dbd78b7b20dd071524ec636c8fa72b3628e69f1abc714c8f9811e5"}, ] [package.dependencies] @@ -1011,17 +1014,18 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "dill" -version = "0.3.7" +version = "0.3.8" description = "serialize all of Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, - {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, + {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, + {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, ] [package.extras] graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "docutils" @@ -1050,27 +1054,30 @@ dev-env = ["black (==22.3.0)", "isort (==5.7.*)", "mypy (==0.931.*)", "pylint (= [[package]] name = "ecos" -version = "2.0.12" +version = "2.0.13" description = "This is the Python package for ECOS: Embedded Cone Solver. See Github page for more information." optional = false python-versions = "*" files = [ - {file = "ecos-2.0.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:835298a299c88c207b3402fba60ad9b5688b59bbbf2ac34a46de5b37165d773a"}, - {file = "ecos-2.0.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608bc822ee8e070927ab3519169b13a1a0fe88f3d562212d6b5dbb1039776360"}, - {file = "ecos-2.0.12-cp310-cp310-win_amd64.whl", hash = "sha256:5184a9d8521ad1af90ffcd9902a6fa75c7bc473f37d30d86f97beda1033dfca2"}, - {file = "ecos-2.0.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eba07599084724eedc20b2862d5580eebebb09609f4740baadc78401cb99827c"}, - {file = "ecos-2.0.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4979dc2d1cb6667e371a45a61887068505c1305437eef104ed6ef16f4b6aa0e3"}, - {file = "ecos-2.0.12-cp311-cp311-win_amd64.whl", hash = "sha256:da8fbbca3feb83a9e27075d29b3765417d0c80af8ea83cbdc4a558cae7b564af"}, - {file = "ecos-2.0.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f70e4547966f530fd7715756f7a65d5b9b90b312b9d37f243ef9356c05e7d74c"}, - {file = "ecos-2.0.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:617be25d74222849622b0f82b94a11abcf1fae78ccaf69977b328321ee6ffa0b"}, - {file = "ecos-2.0.12-cp37-cp37m-win_amd64.whl", hash = "sha256:29d00164eaea66ed54697a3b361c575284a8bca54f2623381a0635806c7303a7"}, - {file = "ecos-2.0.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4e86671397d1d2cd7cccff8a9c45be0541b0c60af8b92a0ff3581c9ed869db67"}, - {file = "ecos-2.0.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:858a4dd3177bdc8cc6e362031732f5177b62138a1e4ef91c0dc3c6bd7d2d1248"}, - {file = "ecos-2.0.12-cp38-cp38-win_amd64.whl", hash = "sha256:528b02f53835bd1baeb2e23f8153b8d6cc2b3704e1768be6a1a972f542241670"}, - {file = "ecos-2.0.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e42bd4c19af6e04f76ccc85d941b1f1adc7faeee4d06d482395a6beb7bec895"}, - {file = "ecos-2.0.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6def54336a15b5a49bc3bfcaa36035e8557cae8a4853b17ca84f5a29c93bcaea"}, - {file = "ecos-2.0.12-cp39-cp39-win_amd64.whl", hash = "sha256:7af08941552fce108bd80145cdb6be7fa74477a20bacdac170800442cc7027d4"}, - {file = "ecos-2.0.12.tar.gz", hash = "sha256:f48816d73b87ae325556ea537b7c8743187311403c80e3832035224156337c4e"}, + {file = "ecos-2.0.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a1c1acf33b70f8657c25f07ec8d7b59bb01dbad39f072fa61fc956c2166ed979"}, + {file = "ecos-2.0.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ea88ee2c94192004d6be9c55a3c79f184eaba3bbf31474229045a1b0a8a1536"}, + {file = "ecos-2.0.13-cp310-cp310-win_amd64.whl", hash = "sha256:df8ae7fce79be9e5f79f0511c51a4824795de5154847fabe1a0288bc2ea349d3"}, + {file = "ecos-2.0.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88dd628bc6e77a069165fa5f50340e2856795c28e00e3fce213a04d7c41c584a"}, + {file = "ecos-2.0.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b2c969c7e22fd8a1d1cd0a90f4325d90572da23e2e923b0da6138ce62503d0"}, + {file = "ecos-2.0.13-cp311-cp311-win_amd64.whl", hash = "sha256:936890fb85a186360a5c8f228dd19acb760e234b38c598d0b46ab29644e31dfc"}, + {file = "ecos-2.0.13-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62ed497ab56017f1d7264eb56223826a984462b1d84fb850d10f0bec3490877d"}, + {file = "ecos-2.0.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf2b1384012bee9e58e5a2373905d3644f74a0ea000b307a239366fe7850c29c"}, + {file = "ecos-2.0.13-cp312-cp312-win_amd64.whl", hash = "sha256:2c1ea09069e32185912506f946bb6d1f144841ba1d1cd0217c67f72cbdf7a8fd"}, + {file = "ecos-2.0.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9f4a76a3e1165359e1704ec6b1b89d487858ec0d838d62a7268133d88221914"}, + {file = "ecos-2.0.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c2d4e0d3ada1a619ddd62fbf48ccbe9b738fdbef119945fe2a05566d03b85a"}, + {file = "ecos-2.0.13-cp37-cp37m-win_amd64.whl", hash = "sha256:84c72e1e5ffa41cd38352dcf0a8c25418f5bf04ed76a576db0daaf9a69f5568f"}, + {file = "ecos-2.0.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1979f1f17ec7f1a0fc45964d02d762393f9f427d965fe8a893e7b1476a9023c3"}, + {file = "ecos-2.0.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:059e6c29c89f47a490353e4f9336e96350a5102a97e1d8a2aaff796bcbe50058"}, + {file = "ecos-2.0.13-cp38-cp38-win_amd64.whl", hash = "sha256:30c7d0cce6c830da5b9ea25af0d47b203255639524eb4d03d1331c600958c834"}, + {file = "ecos-2.0.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42c15f1d79eb2ada532e9781b4aeb3ed84b1c7e38239ba4d6502c6a092d5b1"}, + {file = "ecos-2.0.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32fb33185f6dd94a1c798bc481eb86c9f4e832efec91f6ab0584e2fc26fd375e"}, + {file = "ecos-2.0.13-cp39-cp39-win_amd64.whl", hash = "sha256:68995ab12d363576dddb2d1f91ead3b9c8a8ca61f29000f0b1daef1b4e7b5b64"}, + {file = "ecos-2.0.13.tar.gz", hash = "sha256:f2a9dc108ade7faf6f6f4fad245f4714b7293c8767d2a351ead59428a94a98b9"}, ] [package.dependencies] @@ -1122,13 +1129,13 @@ pyrepl = ">=0.8.2" [[package]] name = "fastjsonschema" -version = "2.19.0" +version = "2.19.1" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.19.0-py3-none-any.whl", hash = "sha256:b9fd1a2dd6971dbc7fee280a95bd199ae0dd9ce22beb91cc75e9c1c528a5170e"}, - {file = "fastjsonschema-2.19.0.tar.gz", hash = "sha256:e25df6647e1bc4a26070b700897b07b542ec898dd4f1f6ea013e7f6a88417225"}, + {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, + {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, ] [package.extras] @@ -1231,60 +1238,60 @@ files = [ [[package]] name = "fonttools" -version = "4.47.0" +version = "4.49.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d2404107626f97a221dc1a65b05396d2bb2ce38e435f64f26ed2369f68675d9"}, - {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01f409be619a9a0f5590389e37ccb58b47264939f0e8d58bfa1f3ba07d22671"}, - {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d986b66ff722ef675b7ee22fbe5947a41f60a61a4da15579d5e276d897fbc7fa"}, - {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8acf6dd0434b211b3bd30d572d9e019831aae17a54016629fa8224783b22df8"}, - {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:495369c660e0c27233e3c572269cbe520f7f4978be675f990f4005937337d391"}, - {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c59227d7ba5b232281c26ae04fac2c73a79ad0e236bca5c44aae904a18f14faf"}, - {file = "fonttools-4.47.0-cp310-cp310-win32.whl", hash = "sha256:59a6c8b71a245800e923cb684a2dc0eac19c56493e2f896218fcf2571ed28984"}, - {file = "fonttools-4.47.0-cp310-cp310-win_amd64.whl", hash = "sha256:52c82df66201f3a90db438d9d7b337c7c98139de598d0728fb99dab9fd0495ca"}, - {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:854421e328d47d70aa5abceacbe8eef231961b162c71cbe7ff3f47e235e2e5c5"}, - {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:511482df31cfea9f697930f61520f6541185fa5eeba2fa760fe72e8eee5af88b"}, - {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0e2c88c8c985b7b9a7efcd06511fb0a1fe3ddd9a6cd2895ef1dbf9059719d7"}, - {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7a0a8848726956e9d9fb18c977a279013daadf0cbb6725d2015a6dd57527992"}, - {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e869da810ae35afb3019baa0d0306cdbab4760a54909c89ad8904fa629991812"}, - {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dd23848f877c3754f53a4903fb7a593ed100924f9b4bff7d5a4e2e8a7001ae11"}, - {file = "fonttools-4.47.0-cp311-cp311-win32.whl", hash = "sha256:bf1810635c00f7c45d93085611c995fc130009cec5abdc35b327156aa191f982"}, - {file = "fonttools-4.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:61df4dee5d38ab65b26da8efd62d859a1eef7a34dcbc331299a28e24d04c59a7"}, - {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e3f4d61f3a8195eac784f1d0c16c0a3105382c1b9a74d99ac4ba421da39a8826"}, - {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:174995f7b057e799355b393e97f4f93ef1f2197cbfa945e988d49b2a09ecbce8"}, - {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea592e6a09b71cb7a7661dd93ac0b877a6228e2d677ebacbad0a4d118494c86d"}, - {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40bdbe90b33897d9cc4a39f8e415b0fcdeae4c40a99374b8a4982f127ff5c767"}, - {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:843509ae9b93db5aaf1a6302085e30bddc1111d31e11d724584818f5b698f500"}, - {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9acfa1cdc479e0dde528b61423855913d949a7f7fe09e276228298fef4589540"}, - {file = "fonttools-4.47.0-cp312-cp312-win32.whl", hash = "sha256:66c92ec7f95fd9732550ebedefcd190a8d81beaa97e89d523a0d17198a8bda4d"}, - {file = "fonttools-4.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8fa20748de55d0021f83754b371432dca0439e02847962fc4c42a0e444c2d78"}, - {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c75e19971209fbbce891ebfd1b10c37320a5a28e8d438861c21d35305aedb81c"}, - {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e79f1a3970d25f692bbb8c8c2637e621a66c0d60c109ab48d4a160f50856deff"}, - {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:562681188c62c024fe2c611b32e08b8de2afa00c0c4e72bed47c47c318e16d5c"}, - {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a77a60315c33393b2bd29d538d1ef026060a63d3a49a9233b779261bad9c3f71"}, - {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4fabb8cc9422efae1a925160083fdcbab8fdc96a8483441eb7457235df625bd"}, - {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a78dba8c2a1e9d53a0fb5382979f024200dc86adc46a56cbb668a2249862fda"}, - {file = "fonttools-4.47.0-cp38-cp38-win32.whl", hash = "sha256:e6b968543fde4119231c12c2a953dcf83349590ca631ba8216a8edf9cd4d36a9"}, - {file = "fonttools-4.47.0-cp38-cp38-win_amd64.whl", hash = "sha256:4a9a51745c0439516d947480d4d884fa18bd1458e05b829e482b9269afa655bc"}, - {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62d8ddb058b8e87018e5dc26f3258e2c30daad4c87262dfeb0e2617dd84750e6"}, - {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dde0eab40faaa5476133123f6a622a1cc3ac9b7af45d65690870620323308b4"}, - {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4da089f6dfdb822293bde576916492cd708c37c2501c3651adde39804630538"}, - {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:253bb46bab970e8aae254cebf2ae3db98a4ef6bd034707aa68a239027d2b198d"}, - {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1193fb090061efa2f9e2d8d743ae9850c77b66746a3b32792324cdce65784154"}, - {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:084511482dd265bce6dca24c509894062f0117e4e6869384d853f46c0e6d43be"}, - {file = "fonttools-4.47.0-cp39-cp39-win32.whl", hash = "sha256:97620c4af36e4c849e52661492e31dc36916df12571cb900d16960ab8e92a980"}, - {file = "fonttools-4.47.0-cp39-cp39-win_amd64.whl", hash = "sha256:e77bdf52185bdaf63d39f3e1ac3212e6cfa3ab07d509b94557a8902ce9c13c82"}, - {file = "fonttools-4.47.0-py3-none-any.whl", hash = "sha256:d6477ba902dd2d7adda7f0fd3bfaeb92885d45993c9e1928c9f28fc3961415f7"}, - {file = "fonttools-4.47.0.tar.gz", hash = "sha256:ec13a10715eef0e031858c1c23bfaee6cba02b97558e4a7bfa089dba4a8c2ebf"}, + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d970ecca0aac90d399e458f0b7a8a597e08f95de021f17785fb68e2dc0b99717"}, + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac9a745b7609f489faa65e1dc842168c18530874a5f5b742ac3dd79e26bca8bc"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ba0e00620ca28d4ca11fc700806fd69144b463aa3275e1b36e56c7c09915559"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdee3ab220283057e7840d5fb768ad4c2ebe65bdba6f75d5d7bf47f4e0ed7d29"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ce7033cb61f2bb65d8849658d3786188afd80f53dad8366a7232654804529532"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:07bc5ea02bb7bc3aa40a1eb0481ce20e8d9b9642a9536cde0218290dd6085828"}, + {file = "fonttools-4.49.0-cp310-cp310-win32.whl", hash = "sha256:86eef6aab7fd7c6c8545f3ebd00fd1d6729ca1f63b0cb4d621bccb7d1d1c852b"}, + {file = "fonttools-4.49.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fac1b7eebfce75ea663e860e7c5b4a8831b858c17acd68263bc156125201abf"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:edc0cce355984bb3c1d1e89d6a661934d39586bb32191ebff98c600f8957c63e"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:83a0d9336de2cba86d886507dd6e0153df333ac787377325a39a2797ec529814"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36c8865bdb5cfeec88f5028e7e592370a0657b676c6f1d84a2108e0564f90e22"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33037d9e56e2562c710c8954d0f20d25b8386b397250d65581e544edc9d6b942"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8fb022d799b96df3eaa27263e9eea306bd3d437cc9aa981820850281a02b6c9a"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33c584c0ef7dc54f5dd4f84082eabd8d09d1871a3d8ca2986b0c0c98165f8e86"}, + {file = "fonttools-4.49.0-cp311-cp311-win32.whl", hash = "sha256:cbe61b158deb09cffdd8540dc4a948d6e8f4d5b4f3bf5cd7db09bd6a61fee64e"}, + {file = "fonttools-4.49.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc11e5114f3f978d0cea7e9853627935b30d451742eeb4239a81a677bdee6bf6"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d647a0e697e5daa98c87993726da8281c7233d9d4ffe410812a4896c7c57c075"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f3bbe672df03563d1f3a691ae531f2e31f84061724c319652039e5a70927167e"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bebd91041dda0d511b0d303180ed36e31f4f54b106b1259b69fade68413aa7ff"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4145f91531fd43c50f9eb893faa08399816bb0b13c425667c48475c9f3a2b9b5"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea329dafb9670ffbdf4dbc3b0e5c264104abcd8441d56de77f06967f032943cb"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c076a9e548521ecc13d944b1d261ff3d7825048c338722a4bd126d22316087b7"}, + {file = "fonttools-4.49.0-cp312-cp312-win32.whl", hash = "sha256:b607ea1e96768d13be26d2b400d10d3ebd1456343eb5eaddd2f47d1c4bd00880"}, + {file = "fonttools-4.49.0-cp312-cp312-win_amd64.whl", hash = "sha256:a974c49a981e187381b9cc2c07c6b902d0079b88ff01aed34695ec5360767034"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b85ec0bdd7bdaa5c1946398cbb541e90a6dfc51df76dfa88e0aaa41b335940cb"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af20acbe198a8a790618ee42db192eb128afcdcc4e96d99993aca0b60d1faeb4"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d418b1fee41a1d14931f7ab4b92dc0bc323b490e41d7a333eec82c9f1780c75"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44a52b8e6244b6548851b03b2b377a9702b88ddc21dcaf56a15a0393d425cb9"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7125068e04a70739dad11857a4d47626f2b0bd54de39e8622e89701836eabd"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29e89d0e1a7f18bc30f197cfadcbef5a13d99806447c7e245f5667579a808036"}, + {file = "fonttools-4.49.0-cp38-cp38-win32.whl", hash = "sha256:9d95fa0d22bf4f12d2fb7b07a46070cdfc19ef5a7b1c98bc172bfab5bf0d6844"}, + {file = "fonttools-4.49.0-cp38-cp38-win_amd64.whl", hash = "sha256:768947008b4dc552d02772e5ebd49e71430a466e2373008ce905f953afea755a"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08877e355d3dde1c11973bb58d4acad1981e6d1140711230a4bfb40b2b937ccc"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fdb54b076f25d6b0f0298dc706acee5052de20c83530fa165b60d1f2e9cbe3cb"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0af65c720520710cc01c293f9c70bd69684365c6015cc3671db2b7d807fe51f2"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f255ce8ed7556658f6d23f6afd22a6d9bbc3edb9b96c96682124dc487e1bf42"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d00af0884c0e65f60dfaf9340e26658836b935052fdd0439952ae42e44fdd2be"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:263832fae27481d48dfafcc43174644b6706639661e242902ceb30553557e16c"}, + {file = "fonttools-4.49.0-cp39-cp39-win32.whl", hash = "sha256:0404faea044577a01bb82d47a8fa4bc7a54067fa7e324785dd65d200d6dd1133"}, + {file = "fonttools-4.49.0-cp39-cp39-win_amd64.whl", hash = "sha256:b050d362df50fc6e38ae3954d8c29bf2da52be384649ee8245fdb5186b620836"}, + {file = "fonttools-4.49.0-py3-none-any.whl", hash = "sha256:af281525e5dd7fa0b39fb1667b8d5ca0e2a9079967e14c4bfe90fd1cd13e0f18"}, + {file = "fonttools-4.49.0.tar.gz", hash = "sha256:ebf46e7f01b7af7861310417d7c49591a85d99146fc23a5ba82fdb28af156321"}, ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0,<5)"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] @@ -1334,13 +1341,13 @@ files = [ [[package]] name = "google-api-core" -version = "2.15.0" +version = "2.17.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.15.0.tar.gz", hash = "sha256:abc978a72658f14a2df1e5e12532effe40f94f868f6e23d95133bd6abcca35ca"}, - {file = "google_api_core-2.15.0-py3-none-any.whl", hash = "sha256:2aa56d2be495551e66bbff7f729b790546f87d5c90e74781aa77233bcb395a8a"}, + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, ] [package.dependencies] @@ -1364,13 +1371,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.25.2" +version = "2.28.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.25.2.tar.gz", hash = "sha256:42f707937feb4f5e5a39e6c4f343a17300a459aaf03141457ba505812841cc40"}, - {file = "google_auth-2.25.2-py2.py3-none-any.whl", hash = "sha256:473a8dfd0135f75bb79d878436e568f2695dce456764bf3a02b6f8c540b1d256"}, + {file = "google-auth-2.28.0.tar.gz", hash = "sha256:3cfc1b6e4e64797584fb53fc9bd0b7afa9b7c0dba2004fa7dcc9349e58cc3195"}, + {file = "google_auth-2.28.0-py2.py3-none-any.whl", hash = "sha256:7634d29dcd1e101f5226a23cbc4a0c6cda6394253bf80e281d9c5c6797869c53"}, ] [package.dependencies] @@ -1387,13 +1394,13 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-auth-oauthlib" -version = "1.0.0" +version = "1.2.0" description = "Google Authentication Library" optional = false python-versions = ">=3.6" files = [ - {file = "google-auth-oauthlib-1.0.0.tar.gz", hash = "sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5"}, - {file = "google_auth_oauthlib-1.0.0-py2.py3-none-any.whl", hash = "sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb"}, + {file = "google-auth-oauthlib-1.2.0.tar.gz", hash = "sha256:292d2d3783349f2b0734a0a0207b1e1e322ac193c2c09d8f7c613fb7cc501ea8"}, + {file = "google_auth_oauthlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:297c1ce4cb13a99b5834c74a1fe03252e1e499716718b190f56bcb9c4abc4faf"}, ] [package.dependencies] @@ -1437,84 +1444,84 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "grpcio" -version = "1.60.0" +version = "1.60.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.60.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:d020cfa595d1f8f5c6b343530cd3ca16ae5aefdd1e832b777f9f0eb105f5b139"}, - {file = "grpcio-1.60.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b98f43fcdb16172dec5f4b49f2fece4b16a99fd284d81c6bbac1b3b69fcbe0ff"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:20e7a4f7ded59097c84059d28230907cd97130fa74f4a8bfd1d8e5ba18c81491"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452ca5b4afed30e7274445dd9b441a35ece656ec1600b77fff8c216fdf07df43"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43e636dc2ce9ece583b3e2ca41df5c983f4302eabc6d5f9cd04f0562ee8ec1ae"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e306b97966369b889985a562ede9d99180def39ad42c8014628dd3cc343f508"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f897c3b127532e6befdcf961c415c97f320d45614daf84deba0a54e64ea2457b"}, - {file = "grpcio-1.60.0-cp310-cp310-win32.whl", hash = "sha256:b87efe4a380887425bb15f220079aa8336276398dc33fce38c64d278164f963d"}, - {file = "grpcio-1.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:a9c7b71211f066908e518a2ef7a5e211670761651039f0d6a80d8d40054047df"}, - {file = "grpcio-1.60.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:fb464479934778d7cc5baf463d959d361954d6533ad34c3a4f1d267e86ee25fd"}, - {file = "grpcio-1.60.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4b44d7e39964e808b071714666a812049765b26b3ea48c4434a3b317bac82f14"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:90bdd76b3f04bdb21de5398b8a7c629676c81dfac290f5f19883857e9371d28c"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91229d7203f1ef0ab420c9b53fe2ca5c1fbeb34f69b3bc1b5089466237a4a134"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b36a2c6d4920ba88fa98075fdd58ff94ebeb8acc1215ae07d01a418af4c0253"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:297eef542156d6b15174a1231c2493ea9ea54af8d016b8ca7d5d9cc65cfcc444"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:87c9224acba0ad8bacddf427a1c2772e17ce50b3042a789547af27099c5f751d"}, - {file = "grpcio-1.60.0-cp311-cp311-win32.whl", hash = "sha256:95ae3e8e2c1b9bf671817f86f155c5da7d49a2289c5cf27a319458c3e025c320"}, - {file = "grpcio-1.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:467a7d31554892eed2aa6c2d47ded1079fc40ea0b9601d9f79204afa8902274b"}, - {file = "grpcio-1.60.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:a7152fa6e597c20cb97923407cf0934e14224af42c2b8d915f48bc3ad2d9ac18"}, - {file = "grpcio-1.60.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:7db16dd4ea1b05ada504f08d0dca1cd9b926bed3770f50e715d087c6f00ad748"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:b0571a5aef36ba9177e262dc88a9240c866d903a62799e44fd4aae3f9a2ec17e"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fd9584bf1bccdfff1512719316efa77be235469e1e3295dce64538c4773840b"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6a478581b1a1a8fdf3318ecb5f4d0cda41cacdffe2b527c23707c9c1b8fdb55"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:77c8a317f0fd5a0a2be8ed5cbe5341537d5c00bb79b3bb27ba7c5378ba77dbca"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1c30bb23a41df95109db130a6cc1b974844300ae2e5d68dd4947aacba5985aa5"}, - {file = "grpcio-1.60.0-cp312-cp312-win32.whl", hash = "sha256:2aef56e85901c2397bd557c5ba514f84de1f0ae5dd132f5d5fed042858115951"}, - {file = "grpcio-1.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:e381fe0c2aa6c03b056ad8f52f8efca7be29fb4d9ae2f8873520843b6039612a"}, - {file = "grpcio-1.60.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:92f88ca1b956eb8427a11bb8b4a0c0b2b03377235fc5102cb05e533b8693a415"}, - {file = "grpcio-1.60.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:e278eafb406f7e1b1b637c2cf51d3ad45883bb5bd1ca56bc05e4fc135dfdaa65"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:a48edde788b99214613e440fce495bbe2b1e142a7f214cce9e0832146c41e324"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de2ad69c9a094bf37c1102b5744c9aec6cf74d2b635558b779085d0263166454"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:073f959c6f570797272f4ee9464a9997eaf1e98c27cb680225b82b53390d61e6"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c826f93050c73e7769806f92e601e0efdb83ec8d7c76ddf45d514fee54e8e619"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e30be89a75ee66aec7f9e60086fadb37ff8c0ba49a022887c28c134341f7179"}, - {file = "grpcio-1.60.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b0fb2d4801546598ac5cd18e3ec79c1a9af8b8f2a86283c55a5337c5aeca4b1b"}, - {file = "grpcio-1.60.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:9073513ec380434eb8d21970e1ab3161041de121f4018bbed3146839451a6d8e"}, - {file = "grpcio-1.60.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:74d7d9fa97809c5b892449b28a65ec2bfa458a4735ddad46074f9f7d9550ad13"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1434ca77d6fed4ea312901122dc8da6c4389738bf5788f43efb19a838ac03ead"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e61e76020e0c332a98290323ecfec721c9544f5b739fab925b6e8cbe1944cf19"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675997222f2e2f22928fbba640824aebd43791116034f62006e19730715166c0"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5208a57eae445ae84a219dfd8b56e04313445d146873117b5fa75f3245bc1390"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:428d699c8553c27e98f4d29fdc0f0edc50e9a8a7590bfd294d2edb0da7be3629"}, - {file = "grpcio-1.60.0-cp38-cp38-win32.whl", hash = "sha256:83f2292ae292ed5a47cdcb9821039ca8e88902923198f2193f13959360c01860"}, - {file = "grpcio-1.60.0-cp38-cp38-win_amd64.whl", hash = "sha256:705a68a973c4c76db5d369ed573fec3367d7d196673fa86614b33d8c8e9ebb08"}, - {file = "grpcio-1.60.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c193109ca4070cdcaa6eff00fdb5a56233dc7610216d58fb81638f89f02e4968"}, - {file = "grpcio-1.60.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:676e4a44e740deaba0f4d95ba1d8c5c89a2fcc43d02c39f69450b1fa19d39590"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5ff21e000ff2f658430bde5288cb1ac440ff15c0d7d18b5fb222f941b46cb0d2"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c86343cf9ff7b2514dd229bdd88ebba760bd8973dac192ae687ff75e39ebfab"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fd3b3968ffe7643144580f260f04d39d869fcc2cddb745deef078b09fd2b328"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:30943b9530fe3620e3b195c03130396cd0ee3a0d10a66c1bee715d1819001eaf"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b10241250cb77657ab315270b064a6c7f1add58af94befa20687e7c8d8603ae6"}, - {file = "grpcio-1.60.0-cp39-cp39-win32.whl", hash = "sha256:79a050889eb8d57a93ed21d9585bb63fca881666fc709f5d9f7f9372f5e7fd03"}, - {file = "grpcio-1.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a97a681e82bc11a42d4372fe57898d270a2707f36c45c6676e49ce0d5c41353"}, - {file = "grpcio-1.60.0.tar.gz", hash = "sha256:2199165a1affb666aa24adf0c97436686d0a61bc5fc113c037701fb7c7fceb96"}, + {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, + {file = "grpcio-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb"}, + {file = "grpcio-1.60.1-cp310-cp310-win32.whl", hash = "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1"}, + {file = "grpcio-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177"}, + {file = "grpcio-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303"}, + {file = "grpcio-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce"}, + {file = "grpcio-1.60.1-cp311-cp311-win32.whl", hash = "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd"}, + {file = "grpcio-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c"}, + {file = "grpcio-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9"}, + {file = "grpcio-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05"}, + {file = "grpcio-1.60.1-cp312-cp312-win32.whl", hash = "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21"}, + {file = "grpcio-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f"}, + {file = "grpcio-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594"}, + {file = "grpcio-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e"}, + {file = "grpcio-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de"}, + {file = "grpcio-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549"}, + {file = "grpcio-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a"}, + {file = "grpcio-1.60.1-cp38-cp38-win32.whl", hash = "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929"}, + {file = "grpcio-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872"}, + {file = "grpcio-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8"}, + {file = "grpcio-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6"}, + {file = "grpcio-1.60.1-cp39-cp39-win32.whl", hash = "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804"}, + {file = "grpcio-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904"}, + {file = "grpcio-1.60.1.tar.gz", hash = "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.60.0)"] +protobuf = ["grpcio-tools (>=1.60.1)"] [[package]] name = "grpcio-status" -version = "1.60.0" +version = "1.60.1" description = "Status proto mapping for gRPC" optional = false python-versions = ">=3.6" files = [ - {file = "grpcio-status-1.60.0.tar.gz", hash = "sha256:f10e0b6db3adc0fdc244b71962814ee982996ef06186446b5695b9fa635aa1ab"}, - {file = "grpcio_status-1.60.0-py3-none-any.whl", hash = "sha256:7d383fa36e59c1e61d380d91350badd4d12ac56e4de2c2b831b050362c3c572e"}, + {file = "grpcio-status-1.60.1.tar.gz", hash = "sha256:61b5aab8989498e8aa142c20b88829ea5d90d18c18c853b9f9e6d407d37bf8b4"}, + {file = "grpcio_status-1.60.1-py3-none-any.whl", hash = "sha256:3034fdb239185b6e0f3169d08c268c4507481e4b8a434c21311a03d9eb5889a0"}, ] [package.dependencies] googleapis-common-protos = ">=1.5.5" -grpcio = ">=1.60.0" +grpcio = ">=1.60.1" protobuf = ">=4.21.6" [[package]] @@ -1660,13 +1667,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.0" +version = "7.0.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, - {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] @@ -1745,21 +1752,21 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pa [[package]] name = "ipywidgets" -version = "8.1.1" +version = "8.1.2" description = "Jupyter interactive widgets" optional = false python-versions = ">=3.7" files = [ - {file = "ipywidgets-8.1.1-py3-none-any.whl", hash = "sha256:2b88d728656aea3bbfd05d32c747cfd0078f9d7e159cf982433b58ad717eed7f"}, - {file = "ipywidgets-8.1.1.tar.gz", hash = "sha256:40211efb556adec6fa450ccc2a77d59ca44a060f4f9f136833df59c9f538e6e8"}, + {file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"}, + {file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"}, ] [package.dependencies] comm = ">=0.1.3" ipython = ">=6.1.0" -jupyterlab-widgets = ">=3.0.9,<3.1.0" +jupyterlab-widgets = ">=3.0.10,<3.1.0" traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.9,<4.1.0" +widgetsnbextension = ">=4.0.10,<4.1.0" [package.extras] test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] @@ -1880,13 +1887,13 @@ test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pyt [[package]] name = "jupyter-core" -version = "5.5.1" +version = "5.7.1" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.5.1-py3-none-any.whl", hash = "sha256:220dfb00c45f0d780ce132bb7976b58263f81a3ada6e90a9b6823785a424f739"}, - {file = "jupyter_core-5.5.1.tar.gz", hash = "sha256:1553311a97ccd12936037f36b9ab4d6ae8ceea6ad2d5c90d94a909e752178e40"}, + {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, + {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, ] [package.dependencies] @@ -1911,24 +1918,24 @@ files = [ [[package]] name = "jupyterlab-widgets" -version = "3.0.9" +version = "3.0.10" description = "Jupyter interactive widgets for JupyterLab" optional = false python-versions = ">=3.7" files = [ - {file = "jupyterlab_widgets-3.0.9-py3-none-any.whl", hash = "sha256:3cf5bdf5b897bf3bccf1c11873aa4afd776d7430200f765e0686bd352487b58d"}, - {file = "jupyterlab_widgets-3.0.9.tar.gz", hash = "sha256:6005a4e974c7beee84060fdfba341a3218495046de8ae3ec64888e5fe19fdb4c"}, + {file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"}, + {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, ] [[package]] name = "keras" -version = "2.14.0" +version = "2.15.0" description = "Deep learning for humans." optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "keras-2.14.0-py3-none-any.whl", hash = "sha256:d7429d1d2131cc7eb1f2ea2ec330227c7d9d38dab3dfdf2e78defee4ecc43fcd"}, - {file = "keras-2.14.0.tar.gz", hash = "sha256:22788bdbc86d9988794fe9703bb5205141da797c4faeeb59497c58c3d94d34ed"}, + {file = "keras-2.15.0-py3-none-any.whl", hash = "sha256:2dcc6d2e30cf9c951064b63c1f4c404b966c59caf09e01f3549138ec8ee0dd1f"}, + {file = "keras-2.15.0.tar.gz", hash = "sha256:81871d298c064dc4ac6b58440fdae67bfcf47c8d7ad28580fab401834c06a575"}, ] [[package]] @@ -2095,46 +2102,43 @@ files = [ [[package]] name = "llvmlite" -version = "0.41.1" +version = "0.42.0" description = "lightweight wrapper around basic LLVM functionality" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "llvmlite-0.41.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1e1029d47ee66d3a0c4d6088641882f75b93db82bd0e6178f7bd744ebce42b9"}, - {file = "llvmlite-0.41.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:150d0bc275a8ac664a705135e639178883293cf08c1a38de3bbaa2f693a0a867"}, - {file = "llvmlite-0.41.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1eee5cf17ec2b4198b509272cf300ee6577229d237c98cc6e63861b08463ddc6"}, - {file = "llvmlite-0.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd0338da625346538f1173a17cabf21d1e315cf387ca21b294ff209d176e244"}, - {file = "llvmlite-0.41.1-cp310-cp310-win32.whl", hash = "sha256:fa1469901a2e100c17eb8fe2678e34bd4255a3576d1a543421356e9c14d6e2ae"}, - {file = "llvmlite-0.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:2b76acee82ea0e9304be6be9d4b3840208d050ea0dcad75b1635fa06e949a0ae"}, - {file = "llvmlite-0.41.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:210e458723436b2469d61b54b453474e09e12a94453c97ea3fbb0742ba5a83d8"}, - {file = "llvmlite-0.41.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:855f280e781d49e0640aef4c4af586831ade8f1a6c4df483fb901cbe1a48d127"}, - {file = "llvmlite-0.41.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b67340c62c93a11fae482910dc29163a50dff3dfa88bc874872d28ee604a83be"}, - {file = "llvmlite-0.41.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2181bb63ef3c607e6403813421b46982c3ac6bfc1f11fa16a13eaafb46f578e6"}, - {file = "llvmlite-0.41.1-cp311-cp311-win_amd64.whl", hash = "sha256:9564c19b31a0434f01d2025b06b44c7ed422f51e719ab5d24ff03b7560066c9a"}, - {file = "llvmlite-0.41.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5940bc901fb0325970415dbede82c0b7f3e35c2d5fd1d5e0047134c2c46b3281"}, - {file = "llvmlite-0.41.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8b0a9a47c28f67a269bb62f6256e63cef28d3c5f13cbae4fab587c3ad506778b"}, - {file = "llvmlite-0.41.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8afdfa6da33f0b4226af8e64cfc2b28986e005528fbf944d0a24a72acfc9432"}, - {file = "llvmlite-0.41.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8454c1133ef701e8c050a59edd85d238ee18bb9a0eb95faf2fca8b909ee3c89a"}, - {file = "llvmlite-0.41.1-cp38-cp38-win32.whl", hash = "sha256:2d92c51e6e9394d503033ffe3292f5bef1566ab73029ec853861f60ad5c925d0"}, - {file = "llvmlite-0.41.1-cp38-cp38-win_amd64.whl", hash = "sha256:df75594e5a4702b032684d5481db3af990b69c249ccb1d32687b8501f0689432"}, - {file = "llvmlite-0.41.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04725975e5b2af416d685ea0769f4ecc33f97be541e301054c9f741003085802"}, - {file = "llvmlite-0.41.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf14aa0eb22b58c231243dccf7e7f42f7beec48970f2549b3a6acc737d1a4ba4"}, - {file = "llvmlite-0.41.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c32356f669e036eb01016e883b22add883c60739bc1ebee3a1cc0249a50828"}, - {file = "llvmlite-0.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24091a6b31242bcdd56ae2dbea40007f462260bc9bdf947953acc39dffd54f8f"}, - {file = "llvmlite-0.41.1-cp39-cp39-win32.whl", hash = "sha256:880cb57ca49e862e1cd077104375b9d1dfdc0622596dfa22105f470d7bacb309"}, - {file = "llvmlite-0.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:92f093986ab92e71c9ffe334c002f96defc7986efda18397d0f08534f3ebdc4d"}, - {file = "llvmlite-0.41.1.tar.gz", hash = "sha256:f19f767a018e6ec89608e1f6b13348fa2fcde657151137cb64e56d48598a92db"}, + {file = "llvmlite-0.42.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3366938e1bf63d26c34fbfb4c8e8d2ded57d11e0567d5bb243d89aab1eb56098"}, + {file = "llvmlite-0.42.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c35da49666a21185d21b551fc3caf46a935d54d66969d32d72af109b5e7d2b6f"}, + {file = "llvmlite-0.42.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70f44ccc3c6220bd23e0ba698a63ec2a7d3205da0d848804807f37fc243e3f77"}, + {file = "llvmlite-0.42.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763f8d8717a9073b9e0246998de89929071d15b47f254c10eef2310b9aac033d"}, + {file = "llvmlite-0.42.0-cp310-cp310-win_amd64.whl", hash = "sha256:8d90edf400b4ceb3a0e776b6c6e4656d05c7187c439587e06f86afceb66d2be5"}, + {file = "llvmlite-0.42.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ae511caed28beaf1252dbaf5f40e663f533b79ceb408c874c01754cafabb9cbf"}, + {file = "llvmlite-0.42.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81e674c2fe85576e6c4474e8c7e7aba7901ac0196e864fe7985492b737dbab65"}, + {file = "llvmlite-0.42.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb3975787f13eb97629052edb5017f6c170eebc1c14a0433e8089e5db43bcce6"}, + {file = "llvmlite-0.42.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5bece0cdf77f22379f19b1959ccd7aee518afa4afbd3656c6365865f84903f9"}, + {file = "llvmlite-0.42.0-cp311-cp311-win_amd64.whl", hash = "sha256:7e0c4c11c8c2aa9b0701f91b799cb9134a6a6de51444eff5a9087fc7c1384275"}, + {file = "llvmlite-0.42.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:08fa9ab02b0d0179c688a4216b8939138266519aaa0aa94f1195a8542faedb56"}, + {file = "llvmlite-0.42.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b2fce7d355068494d1e42202c7aff25d50c462584233013eb4470c33b995e3ee"}, + {file = "llvmlite-0.42.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebe66a86dc44634b59a3bc860c7b20d26d9aaffcd30364ebe8ba79161a9121f4"}, + {file = "llvmlite-0.42.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d47494552559e00d81bfb836cf1c4d5a5062e54102cc5767d5aa1e77ccd2505c"}, + {file = "llvmlite-0.42.0-cp312-cp312-win_amd64.whl", hash = "sha256:05cb7e9b6ce69165ce4d1b994fbdedca0c62492e537b0cc86141b6e2c78d5888"}, + {file = "llvmlite-0.42.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bdd3888544538a94d7ec99e7c62a0cdd8833609c85f0c23fcb6c5c591aec60ad"}, + {file = "llvmlite-0.42.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0936c2067a67fb8816c908d5457d63eba3e2b17e515c5fe00e5ee2bace06040"}, + {file = "llvmlite-0.42.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a78ab89f1924fc11482209f6799a7a3fc74ddc80425a7a3e0e8174af0e9e2301"}, + {file = "llvmlite-0.42.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7599b65c7af7abbc978dbf345712c60fd596aa5670496561cc10e8a71cebfb2"}, + {file = "llvmlite-0.42.0-cp39-cp39-win_amd64.whl", hash = "sha256:43d65cc4e206c2e902c1004dd5418417c4efa6c1d04df05c6c5675a27e8ca90e"}, + {file = "llvmlite-0.42.0.tar.gz", hash = "sha256:f92b09243c0cc3f457da8b983f67bd8e1295d0f5b3746c7a1861d7a99403854a"}, ] [[package]] name = "markdown" -version = "3.5.1" +version = "3.5.2" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "Markdown-3.5.1-py3-none-any.whl", hash = "sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc"}, - {file = "Markdown-3.5.1.tar.gz", hash = "sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd"}, + {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, + {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, ] [package.dependencies] @@ -2146,108 +2150,108 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] name = "matplotlib" -version = "3.8.2" +version = "3.8.3" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, - {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, - {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, - {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, - {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, - {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, - {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, - {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, - {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, - {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, - {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"}, + {file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"}, + {file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, + {file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, + {file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, + {file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, + {file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"}, + {file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"}, + {file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, + {file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, ] [package.dependencies] @@ -2440,13 +2444,13 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>= [[package]] name = "nbconvert" -version = "7.13.0" +version = "7.16.0" description = "Converting Jupyter Notebooks" optional = false python-versions = ">=3.8" files = [ - {file = "nbconvert-7.13.0-py3-none-any.whl", hash = "sha256:22521cfcc10ba5755e44acb6a70d2bd8a891ce7aed6746481e10cd548b169e19"}, - {file = "nbconvert-7.13.0.tar.gz", hash = "sha256:c6f61c86fca5b28bd17f4f9a308248e59fa2b54919e1589f6cc3575c5dfec2bd"}, + {file = "nbconvert-7.16.0-py3-none-any.whl", hash = "sha256:ad3dc865ea6e2768d31b7eb6c7ab3be014927216a5ece3ef276748dd809054c7"}, + {file = "nbconvert-7.16.0.tar.gz", hash = "sha256:813e6553796362489ae572e39ba1bff978536192fb518e10826b0e8cadf03ec8"}, ] [package.dependencies] @@ -2536,81 +2540,81 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "numba" -version = "0.58.1" +version = "0.59.0" description = "compiling Python code using LLVM" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "numba-0.58.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07f2fa7e7144aa6f275f27260e73ce0d808d3c62b30cff8906ad1dec12d87bbe"}, - {file = "numba-0.58.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7bf1ddd4f7b9c2306de0384bf3854cac3edd7b4d8dffae2ec1b925e4c436233f"}, - {file = "numba-0.58.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bc2d904d0319d7a5857bd65062340bed627f5bfe9ae4a495aef342f072880d50"}, - {file = "numba-0.58.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e79b6cc0d2bf064a955934a2e02bf676bc7995ab2db929dbbc62e4c16551be6"}, - {file = "numba-0.58.1-cp310-cp310-win_amd64.whl", hash = "sha256:81fe5b51532478149b5081311b0fd4206959174e660c372b94ed5364cfb37c82"}, - {file = "numba-0.58.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bcecd3fb9df36554b342140a4d77d938a549be635d64caf8bd9ef6c47a47f8aa"}, - {file = "numba-0.58.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1eaa744f518bbd60e1f7ccddfb8002b3d06bd865b94a5d7eac25028efe0e0ff"}, - {file = "numba-0.58.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bf68df9c307fb0aa81cacd33faccd6e419496fdc621e83f1efce35cdc5e79cac"}, - {file = "numba-0.58.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:55a01e1881120e86d54efdff1be08381886fe9f04fc3006af309c602a72bc44d"}, - {file = "numba-0.58.1-cp311-cp311-win_amd64.whl", hash = "sha256:811305d5dc40ae43c3ace5b192c670c358a89a4d2ae4f86d1665003798ea7a1a"}, - {file = "numba-0.58.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ea5bfcf7d641d351c6a80e8e1826eb4a145d619870016eeaf20bbd71ef5caa22"}, - {file = "numba-0.58.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e63d6aacaae1ba4ef3695f1c2122b30fa3d8ba039c8f517784668075856d79e2"}, - {file = "numba-0.58.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6fe7a9d8e3bd996fbe5eac0683227ccef26cba98dae6e5cee2c1894d4b9f16c1"}, - {file = "numba-0.58.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:898af055b03f09d33a587e9425500e5be84fc90cd2f80b3fb71c6a4a17a7e354"}, - {file = "numba-0.58.1-cp38-cp38-win_amd64.whl", hash = "sha256:d3e2fe81fe9a59fcd99cc572002101119059d64d31eb6324995ee8b0f144a306"}, - {file = "numba-0.58.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c765aef472a9406a97ea9782116335ad4f9ef5c9f93fc05fd44aab0db486954"}, - {file = "numba-0.58.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e9356e943617f5e35a74bf56ff6e7cc83e6b1865d5e13cee535d79bf2cae954"}, - {file = "numba-0.58.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:240e7a1ae80eb6b14061dc91263b99dc8d6af9ea45d310751b780888097c1aaa"}, - {file = "numba-0.58.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:45698b995914003f890ad839cfc909eeb9c74921849c712a05405d1a79c50f68"}, - {file = "numba-0.58.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd3dda77955be03ff366eebbfdb39919ce7c2620d86c906203bed92124989032"}, - {file = "numba-0.58.1.tar.gz", hash = "sha256:487ded0633efccd9ca3a46364b40006dbdaca0f95e99b8b83e778d1195ebcbaa"}, + {file = "numba-0.59.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d061d800473fb8fef76a455221f4ad649a53f5e0f96e3f6c8b8553ee6fa98fa"}, + {file = "numba-0.59.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c086a434e7d3891ce5dfd3d1e7ee8102ac1e733962098578b507864120559ceb"}, + {file = "numba-0.59.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9e20736bf62e61f8353fb71b0d3a1efba636c7a303d511600fc57648b55823ed"}, + {file = "numba-0.59.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e86e6786aec31d2002122199486e10bbc0dc40f78d76364cded375912b13614c"}, + {file = "numba-0.59.0-cp310-cp310-win_amd64.whl", hash = "sha256:0307ee91b24500bb7e64d8a109848baf3a3905df48ce142b8ac60aaa406a0400"}, + {file = "numba-0.59.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d540f69a8245fb714419c2209e9af6104e568eb97623adc8943642e61f5d6d8e"}, + {file = "numba-0.59.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1192d6b2906bf3ff72b1d97458724d98860ab86a91abdd4cfd9328432b661e31"}, + {file = "numba-0.59.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90efb436d3413809fcd15298c6d395cb7d98184350472588356ccf19db9e37c8"}, + {file = "numba-0.59.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd3dac45e25d927dcb65d44fb3a973994f5add2b15add13337844afe669dd1ba"}, + {file = "numba-0.59.0-cp311-cp311-win_amd64.whl", hash = "sha256:753dc601a159861808cc3207bad5c17724d3b69552fd22768fddbf302a817a4c"}, + {file = "numba-0.59.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ce62bc0e6dd5264e7ff7f34f41786889fa81a6b860662f824aa7532537a7bee0"}, + {file = "numba-0.59.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8cbef55b73741b5eea2dbaf1b0590b14977ca95a13a07d200b794f8f6833a01c"}, + {file = "numba-0.59.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:70d26ba589f764be45ea8c272caa467dbe882b9676f6749fe6f42678091f5f21"}, + {file = "numba-0.59.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e125f7d69968118c28ec0eed9fbedd75440e64214b8d2eac033c22c04db48492"}, + {file = "numba-0.59.0-cp312-cp312-win_amd64.whl", hash = "sha256:4981659220b61a03c1e557654027d271f56f3087448967a55c79a0e5f926de62"}, + {file = "numba-0.59.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe4d7562d1eed754a7511ed7ba962067f198f86909741c5c6e18c4f1819b1f47"}, + {file = "numba-0.59.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6feb1504bb432280f900deaf4b1dadcee68812209500ed3f81c375cbceab24dc"}, + {file = "numba-0.59.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:944faad25ee23ea9dda582bfb0189fb9f4fc232359a80ab2a028b94c14ce2b1d"}, + {file = "numba-0.59.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5516a469514bfae52a9d7989db4940653a5cbfac106f44cb9c50133b7ad6224b"}, + {file = "numba-0.59.0-cp39-cp39-win_amd64.whl", hash = "sha256:32bd0a41525ec0b1b853da244808f4e5333867df3c43c30c33f89cf20b9c2b63"}, + {file = "numba-0.59.0.tar.gz", hash = "sha256:12b9b064a3e4ad00e2371fc5212ef0396c80f41caec9b5ec391c8b04b6eaf2a8"}, ] [package.dependencies] -llvmlite = "==0.41.*" +llvmlite = "==0.42.*" numpy = ">=1.22,<1.27" [[package]] name = "numpy" -version = "1.26.2" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, - {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, - {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, - {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, - {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, - {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, - {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, - {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, - {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, - {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, - {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] @@ -2649,42 +2653,46 @@ tests = ["pytest", "pytest-cov", "pytest-pep8"] [[package]] name = "osqp" -version = "0.6.3" +version = "0.6.5" description = "OSQP: The Operator Splitting QP Solver" optional = false python-versions = "*" files = [ - {file = "osqp-0.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7d923c836f1d07115057e595245ccc1694ecae730a1affda78fc6f3c8d239"}, - {file = "osqp-0.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dfda08c38c3521012740a73ef782f97dfc54a41deae4b0bc4afd18d0e74da0"}, - {file = "osqp-0.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7eafa3f3e82dd36c52f3f4ef19a95142405c807c272c4b53c5971c53535d7804"}, - {file = "osqp-0.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:3cbb6efdaffb7387dc0037dfe3259d4803e5ad7217e6f20fb605c92953214b9d"}, - {file = "osqp-0.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b2049b2c42565dcaa63ddca1c4028b1fb20aab141453f5d77e8ff5b1a99a2cf"}, - {file = "osqp-0.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:146b89f2cfbf59eaeb2c47e3a312f2034138df78d80ce052364810dc0ef70fc4"}, - {file = "osqp-0.6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0084e3d733c75687d68bc133bc380ce471dfe6f7724af2718a43491782eec8d6"}, - {file = "osqp-0.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:1b573fe1cd0e82239a279c58817c1d365187ef862e928b2b9c828c3c516ad3c2"}, - {file = "osqp-0.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c3951ef505177b858c6cd34de980346014cae3d2234c93db960b12c5885f9a2"}, - {file = "osqp-0.6.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc18f87c9549032c163ce590a5e32079df94ee656c8fb357ba607aa9d78fab81"}, - {file = "osqp-0.6.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07b1a4b538aab629b0fae69f644b7e76f81f94d65230014d482e296dacd046b"}, - {file = "osqp-0.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:60abec3593870990b16f00bd5017096a7091fb00b68d0db3383fc048ca8e55c9"}, - {file = "osqp-0.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b73bdd9589901841af83c5ed6a4092b4fac5a0beff9e32682d8526d1f16a728c"}, - {file = "osqp-0.6.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d9f611823af4a8b241c86805920e5382cd65c7f94fd3615b4eef999ed94c7c"}, - {file = "osqp-0.6.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30fbc3b3c028c06a6c5f1e66be7b7106ad48a29e0dc5bd82393f82dd68235ef8"}, - {file = "osqp-0.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fe57e4bde071b388518ecb068f26319506dd9cb107363d3d80c12d2e59fc1e81"}, - {file = "osqp-0.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:41f304d1d7f91af07d8f0b01e5af29ec3bb8824f0102c7fd8b13b497be120da4"}, - {file = "osqp-0.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea7d8c92bcdf4fef98d777f13d39060d425ef2e8778ed487c96a6fa10848cdea"}, - {file = "osqp-0.6.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f3a3c6d2708868e5e3fe2da300d6523cbf68a3d8734ce9c5043db37391969f5"}, - {file = "osqp-0.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:1c548a0b3691850e7e22f3624a128d8af33416d70a9b5976a47d4d832028dcd8"}, - {file = "osqp-0.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:387e7abd737dfe32c9ec00ad74af25328cdd0d0f634d79530655c040a5cb9590"}, - {file = "osqp-0.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1445e10a94e01698e13c87a7debf6ac1a15f3acd1f8f6340cb1ad945db4732b"}, - {file = "osqp-0.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0441c10f7fe5f46692a9b44a57138977bb112ae3f8127151671968c5d9ec5dbb"}, - {file = "osqp-0.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:b15e65a307fbbabf60248bb9bc204e61d5d4ae64e00427a69e2dad9622f4c29d"}, - {file = "osqp-0.6.3.tar.gz", hash = "sha256:03e460e683ec2ce0f839353ddfa3c4c8ffa509ab8cf6a2b2afbb586fa453e180"}, + {file = "osqp-0.6.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e8024dba07281111af39e71bff6449fb22a37bf3358aa0c7fd1daa6bca692c99"}, + {file = "osqp-0.6.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a68e247f2bbb53e87f1c1ca80ff3fc86b781f771d6da2a2ecd2f6e7492c802f3"}, + {file = "osqp-0.6.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e81e299637eb2342e30eb2df0ec45dc243683af0a71676c9b45b9337bb05da97"}, + {file = "osqp-0.6.5-cp310-cp310-win_amd64.whl", hash = "sha256:42425632927d983cbe935067783b944ebd4959e9eb6611da8401007b66a0c841"}, + {file = "osqp-0.6.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a7b180db09be1c3e3cb4109396b894f481ca9c6e160a530acd71f1769610f96c"}, + {file = "osqp-0.6.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:648f4beff10c16620f3b95e86dee702052d587b847ddbd5d8f71ad39ac36db3a"}, + {file = "osqp-0.6.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7649d56d775662e0a5d1665ed220d585f904d14a49cc6931bf27725bb9c4b2e0"}, + {file = "osqp-0.6.5-cp311-cp311-win_amd64.whl", hash = "sha256:b033b7aec973a655cfec4558e0c4fc92ee9f914bcb0a669e0156398d8ddbef8f"}, + {file = "osqp-0.6.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5c344619465e625aac6d13812d442dd31d4a9ab243e39abb5938c3f6116409b0"}, + {file = "osqp-0.6.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:000ad48aa071ecc4c75ebc39d1291752fe3a9937a30d00fff5dc61663ec67eeb"}, + {file = "osqp-0.6.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a36a40df69db5195fba613341663db2c7dcf977eb75b9578a8fd7682bbe02324"}, + {file = "osqp-0.6.5-cp312-cp312-win_amd64.whl", hash = "sha256:3d8212db7c55af1961ccce4a32fd382bfe34e2198664ea3f81cc47eef8d0f288"}, + {file = "osqp-0.6.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ca7d80c0767b1350cd74e4f1446ec51661152690d38b1382ceccdfccd757afce"}, + {file = "osqp-0.6.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b15e2b96d4d9b2eff37a05405372c69cf17ada3d1e42c5e28cbdbd053189ab5"}, + {file = "osqp-0.6.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a41600e34ece7156606fd3620987fdf224b0a35c857540cb5bf45072f5c022b"}, + {file = "osqp-0.6.5-cp36-cp36m-win_amd64.whl", hash = "sha256:8c38574b35a3ddfb794aafee9bc5a74635160b9fc52bbc89ae6164fe207556de"}, + {file = "osqp-0.6.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d06f614e3be1b1f3cd68569b2dc3628c2fdef1e7c4b992672fe05efb1add9801"}, + {file = "osqp-0.6.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a6b995e0a022bd1c33d20d8846d9a068df89cec288b905b5cdfdb98a2ffae8"}, + {file = "osqp-0.6.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09de9b53e7513ee4ade3024ce9f36ef993d916118d0927cce740d086882ea92c"}, + {file = "osqp-0.6.5-cp37-cp37m-win_amd64.whl", hash = "sha256:1f80f85d515ef29b90fb34f137857e75d4fcf21a715d644f54d2cf9494567fab"}, + {file = "osqp-0.6.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de9b9e96001e8f0b2e474106ac75e220fd9279e1635b107b836a6035795e8d07"}, + {file = "osqp-0.6.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fe545d7a87a46cfc57dfb9f0aa2788d2f29e0c71dc1ac57e92f9c9d93064753"}, + {file = "osqp-0.6.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49ab020b5fd7abb5da99e01e47bf81f817ba1df6895e3d3ba4893722cc24d9b6"}, + {file = "osqp-0.6.5-cp38-cp38-win_amd64.whl", hash = "sha256:5d1b5ed6fc4faea94117a0abe140fefe980449b29d3907bd2e6ec1c18eca3d43"}, + {file = "osqp-0.6.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dca127b7a333ce53fb430fc441b2e0aee2df619693d967277a8f8fd095e95007"}, + {file = "osqp-0.6.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ec902844defedf7c5a5ed482b93286d1735a65b71bb27c93e18c929f313c93d"}, + {file = "osqp-0.6.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25a9e1e8f1db38094dc7ee544e603e31fe7bf1b2a3fc75c78c1d39a727e2540"}, + {file = "osqp-0.6.5-cp39-cp39-win_amd64.whl", hash = "sha256:6dce90d8c4ad551489a452573ea819e089e1e1c3b23bbd8f155bb6059ce8ef36"}, + {file = "osqp-0.6.5.tar.gz", hash = "sha256:b2810aee7be2373add8b6c0be5ad99b810288774abca421751cb032d6a5aedef"}, ] [package.dependencies] numpy = ">=1.7" qdldl = "*" -scipy = ">=0.13.2" +scipy = ">=0.13.2,<1.12.0" [[package]] name = "packaging" @@ -2699,36 +2707,40 @@ files = [ [[package]] name = "pandas" -version = "2.1.4" +version = "2.2.0" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bdec823dc6ec53f7a6339a0e34c68b144a7a1fd28d80c260534c39c62c5bf8c9"}, - {file = "pandas-2.1.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:294d96cfaf28d688f30c918a765ea2ae2e0e71d3536754f4b6de0ea4a496d034"}, - {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b728fb8deba8905b319f96447a27033969f3ea1fea09d07d296c9030ab2ed1d"}, - {file = "pandas-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00028e6737c594feac3c2df15636d73ace46b8314d236100b57ed7e4b9ebe8d9"}, - {file = "pandas-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:426dc0f1b187523c4db06f96fb5c8d1a845e259c99bda74f7de97bd8a3bb3139"}, - {file = "pandas-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:f237e6ca6421265643608813ce9793610ad09b40154a3344a088159590469e46"}, - {file = "pandas-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7d852d16c270e4331f6f59b3e9aa23f935f5c4b0ed2d0bc77637a8890a5d092"}, - {file = "pandas-2.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7d5f2f54f78164b3d7a40f33bf79a74cdee72c31affec86bfcabe7e0789821"}, - {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa6e92e639da0d6e2017d9ccff563222f4eb31e4b2c3cf32a2a392fc3103c0d"}, - {file = "pandas-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d797591b6846b9db79e65dc2d0d48e61f7db8d10b2a9480b4e3faaddc421a171"}, - {file = "pandas-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2d3e7b00f703aea3945995ee63375c61b2e6aa5aa7871c5d622870e5e137623"}, - {file = "pandas-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:dc9bf7ade01143cddc0074aa6995edd05323974e6e40d9dbde081021ded8510e"}, - {file = "pandas-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:482d5076e1791777e1571f2e2d789e940dedd927325cc3cb6d0800c6304082f6"}, - {file = "pandas-2.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8a706cfe7955c4ca59af8c7a0517370eafbd98593155b48f10f9811da440248b"}, - {file = "pandas-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0513a132a15977b4a5b89aabd304647919bc2169eac4c8536afb29c07c23540"}, - {file = "pandas-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9f17f2b6fc076b2a0078862547595d66244db0f41bf79fc5f64a5c4d635bead"}, - {file = "pandas-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:45d63d2a9b1b37fa6c84a68ba2422dc9ed018bdaa668c7f47566a01188ceeec1"}, - {file = "pandas-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:f69b0c9bb174a2342818d3e2778584e18c740d56857fc5cdb944ec8bbe4082cf"}, - {file = "pandas-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3f06bda01a143020bad20f7a85dd5f4a1600112145f126bc9e3e42077c24ef34"}, - {file = "pandas-2.1.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab5796839eb1fd62a39eec2916d3e979ec3130509930fea17fe6f81e18108f6a"}, - {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbaf9e8d3a63a9276d707b4d25930a262341bca9874fcb22eff5e3da5394732"}, - {file = "pandas-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebfd771110b50055712b3b711b51bee5d50135429364d0498e1213a7adc2be8"}, - {file = "pandas-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8ea107e0be2aba1da619cc6ba3f999b2bfc9669a83554b1904ce3dd9507f0860"}, - {file = "pandas-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:d65148b14788b3758daf57bf42725caa536575da2b64df9964c563b015230984"}, - {file = "pandas-2.1.4.tar.gz", hash = "sha256:fcb68203c833cc735321512e13861358079a96c174a61f5116a1de89c58c0ef7"}, + {file = "pandas-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8108ee1712bb4fa2c16981fba7e68b3f6ea330277f5ca34fa8d557e986a11670"}, + {file = "pandas-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:736da9ad4033aeab51d067fc3bd69a0ba36f5a60f66a527b3d72e2030e63280a"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e0b4fc3ddceb56ec8a287313bc22abe17ab0eb184069f08fc6a9352a769b18"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20404d2adefe92aed3b38da41d0847a143a09be982a31b85bc7dd565bdba0f4e"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ea3ee3f125032bfcade3a4cf85131ed064b4f8dd23e5ce6fa16473e48ebcaf5"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9670b3ac00a387620489dfc1bca66db47a787f4e55911f1293063a78b108df1"}, + {file = "pandas-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a946f210383c7e6d16312d30b238fd508d80d927014f3b33fb5b15c2f895430"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1b438fa26b208005c997e78672f1aa8138f67002e833312e6230f3e57fa87d5"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ce2fbc8d9bf303ce54a476116165220a1fedf15985b09656b4b4275300e920b"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2707514a7bec41a4ab81f2ccce8b382961a29fbe9492eab1305bb075b2b1ff4f"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85793cbdc2d5bc32620dc8ffa715423f0c680dacacf55056ba13454a5be5de88"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfd6c2491dc821b10c716ad6776e7ab311f7df5d16038d0b7458bc0b67dc10f3"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a146b9dcacc3123aa2b399df1a284de5f46287a4ab4fbfc237eac98a92ebcb71"}, + {file = "pandas-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbc1b53c0e1fdf16388c33c3cca160f798d38aea2978004dd3f4d3dec56454c9"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a41d06f308a024981dcaa6c41f2f2be46a6b186b902c94c2674e8cb5c42985bc"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:159205c99d7a5ce89ecfc37cb08ed179de7783737cea403b295b5eda8e9c56d1"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1e1f3861ea9132b32f2133788f3b14911b68102d562715d71bd0013bc45440"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:761cb99b42a69005dec2b08854fb1d4888fdf7b05db23a8c5a099e4b886a2106"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a20628faaf444da122b2a64b1e5360cde100ee6283ae8effa0d8745153809a2e"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f5be5d03ea2073627e7111f61b9f1f0d9625dc3c4d8dda72cc827b0c58a1d042"}, + {file = "pandas-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a626795722d893ed6aacb64d2401d017ddc8a2341b49e0384ab9bf7112bdec30"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f66419d4a41132eb7e9a73dcec9486cf5019f52d90dd35547af11bc58f8637d"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57abcaeda83fb80d447f28ab0cc7b32b13978f6f733875ebd1ed14f8fbc0f4ab"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60f1f7dba3c2d5ca159e18c46a34e7ca7247a73b5dd1a22b6d59707ed6b899a"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb61dc8567b798b969bcc1fc964788f5a68214d333cade8319c7ab33e2b5d88a"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52826b5f4ed658fa2b729264d63f6732b8b29949c7fd234510d57c61dbeadfcd"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bde2bc699dbd80d7bc7f9cab1e23a95c4375de615860ca089f34e7c64f4a8de7"}, + {file = "pandas-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3de918a754bbf2da2381e8a3dcc45eede8cd7775b047b923f9006d5f876802ae"}, + {file = "pandas-2.2.0.tar.gz", hash = "sha256:30b83f7c3eb217fb4d1b494a57a2fda5444f17834f5df2de6b2ffff68dc3c8e2"}, ] [package.dependencies] @@ -2738,41 +2750,41 @@ numpy = [ ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" -tzdata = ">=2022.1" +tzdata = ">=2022.7" [package.extras] -all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] -aws = ["s3fs (>=2022.05.0)"] -clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] -compression = ["zstandard (>=0.17.0)"] -computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] -feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2022.05.0)"] -gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] -hdf5 = ["tables (>=3.7.0)"] -html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] -mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] -parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] -plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] -spss = ["pyreadstat (>=1.1.5)"] -sql-other = ["SQLAlchemy (>=1.4.36)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.8.0)"] +xml = ["lxml (>=4.9.2)"] [[package]] name = "pandocfilters" -version = "1.5.0" +version = "1.5.1" description = "Utilities for writing pandoc filters in python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, - {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, + {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, + {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, ] [[package]] @@ -2911,28 +2923,28 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.1.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -2983,47 +2995,47 @@ testing = ["google-api-core[grpc] (>=1.31.5)"] [[package]] name = "protobuf" -version = "4.25.1" +version = "4.25.3" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.1-cp310-abi3-win32.whl", hash = "sha256:193f50a6ab78a970c9b4f148e7c750cfde64f59815e86f686c22e26b4fe01ce7"}, - {file = "protobuf-4.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:3497c1af9f2526962f09329fd61a36566305e6c72da2590ae0d7d1322818843b"}, - {file = "protobuf-4.25.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:0bf384e75b92c42830c0a679b0cd4d6e2b36ae0cf3dbb1e1dfdda48a244f4bcd"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:0f881b589ff449bf0b931a711926e9ddaad3b35089cc039ce1af50b21a4ae8cb"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:ca37bf6a6d0046272c152eea90d2e4ef34593aaa32e8873fc14c16440f22d4b7"}, - {file = "protobuf-4.25.1-cp38-cp38-win32.whl", hash = "sha256:abc0525ae2689a8000837729eef7883b9391cd6aa7950249dcf5a4ede230d5dd"}, - {file = "protobuf-4.25.1-cp38-cp38-win_amd64.whl", hash = "sha256:1484f9e692091450e7edf418c939e15bfc8fc68856e36ce399aed6889dae8bb0"}, - {file = "protobuf-4.25.1-cp39-cp39-win32.whl", hash = "sha256:8bdbeaddaac52d15c6dce38c71b03038ef7772b977847eb6d374fc86636fa510"}, - {file = "protobuf-4.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:becc576b7e6b553d22cbdf418686ee4daa443d7217999125c045ad56322dda10"}, - {file = "protobuf-4.25.1-py3-none-any.whl", hash = "sha256:a19731d5e83ae4737bb2a089605e636077ac001d18781b3cf489b9546c7c80d6"}, - {file = "protobuf-4.25.1.tar.gz", hash = "sha256:57d65074b4f5baa4ab5da1605c02be90ac20c8b40fb137d6a8df9f416b0d0ce2"}, + {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, + {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, + {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, + {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, + {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, + {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, + {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, + {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, + {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, ] [[package]] name = "psutil" -version = "5.9.7" +version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "psutil-5.9.7-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0bd41bf2d1463dfa535942b2a8f0e958acf6607ac0be52265ab31f7923bcd5e6"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:5794944462509e49d4d458f4dbfb92c47539e7d8d15c796f141f474010084056"}, - {file = "psutil-5.9.7-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:fe361f743cb3389b8efda21980d93eb55c1f1e3898269bc9a2a1d0bb7b1f6508"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e469990e28f1ad738f65a42dcfc17adaed9d0f325d55047593cb9033a0ab63df"}, - {file = "psutil-5.9.7-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:3c4747a3e2ead1589e647e64aad601981f01b68f9398ddf94d01e3dc0d1e57c7"}, - {file = "psutil-5.9.7-cp27-none-win32.whl", hash = "sha256:1d4bc4a0148fdd7fd8f38e0498639ae128e64538faa507df25a20f8f7fb2341c"}, - {file = "psutil-5.9.7-cp27-none-win_amd64.whl", hash = "sha256:4c03362e280d06bbbfcd52f29acd79c733e0af33d707c54255d21029b8b32ba6"}, - {file = "psutil-5.9.7-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ea36cc62e69a13ec52b2f625c27527f6e4479bca2b340b7a452af55b34fcbe2e"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1132704b876e58d277168cd729d64750633d5ff0183acf5b3c986b8466cd0284"}, - {file = "psutil-5.9.7-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8b7f07948f1304497ce4f4684881250cd859b16d06a1dc4d7941eeb6233bfe"}, - {file = "psutil-5.9.7-cp36-cp36m-win32.whl", hash = "sha256:b27f8fdb190c8c03914f908a4555159327d7481dac2f01008d483137ef3311a9"}, - {file = "psutil-5.9.7-cp36-cp36m-win_amd64.whl", hash = "sha256:44969859757f4d8f2a9bd5b76eba8c3099a2c8cf3992ff62144061e39ba8568e"}, - {file = "psutil-5.9.7-cp37-abi3-win32.whl", hash = "sha256:c727ca5a9b2dd5193b8644b9f0c883d54f1248310023b5ad3e92036c5e2ada68"}, - {file = "psutil-5.9.7-cp37-abi3-win_amd64.whl", hash = "sha256:f37f87e4d73b79e6c5e749440c3113b81d1ee7d26f21c19c47371ddea834f414"}, - {file = "psutil-5.9.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:032f4f2c909818c86cea4fe2cc407f1c0f0cde8e6c6d702b28b8ce0c0d143340"}, - {file = "psutil-5.9.7.tar.gz", hash = "sha256:3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c"}, + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, ] [package.extras] @@ -3151,47 +3163,47 @@ files = [ [[package]] name = "pydantic" -version = "1.10.13" +version = "1.10.14" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:efff03cc7a4f29d9009d1c96ceb1e7a70a65cfe86e89d34e4a5f2ab1e5693737"}, - {file = "pydantic-1.10.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ecea2b9d80e5333303eeb77e180b90e95eea8f765d08c3d278cd56b00345d01"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1740068fd8e2ef6eb27a20e5651df000978edce6da6803c2bef0bc74540f9548"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84bafe2e60b5e78bc64a2941b4c071a4b7404c5c907f5f5a99b0139781e69ed8"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc0898c12f8e9c97f6cd44c0ed70d55749eaf783716896960b4ecce2edfd2d69"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:654db58ae399fe6434e55325a2c3e959836bd17a6f6a0b6ca8107ea0571d2e17"}, - {file = "pydantic-1.10.13-cp310-cp310-win_amd64.whl", hash = "sha256:75ac15385a3534d887a99c713aa3da88a30fbd6204a5cd0dc4dab3d770b9bd2f"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c553f6a156deb868ba38a23cf0df886c63492e9257f60a79c0fd8e7173537653"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e08865bc6464df8c7d61439ef4439829e3ab62ab1669cddea8dd00cd74b9ffe"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31647d85a2013d926ce60b84f9dd5300d44535a9941fe825dc349ae1f760df9"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:210ce042e8f6f7c01168b2d84d4c9eb2b009fe7bf572c2266e235edf14bacd80"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8ae5dd6b721459bfa30805f4c25880e0dd78fc5b5879f9f7a692196ddcb5a580"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f8e81fc5fb17dae698f52bdd1c4f18b6ca674d7068242b2aff075f588301bbb0"}, - {file = "pydantic-1.10.13-cp311-cp311-win_amd64.whl", hash = "sha256:61d9dce220447fb74f45e73d7ff3b530e25db30192ad8d425166d43c5deb6df0"}, - {file = "pydantic-1.10.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4b03e42ec20286f052490423682016fd80fda830d8e4119f8ab13ec7464c0132"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59ef915cac80275245824e9d771ee939133be38215555e9dc90c6cb148aaeb5"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a1f9f747851338933942db7af7b6ee8268568ef2ed86c4185c6ef4402e80ba8"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:97cce3ae7341f7620a0ba5ef6cf043975cd9d2b81f3aa5f4ea37928269bc1b87"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854223752ba81e3abf663d685f105c64150873cc6f5d0c01d3e3220bcff7d36f"}, - {file = "pydantic-1.10.13-cp37-cp37m-win_amd64.whl", hash = "sha256:b97c1fac8c49be29486df85968682b0afa77e1b809aff74b83081cc115e52f33"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c958d053453a1c4b1c2062b05cd42d9d5c8eb67537b8d5a7e3c3032943ecd261"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c5370a7edaac06daee3af1c8b1192e305bc102abcbf2a92374b5bc793818599"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6f6e7305244bddb4414ba7094ce910560c907bdfa3501e9db1a7fd7eaea127"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3a3c792a58e1622667a2837512099eac62490cdfd63bd407993aaf200a4cf1f"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c636925f38b8db208e09d344c7aa4f29a86bb9947495dd6b6d376ad10334fb78"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:678bcf5591b63cc917100dc50ab6caebe597ac67e8c9ccb75e698f66038ea953"}, - {file = "pydantic-1.10.13-cp38-cp38-win_amd64.whl", hash = "sha256:6cf25c1a65c27923a17b3da28a0bdb99f62ee04230c931d83e888012851f4e7f"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ef467901d7a41fa0ca6db9ae3ec0021e3f657ce2c208e98cd511f3161c762c6"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968ac42970f57b8344ee08837b62f6ee6f53c33f603547a55571c954a4225691"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9849f031cf8a2f0a928fe885e5a04b08006d6d41876b8bbd2fc68a18f9f2e3fd"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56e3ff861c3b9c6857579de282ce8baabf443f42ffba355bf070770ed63e11e1"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f00790179497767aae6bcdc36355792c79e7bbb20b145ff449700eb076c5f96"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:75b297827b59bc229cac1a23a2f7a4ac0031068e5be0ce385be1462e7e17a35d"}, - {file = "pydantic-1.10.13-cp39-cp39-win_amd64.whl", hash = "sha256:e70ca129d2053fb8b728ee7d1af8e553a928d7e301a311094b8a0501adc8763d"}, - {file = "pydantic-1.10.13-py3-none-any.whl", hash = "sha256:b87326822e71bd5f313e7d3bfdc77ac3247035ac10b0c0618bd99dcf95b1e687"}, - {file = "pydantic-1.10.13.tar.gz", hash = "sha256:32c8b48dcd3b2ac4e78b0ba4af3a2c2eb6048cb75202f0ea7b34feb740efc340"}, + {file = "pydantic-1.10.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4fcec873f90537c382840f330b90f4715eebc2bc9925f04cb92de593eae054"}, + {file = "pydantic-1.10.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e3a76f571970fcd3c43ad982daf936ae39b3e90b8a2e96c04113a369869dc87"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d886bd3c3fbeaa963692ef6b643159ccb4b4cefaf7ff1617720cbead04fd1d"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:798a3d05ee3b71967844a1164fd5bdb8c22c6d674f26274e78b9f29d81770c4e"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:23d47a4b57a38e8652bcab15a658fdb13c785b9ce217cc3a729504ab4e1d6bc9"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9f674b5c3bebc2eba401de64f29948ae1e646ba2735f884d1594c5f675d6f2a"}, + {file = "pydantic-1.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:24a7679fab2e0eeedb5a8924fc4a694b3bcaac7d305aeeac72dd7d4e05ecbebf"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d578ac4bf7fdf10ce14caba6f734c178379bd35c486c6deb6f49006e1ba78a7"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa7790e94c60f809c95602a26d906eba01a0abee9cc24150e4ce2189352deb1b"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad4e10efa5474ed1a611b6d7f0d130f4aafadceb73c11d9e72823e8f508e663"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245f4f61f467cb3dfeced2b119afef3db386aec3d24a22a1de08c65038b255f"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:21efacc678a11114c765eb52ec0db62edffa89e9a562a94cbf8fa10b5db5c046"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:412ab4a3f6dbd2bf18aefa9f79c7cca23744846b31f1d6555c2ee2b05a2e14ca"}, + {file = "pydantic-1.10.14-cp311-cp311-win_amd64.whl", hash = "sha256:e897c9f35281f7889873a3e6d6b69aa1447ceb024e8495a5f0d02ecd17742a7f"}, + {file = "pydantic-1.10.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d604be0f0b44d473e54fdcb12302495fe0467c56509a2f80483476f3ba92b33c"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42c7d17706911199798d4c464b352e640cab4351efe69c2267823d619a937e5"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:596f12a1085e38dbda5cbb874d0973303e34227b400b6414782bf205cc14940c"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bfb113860e9288d0886e3b9e49d9cf4a9d48b441f52ded7d96db7819028514cc"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bc3ed06ab13660b565eed80887fcfbc0070f0aa0691fbb351657041d3e874efe"}, + {file = "pydantic-1.10.14-cp37-cp37m-win_amd64.whl", hash = "sha256:ad8c2bc677ae5f6dbd3cf92f2c7dc613507eafe8f71719727cbc0a7dec9a8c01"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c37c28449752bb1f47975d22ef2882d70513c546f8f37201e0fec3a97b816eee"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49a46a0994dd551ec051986806122767cf144b9702e31d47f6d493c336462597"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53e3819bd20a42470d6dd0fe7fc1c121c92247bca104ce608e609b59bc7a77ee"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbb503bbbbab0c588ed3cd21975a1d0d4163b87e360fec17a792f7d8c4ff29f"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:336709883c15c050b9c55a63d6c7ff09be883dbc17805d2b063395dd9d9d0022"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4ae57b4d8e3312d486e2498d42aed3ece7b51848336964e43abbf9671584e67f"}, + {file = "pydantic-1.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:dba49d52500c35cfec0b28aa8b3ea5c37c9df183ffc7210b10ff2a415c125c4a"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c66609e138c31cba607d8e2a7b6a5dc38979a06c900815495b2d90ce6ded35b4"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d986e115e0b39604b9eee3507987368ff8148222da213cd38c359f6f57b3b347"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646b2b12df4295b4c3148850c85bff29ef6d0d9621a8d091e98094871a62e5c7"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282613a5969c47c83a8710cc8bfd1e70c9223feb76566f74683af889faadc0ea"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:466669501d08ad8eb3c4fecd991c5e793c4e0bbd62299d05111d4f827cded64f"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:13e86a19dca96373dcf3190fcb8797d40a6f12f154a244a8d1e8e03b8f280593"}, + {file = "pydantic-1.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:08b6ec0917c30861e3fe71a93be1648a2aa4f62f866142ba21670b24444d7fd8"}, + {file = "pydantic-1.10.14-py3-none-any.whl", hash = "sha256:8ee853cd12ac2ddbf0ecbac1c289f95882b2d4482258048079d13be700aa114c"}, + {file = "pydantic-1.10.14.tar.gz", hash = "sha256:46f17b832fe27de7850896f3afee50ea682220dd218f7e9c88d436788419dca6"}, ] [package.dependencies] @@ -3367,13 +3379,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -3491,13 +3503,13 @@ files = [ [[package]] name = "pytz" -version = "2023.3.post1" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -3535,7 +3547,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -3543,16 +3554,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -3569,7 +3572,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -3577,7 +3579,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -3761,7 +3762,7 @@ scipy = "^1.10.1" type = "git" url = "https://github.com/qiboteam/qibojit.git" reference = "HEAD" -resolved_reference = "b32f503452127ac915b20af773e29694b5b64dd4" +resolved_reference = "c34ba49a5b0e4efd0ca3b28add8d9d1da97f78b8" [[package]] name = "recommonmark" @@ -3892,13 +3893,13 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruamel-yaml" -version = "0.18.5" +version = "0.18.6" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = ">=3.7" files = [ - {file = "ruamel.yaml-0.18.5-py3-none-any.whl", hash = "sha256:a013ac02f99a69cdd6277d9664689eb1acba07069f912823177c5eced21a6ada"}, - {file = "ruamel.yaml-0.18.5.tar.gz", hash = "sha256:61917e3a35a569c1133a8f772e1226961bf5a1198bea7e23f06a0841dea1ab0e"}, + {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, + {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, ] [package.dependencies] @@ -3969,50 +3970,65 @@ files = [ [[package]] name = "scikit-learn" -version = "1.3.2" +version = "1.4.0" description = "A set of python modules for machine learning and data mining" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "scikit-learn-1.3.2.tar.gz", hash = "sha256:a2f54c76accc15a34bfb9066e6c7a56c1e7235dda5762b990792330b52ccfb05"}, - {file = "scikit_learn-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e326c0eb5cf4d6ba40f93776a20e9a7a69524c4db0757e7ce24ba222471ee8a1"}, - {file = "scikit_learn-1.3.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:535805c2a01ccb40ca4ab7d081d771aea67e535153e35a1fd99418fcedd1648a"}, - {file = "scikit_learn-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1215e5e58e9880b554b01187b8c9390bf4dc4692eedeaf542d3273f4785e342c"}, - {file = "scikit_learn-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ee107923a623b9f517754ea2f69ea3b62fc898a3641766cb7deb2f2ce450161"}, - {file = "scikit_learn-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:35a22e8015048c628ad099da9df5ab3004cdbf81edc75b396fd0cff8699ac58c"}, - {file = "scikit_learn-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6fb6bc98f234fda43163ddbe36df8bcde1d13ee176c6dc9b92bb7d3fc842eb66"}, - {file = "scikit_learn-1.3.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:18424efee518a1cde7b0b53a422cde2f6625197de6af36da0b57ec502f126157"}, - {file = "scikit_learn-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3271552a5eb16f208a6f7f617b8cc6d1f137b52c8a1ef8edf547db0259b2c9fb"}, - {file = "scikit_learn-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4144a5004a676d5022b798d9e573b05139e77f271253a4703eed295bde0433"}, - {file = "scikit_learn-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:67f37d708f042a9b8d59551cf94d30431e01374e00dc2645fa186059c6c5d78b"}, - {file = "scikit_learn-1.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8db94cd8a2e038b37a80a04df8783e09caac77cbe052146432e67800e430c028"}, - {file = "scikit_learn-1.3.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:61a6efd384258789aa89415a410dcdb39a50e19d3d8410bd29be365bcdd512d5"}, - {file = "scikit_learn-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb06f8dce3f5ddc5dee1715a9b9f19f20d295bed8e3cd4fa51e1d050347de525"}, - {file = "scikit_learn-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b2de18d86f630d68fe1f87af690d451388bb186480afc719e5f770590c2ef6c"}, - {file = "scikit_learn-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:0402638c9a7c219ee52c94cbebc8fcb5eb9fe9c773717965c1f4185588ad3107"}, - {file = "scikit_learn-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a19f90f95ba93c1a7f7924906d0576a84da7f3b2282ac3bfb7a08a32801add93"}, - {file = "scikit_learn-1.3.2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:b8692e395a03a60cd927125eef3a8e3424d86dde9b2370d544f0ea35f78a8073"}, - {file = "scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15e1e94cc23d04d39da797ee34236ce2375ddea158b10bee3c343647d615581d"}, - {file = "scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:785a2213086b7b1abf037aeadbbd6d67159feb3e30263434139c98425e3dcfcf"}, - {file = "scikit_learn-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:64381066f8aa63c2710e6b56edc9f0894cc7bf59bd71b8ce5613a4559b6145e0"}, - {file = "scikit_learn-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6c43290337f7a4b969d207e620658372ba3c1ffb611f8bc2b6f031dc5c6d1d03"}, - {file = "scikit_learn-1.3.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:dc9002fc200bed597d5d34e90c752b74df516d592db162f756cc52836b38fe0e"}, - {file = "scikit_learn-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d08ada33e955c54355d909b9c06a4789a729977f165b8bae6f225ff0a60ec4a"}, - {file = "scikit_learn-1.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763f0ae4b79b0ff9cca0bf3716bcc9915bdacff3cebea15ec79652d1cc4fa5c9"}, - {file = "scikit_learn-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:ed932ea780517b00dae7431e031faae6b49b20eb6950918eb83bd043237950e0"}, + {file = "scikit-learn-1.4.0.tar.gz", hash = "sha256:d4373c984eba20e393216edd51a3e3eede56cbe93d4247516d205643c3b93121"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fce93a7473e2f4ee4cc280210968288d6a7d7ad8dc6fa7bb7892145e407085f9"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d77df3d1e15fc37a9329999979fa7868ba8655dbab21fe97fc7ddabac9e08cc7"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2404659fedec40eeafa310cd14d613e564d13dbf8f3c752d31c095195ec05de6"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e98632da8f6410e6fb6bf66937712c949b4010600ccd3f22a5388a83e610cc3c"}, + {file = "scikit_learn-1.4.0-1-cp310-cp310-win_amd64.whl", hash = "sha256:11b3b140f70fbc9f6a08884631ae8dd60a4bb2d7d6d1de92738ea42b740d8992"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8341eabdc754d5ab91641a7763243845e96b6d68e03e472531e88a4f1b09f21"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d1f6bce875ac2bb6b52514f67c185c564ccd299a05b65b7bab091a4c13dde12d"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c408b46b2fd61952d519ea1af2f8f0a7a703e1433923ab1704c4131520b2083b"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b465dd1dcd237b7b1dcd1a9048ccbf70a98c659474324fa708464c3a2533fad"}, + {file = "scikit_learn-1.4.0-1-cp311-cp311-win_amd64.whl", hash = "sha256:0db8e22c42f7980fe5eb22069b1f84c48966f3e0d23a01afde5999e3987a2501"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7eef6ea2ed289af40e88c0be9f7704ca8b5de18508a06897c3fe21e0905efdf"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:349669b01435bc4dbf25c6410b0892073befdaec52637d1a1d1ff53865dc8db3"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d439c584e58434d0350701bd33f6c10b309e851fccaf41c121aed55f6851d8cf"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e2427d9ef46477625ab9b55c1882844fe6fc500f418c3f8e650200182457bc"}, + {file = "scikit_learn-1.4.0-1-cp312-cp312-win_amd64.whl", hash = "sha256:d3d75343940e7bf9b85c830c93d34039fa015eeb341c5c0b4cd7a90dadfe00d4"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:76986d22e884ab062b1beecdd92379656e9d3789ecc1f9870923c178de55f9fe"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:e22446ad89f1cb7657f0d849dcdc345b48e2d10afa3daf2925fdb740f85b714c"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74812c9eabb265be69d738a8ea8d4884917a59637fcbf88a5f0e9020498bc6b3"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad2a63e0dd386b92da3270887a29b308af4d7c750d8c4995dfd9a4798691bcc"}, + {file = "scikit_learn-1.4.0-1-cp39-cp39-win_amd64.whl", hash = "sha256:53b9e29177897c37e2ff9d4ba6ca12fdb156e22523e463db05def303f5c72b5c"}, + {file = "scikit_learn-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb8f044a8f5962613ce1feb4351d66f8d784bd072d36393582f351859b065f7d"}, + {file = "scikit_learn-1.4.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:a6372c90bbf302387792108379f1ec77719c1618d88496d0df30cb8e370b4661"}, + {file = "scikit_learn-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:785ce3c352bf697adfda357c3922c94517a9376002971bc5ea50896144bc8916"}, + {file = "scikit_learn-1.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0aba2a20d89936d6e72d95d05e3bf1db55bca5c5920926ad7b92c34f5e7d3bbe"}, + {file = "scikit_learn-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:2bac5d56b992f8f06816f2cd321eb86071c6f6d44bb4b1cb3d626525820d754b"}, + {file = "scikit_learn-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27ae4b0f1b2c77107c096a7e05b33458354107b47775428d1f11b23e30a73e8a"}, + {file = "scikit_learn-1.4.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5c5c62ffb52c3ffb755eb21fa74cc2cbf2c521bd53f5c04eaa10011dbecf5f80"}, + {file = "scikit_learn-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f0d2018ac6fa055dab65fe8a485967990d33c672d55bc254c56c35287b02fab"}, + {file = "scikit_learn-1.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a8918c415c4b4bf1d60c38d32958849a9191c2428ab35d30b78354085c7c7a"}, + {file = "scikit_learn-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:80a21de63275f8bcd7877b3e781679d2ff1eddfed515a599f95b2502a3283d42"}, + {file = "scikit_learn-1.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0f33bbafb310c26b81c4d41ecaebdbc1f63498a3f13461d50ed9a2e8f24d28e4"}, + {file = "scikit_learn-1.4.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:8b6ac1442ec714b4911e5aef8afd82c691b5c88b525ea58299d455acc4e8dcec"}, + {file = "scikit_learn-1.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05fc5915b716c6cc60a438c250108e9a9445b522975ed37e416d5ea4f9a63381"}, + {file = "scikit_learn-1.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:842b7d6989f3c574685e18da6f91223eb32301d0f93903dd399894250835a6f7"}, + {file = "scikit_learn-1.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:88bcb586fdff865372df1bc6be88bb7e6f9e0aa080dab9f54f5cac7eca8e2b6b"}, + {file = "scikit_learn-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f77674647dd31f56cb12ed13ed25b6ed43a056fffef051715022d2ebffd7a7d1"}, + {file = "scikit_learn-1.4.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:833999872e2920ce00f3a50839946bdac7539454e200eb6db54898a41f4bfd43"}, + {file = "scikit_learn-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:970ec697accaef10fb4f51763f3a7b1250f9f0553cf05514d0e94905322a0172"}, + {file = "scikit_learn-1.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923d778f378ebacca2c672ab1740e5a413e437fb45ab45ab02578f8b689e5d43"}, + {file = "scikit_learn-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:1d041bc95006b545b59e458399e3175ab11ca7a03dc9a74a573ac891f5df1489"}, ] [package.dependencies] -joblib = ">=1.1.1" -numpy = ">=1.17.3,<2.0" -scipy = ">=1.5.0" +joblib = ">=1.2.0" +numpy = ">=1.19.5" +scipy = ">=1.6.0" threadpoolctl = ">=2.0.0" [package.extras] -benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.10.1)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] -tests = ["black (>=23.3.0)", "matplotlib (>=3.1.3)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.16.2)"] +benchmark = ["matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "pandas (>=1.1.5)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.15.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] +tests = ["black (>=23.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.19.12)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.17.2)"] [[package]] name = "scipy" @@ -4091,18 +4107,18 @@ scipy = "*" [[package]] name = "setuptools" -version = "69.0.2" +version = "69.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -4246,20 +4262,18 @@ markdown = ">=3.4" [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.7" +version = "1.0.8" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.7-py3-none-any.whl", hash = "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d"}, - {file = "sphinxcontrib_applehelp-1.0.7.tar.gz", hash = "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa"}, + {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, + {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] @@ -4282,38 +4296,34 @@ Sphinx = ">=2.1" [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.5" +version = "1.0.6" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.5-py3-none-any.whl", hash = "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f"}, - {file = "sphinxcontrib_devhelp-1.0.5.tar.gz", hash = "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212"}, + {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, + {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.4" +version = "2.0.5" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.4-py3-none-any.whl", hash = "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9"}, - {file = "sphinxcontrib_htmlhelp-2.0.4.tar.gz", hash = "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a"}, + {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, + {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -4332,38 +4342,34 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.6" +version = "1.0.7" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.6-py3-none-any.whl", hash = "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4"}, - {file = "sphinxcontrib_qthelp-1.0.6.tar.gz", hash = "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d"}, + {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, + {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.9" +version = "1.1.10" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"}, - {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"}, + {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, + {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] @@ -4429,22 +4435,22 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] [[package]] name = "tensorboard" -version = "2.14.1" +version = "2.15.2" description = "TensorBoard lets you watch Tensors Flow" optional = false python-versions = ">=3.9" files = [ - {file = "tensorboard-2.14.1-py3-none-any.whl", hash = "sha256:3db108fb58f023b6439880e177743c5f1e703e9eeb5fb7d597871f949f85fd58"}, + {file = "tensorboard-2.15.2-py3-none-any.whl", hash = "sha256:a6f6443728064d962caea6d34653e220e34ef8df764cb06a8212c17e1a8f0622"}, ] [package.dependencies] absl-py = ">=0.4" google-auth = ">=1.6.3,<3" -google-auth-oauthlib = ">=0.5,<1.1" +google-auth-oauthlib = ">=0.5,<2" grpcio = ">=1.48.2" markdown = ">=2.6.8" numpy = ">=1.12.0" -protobuf = ">=3.19.6" +protobuf = ">=3.19.6,<4.24.0 || >4.24.0" requests = ">=2.21.0,<3" setuptools = ">=41.0.0" six = ">1.9" @@ -4465,26 +4471,26 @@ files = [ [[package]] name = "tensorflow" -version = "2.14.1" +version = "2.15.0" description = "TensorFlow is an open source machine learning framework for everyone." optional = false python-versions = ">=3.9" files = [ - {file = "tensorflow-2.14.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:f6e9ac1e53db30f1759148f731f87b9d12da5ce0f153fc49406824efd486aae7"}, - {file = "tensorflow-2.14.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:7156bf1f7311dada7dba5345b526a38e6f4e4f4b8509bee162a24342bf6571b2"}, - {file = "tensorflow-2.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5781aadad5b46e2de4e373b0ca15a852b90d58982270a6db02ec52e4986316d"}, - {file = "tensorflow-2.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a955c42164eff4d751732c1274ca4bf059db60c9e2362098ce1eed7177c3fe9"}, - {file = "tensorflow-2.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:4be5f4327a6e854f64b4dcfd08a51c5fc7cc3fea8c76c5bf5c0c3deb002d5221"}, - {file = "tensorflow-2.14.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:597dd6665a91b3d4b881f0d40277eb55b65b04567553206a46e7db9cfa067310"}, - {file = "tensorflow-2.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:9833e61423ad2726f81e3fc770558b81d5f0a454bdb2dad717c5474ea837ce91"}, - {file = "tensorflow-2.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14a48a087954722d9e73086e8ce28a14b1f9f889ea5845c7c0bf30d8747ab6e2"}, - {file = "tensorflow-2.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9aa05a98450fa5bc4efd529383b7d15c10ec12b0238a6744baa1508c4bfa4d5"}, - {file = "tensorflow-2.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:11958d12e39d44a9f5fc753fc312dd1726a8506f2d2606e01421ca4ee9dc5c55"}, - {file = "tensorflow-2.14.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d95404f78a8d5e3d2481383dbe2d2286341ccf9bc5cbb19d857c646494d860c6"}, - {file = "tensorflow-2.14.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:511c4c5bfb2af17c6ca22663f98a7267c4386bf5486fbe78ee2d21482a6fa822"}, - {file = "tensorflow-2.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f66d2990157cf27f80c730878cb8befa8ed9716223494037d31c80fbe5f64370"}, - {file = "tensorflow-2.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9ab2747f75aba0327bfe6092b963694f1001781e5d2c0d251dfeed02b0c3bba"}, - {file = "tensorflow-2.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:7f5c9215bc00ba88f1cde1399f8160a5cb865c20ad71a1d5a6869f9fad62d9a5"}, + {file = "tensorflow-2.15.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:9b248e0f4316b3a3c54cd1f83edfb7a761d473060c1972a8ea31a90d5de3aa72"}, + {file = "tensorflow-2.15.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:eaf420d8b8ec1d4bd75859be7d7545d8e7052726eed8456fdbba63718e7e07ea"}, + {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e98aab454fc73ff1900314821e5bafbf20840ada2004c8caccf4d92e0e12a628"}, + {file = "tensorflow-2.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed601b43df9b7d9bed0203b34bcb9356efd4f671eaaac1046b7166a2afee0cf8"}, + {file = "tensorflow-2.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:2d88f8b71f4a8d9ab9dc7c8e42b14ca0f53d1daab0f989b8f2918907c2891f41"}, + {file = "tensorflow-2.15.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1e0716622ed7af867d8b1997b00a2940f1a1587dee923ff53efa2ee506992f32"}, + {file = "tensorflow-2.15.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:124930e7d4f5d74c61a5c80d642a26c22fe0c42fdd383fe9ee5803c3ac9ed4ce"}, + {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:852efeb4d18beedac0120c4f2d4f4dccf4c090bb6740c5199d395ff609e85e98"}, + {file = "tensorflow-2.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee8ec2b2c6c942ae65d25746e53cdc475e82d5fcbbb3009ce47f5963d69ebfc"}, + {file = "tensorflow-2.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:e05a48006930e4e9e68468e7affed3bbce8a1c7fe6df86500496ad1558804a78"}, + {file = "tensorflow-2.15.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:2cfcdde1ff3c01be617e99ce9783c49cb11da5796ce32a31855412bd092c0bcf"}, + {file = "tensorflow-2.15.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:896bda03f722700a9918d144aee5152a75f1be5e6c5045fd0683b8318a3fc9d9"}, + {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7697b005ce48fec8b2ee8cf25bcbd138f16b5e17f99f7c01a6ea3f2429f86c6"}, + {file = "tensorflow-2.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fa865956d96b7614f247c36e4c22b1543ba5ce656fbe8e4f6266ae7a4917132"}, + {file = "tensorflow-2.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:01108746e1bbfcd48dfabf7f51ddca7693b91ea6821f6f62a27b5a5ebf0817c5"}, ] [package.dependencies] @@ -4495,60 +4501,63 @@ gast = ">=0.2.1,<0.5.0 || >0.5.0,<0.5.1 || >0.5.1,<0.5.2 || >0.5.2" google-pasta = ">=0.1.1" grpcio = ">=1.24.3,<2.0" h5py = ">=2.9.0" -keras = ">=2.14.0,<2.15" +keras = ">=2.15.0,<2.16" libclang = ">=13.0.0" -ml-dtypes = "0.2.0" +ml-dtypes = ">=0.2.0,<0.3.0" numpy = ">=1.23.5,<2.0.0" opt-einsum = ">=2.3.2" packaging = "*" protobuf = ">=3.20.3,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" setuptools = "*" six = ">=1.12.0" -tensorboard = ">=2.14,<2.15" -tensorflow-estimator = ">=2.14.0,<2.15" +tensorboard = ">=2.15,<2.16" +tensorflow-estimator = ">=2.15.0,<2.16" tensorflow-io-gcs-filesystem = ">=0.23.1" termcolor = ">=1.1.0" typing-extensions = ">=3.6.6" wrapt = ">=1.11.0,<1.15" [package.extras] -and-cuda = ["nvidia-cublas-cu11 (==11.11.3.6)", "nvidia-cuda-cupti-cu11 (==11.8.87)", "nvidia-cuda-nvcc-cu11 (==11.8.89)", "nvidia-cuda-runtime-cu11 (==11.8.89)", "nvidia-cudnn-cu11 (==8.7.0.84)", "nvidia-cufft-cu11 (==10.9.0.58)", "nvidia-curand-cu11 (==10.3.0.86)", "nvidia-cusolver-cu11 (==11.4.1.48)", "nvidia-cusparse-cu11 (==11.7.5.86)", "nvidia-nccl-cu11 (==2.16.5)", "tensorrt (==8.5.3.1)"] +and-cuda = ["nvidia-cublas-cu12 (==12.2.5.6)", "nvidia-cuda-cupti-cu12 (==12.2.142)", "nvidia-cuda-nvcc-cu12 (==12.2.140)", "nvidia-cuda-nvrtc-cu12 (==12.2.140)", "nvidia-cuda-runtime-cu12 (==12.2.140)", "nvidia-cudnn-cu12 (==8.9.4.25)", "nvidia-cufft-cu12 (==11.0.8.103)", "nvidia-curand-cu12 (==10.3.3.141)", "nvidia-cusolver-cu12 (==11.5.2.141)", "nvidia-cusparse-cu12 (==12.1.2.141)", "nvidia-nccl-cu12 (==2.16.5)", "nvidia-nvjitlink-cu12 (==12.2.140)", "tensorrt (==8.6.1.post1)", "tensorrt-bindings (==8.6.1)", "tensorrt-libs (==8.6.1)"] [[package]] name = "tensorflow-estimator" -version = "2.14.0" +version = "2.15.0" description = "TensorFlow Estimator." optional = false python-versions = ">=3.7" files = [ - {file = "tensorflow_estimator-2.14.0-py2.py3-none-any.whl", hash = "sha256:820bf57c24aa631abb1bbe4371739ed77edb11361d61381fd8e790115ac0fd57"}, + {file = "tensorflow_estimator-2.15.0-py2.py3-none-any.whl", hash = "sha256:aedf21eec7fb2dc91150fc91a1ce12bc44dbb72278a08b58e79ff87c9e28f153"}, ] [[package]] name = "tensorflow-io-gcs-filesystem" -version = "0.35.0" +version = "0.36.0" description = "TensorFlow IO" optional = false python-versions = ">=3.7, <3.12" files = [ - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:5521721b38105496d4b43a4ffb0af5b04cc4873d464f26fbceddf8d63815ce98"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd8f30908bf8b7b2a017d6b145720d105aff7f998422671b71729708ec7b2fe4"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac8f1de60fdf9c734aea967b98555e366ac8743f77bca15c49eff023f587076b"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:35b6eca7225c815d962254327195f191d88c3c9c2278a5ab23e0ac834acbadbb"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e997389bfe008210cbd97c0c738d64282a2f03ad4d0536013bb0a9efde0c283"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8fb3402fb1457482c386ea19371bc76383412ae9ea4396edb1e8adb4ba76f21"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb6bf8f5b40207ecb17e7fdc3b4fc824a8361267c14e9528c1688e16de135cb7"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:c4f786eebd98d401565374722f2e67f3878675b0d87489cbaa13c70ee6ac370a"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fce1466bdb91096b6d22e7df17358ba228bcb92db5cff83f2f9f1c68eb26788"}, - {file = "tensorflow_io_gcs_filesystem-0.35.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1856fe321fdb75f3386d92109c60db6ef097f610b450f9cc69d76444fb9980d1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:702c6df62b38095ff613c433546d9424d4f33902a5ab26b00fd26457e27a99fa"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e9b8aaca2789af356c42afda0f52380f82e5abb2f3c0b85087833fcfe03875d8"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c477aed96864ceae77d7051c3b687f28813aba7320fc5dd552164fad6ec8d1a1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be1ff92559dfa23048b01179a1827081947583f5c6f9986ccac471df8a29322a"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:72c3ca4b8c0d8dbdd970699d05a100107cf200317ad8e6a8373e2c37225cd552"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:848e8e89a0f49258c7782189c938d8d1162d989da1a80c79f95c7af3ef6006c8"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d72db1ab03edb65fa1e98d06e504ccbc64282d38ab3589afb6db66dc448d1c1"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd4d946b5fa23220daa473a80e511a5fb27493d7e49d17dff0bb43bb0a31f32"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa346fd1dd9f57848b73874007440504f060fadd689fa1cc29cc49817d0eeaf3"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0a4437824424a4423cf86162cb8b21b1bec24698194332748b50bb952e62ab9f"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:31806bd7ac2db789161bc720747de22947063265561a4c17be54698fd9780b03"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc0e57976c1aa035af6281f0330cfb8dd50eee2f63412ecc84d60ff5075d29b7"}, + {file = "tensorflow_io_gcs_filesystem-0.36.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e97ff5c280eb10f699098ae21057be2b146d39e8a906cd5db91f2ea6c34e47d0"}, ] [package.extras] -tensorflow = ["tensorflow (>=2.14.0,<2.15.0)"] -tensorflow-aarch64 = ["tensorflow-aarch64 (>=2.14.0,<2.15.0)"] -tensorflow-cpu = ["tensorflow-cpu (>=2.14.0,<2.15.0)"] -tensorflow-gpu = ["tensorflow-gpu (>=2.14.0,<2.15.0)"] -tensorflow-rocm = ["tensorflow-rocm (>=2.14.0,<2.15.0)"] +tensorflow = ["tensorflow (>=2.15.0,<2.16.0)"] +tensorflow-aarch64 = ["tensorflow-aarch64 (>=2.15.0,<2.16.0)"] +tensorflow-cpu = ["tensorflow-cpu (>=2.15.0,<2.16.0)"] +tensorflow-gpu = ["tensorflow-gpu (>=2.15.0,<2.16.0)"] +tensorflow-rocm = ["tensorflow-rocm (>=2.15.0,<2.16.0)"] [[package]] name = "termcolor" @@ -4566,13 +4575,13 @@ tests = ["pytest", "pytest-cov"] [[package]] name = "threadpoolctl" -version = "3.2.0" +version = "3.3.0" description = "threadpoolctl" optional = false python-versions = ">=3.8" files = [ - {file = "threadpoolctl-3.2.0-py3-none-any.whl", hash = "sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032"}, - {file = "threadpoolctl-3.2.0.tar.gz", hash = "sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355"}, + {file = "threadpoolctl-3.3.0-py3-none-any.whl", hash = "sha256:6155be1f4a39f31a18ea70f94a77e0ccd57dced08122ea61109e7da89883781e"}, + {file = "threadpoolctl-3.3.0.tar.gz", hash = "sha256:5dac632b4fa2d43f42130267929af3ba01399ef4bd1882918e92dbc30365d30c"}, ] [[package]] @@ -4648,13 +4657,13 @@ files = [ [[package]] name = "tqdm" -version = "4.66.1" +version = "4.66.2" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, - {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, + {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, + {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, ] [package.dependencies] @@ -4668,13 +4677,13 @@ telegram = ["requests"] [[package]] name = "traitlets" -version = "5.14.0" +version = "5.14.1" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.0-py3-none-any.whl", hash = "sha256:f14949d23829023013c47df20b4a76ccd1a85effb786dc060f34de7948361b33"}, - {file = "traitlets-5.14.0.tar.gz", hash = "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772"}, + {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, + {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, ] [package.extras] @@ -4683,24 +4692,24 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "types-deprecated" -version = "1.2.9.3" +version = "1.2.9.20240106" description = "Typing stubs for Deprecated" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-Deprecated-1.2.9.3.tar.gz", hash = "sha256:ef87327adf3e3c4a4c7d8e06e58f6476710d3466ecfb53c49efb080804a70ef3"}, - {file = "types_Deprecated-1.2.9.3-py3-none-any.whl", hash = "sha256:24da9210763e5e1b3d0d4f6f8bba9ad3bb6af3fe7f6815fc37e3ede4681704f5"}, + {file = "types-Deprecated-1.2.9.20240106.tar.gz", hash = "sha256:afeb819e9a03d0a5795f18c88fe6207c48ed13c639e93281bd9d9b7bb6d34310"}, + {file = "types_Deprecated-1.2.9.20240106-py3-none-any.whl", hash = "sha256:9dcb258493b5be407574ee21e50ddac9e429072d39b576126bf1ac00764fb9a8"}, ] [[package]] name = "types-python-dateutil" -version = "2.8.19.14" +version = "2.8.19.20240106" description = "Typing stubs for python-dateutil" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-python-dateutil-2.8.19.14.tar.gz", hash = "sha256:1f4f10ac98bb8b16ade9dbee3518d9ace017821d94b057a425b069f834737f4b"}, - {file = "types_python_dateutil-2.8.19.14-py3-none-any.whl", hash = "sha256:f977b8de27787639986b4e28963263fd0e5158942b3ecef91b9335c130cb1ce9"}, + {file = "types-python-dateutil-2.8.19.20240106.tar.gz", hash = "sha256:1f8db221c3b98e6ca02ea83a58371b22c374f42ae5bbdf186db9c9a76581459f"}, + {file = "types_python_dateutil-2.8.19.20240106-py3-none-any.whl", hash = "sha256:efbbdc54590d0f16152fa103c9879c7d4a00e82078f6e2cf01769042165acaa2"}, ] [[package]] @@ -4727,40 +4736,41 @@ files = [ [[package]] name = "tzdata" -version = "2023.3" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "wcwidth" -version = "0.2.12" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, - {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -4807,13 +4817,13 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "widgetsnbextension" -version = "4.0.9" +version = "4.0.10" description = "Jupyter interactive widgets for Jupyter Notebook" optional = false python-versions = ">=3.7" files = [ - {file = "widgetsnbextension-4.0.9-py3-none-any.whl", hash = "sha256:91452ca8445beb805792f206e560c1769284267a30ceb1cec9f5bcc887d15175"}, - {file = "widgetsnbextension-4.0.9.tar.gz", hash = "sha256:3c1f5e46dc1166dfd40a42d685e6a51396fd34ff878742a3e47c6f0cc4a2a385"}, + {file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"}, + {file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"}, ] [[package]] @@ -4934,4 +4944,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "fb9a22edabc2aa704e5ba3bcbf60123f4b6c5e929a248b717b962f78c64c49f1" +content-hash = "b09e5553614b918471f77a7b127dc60fba100ae822350664ff1045ff49b71949" diff --git a/pyproject.toml b/pyproject.toml index bb2b539695..c2eac671cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,8 @@ cma = "^3.3.0" joblib = "^1.2.0" hyperopt = "^0.2.7" tabulate = "^0.9.0" +numpy = "^1.26.4" +tensorflow = {version = "^2.14.1", optional = true} [tool.poetry.group.dev] optional = true @@ -73,6 +75,8 @@ docs = "make -C doc html" docs-clean = "make -C doc clean" test-docs = "make -C doc doctest" + + [tool.poetry.group.cuda11] optional = true @@ -81,6 +85,8 @@ cupy-cuda11x = "^12.0.0" cuquantum-python-cu11 = "^23.3.0" qibojit = { git = "https://github.com/qiboteam/qibojit.git" } + + [tool.poetry.group.cuda12] optional = true From 7cf62c5ea82314f13b42dd8386e17597a61fab60 Mon Sep 17 00:00:00 2001 From: scarrazza Date: Fri, 16 Feb 2024 06:26:10 +0100 Subject: [PATCH 195/200] adding missing deps --- poetry.lock | 2 +- pyproject.toml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 80c9adaac1..e9f28f83dc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4944,4 +4944,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "b09e5553614b918471f77a7b127dc60fba100ae822350664ff1045ff49b71949" +content-hash = "ceb8a39781a941368015611e00cb7e27ded43108428c638ea38576d759e0a3da" diff --git a/pyproject.toml b/pyproject.toml index c2eac671cc..52f27ec003 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,8 @@ joblib = "^1.2.0" hyperopt = "^0.2.7" tabulate = "^0.9.0" numpy = "^1.26.4" +networkx = "^3.2.1" +cvxpy = {version = "^1.4.2", optional = true} tensorflow = {version = "^2.14.1", optional = true} [tool.poetry.group.dev] @@ -77,6 +79,8 @@ test-docs = "make -C doc doctest" + + [tool.poetry.group.cuda11] optional = true @@ -87,6 +91,8 @@ qibojit = { git = "https://github.com/qiboteam/qibojit.git" } + + [tool.poetry.group.cuda12] optional = true From 3eb38adfe5a6a4f1b2f1d84dc02eec0fd7b34dd4 Mon Sep 17 00:00:00 2001 From: scarrazza Date: Fri, 16 Feb 2024 06:34:44 +0100 Subject: [PATCH 196/200] marking tf --- poetry.lock | 81 +++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 2 +- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index e9f28f83dc..3b635b3bc4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4926,6 +4926,85 @@ files = [ {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, ] +[[package]] +name = "wrapt" +version = "1.16.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + [[package]] name = "zipp" version = "3.17.0" @@ -4944,4 +5023,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "ceb8a39781a941368015611e00cb7e27ded43108428c638ea38576d759e0a3da" +content-hash = "32240d5c176ef55b4c88f63adf9489e3b0cffeb430b9b40ca1c53dc08291ac1c" diff --git a/pyproject.toml b/pyproject.toml index 52f27ec003..82b35e3938 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ tabulate = "^0.9.0" numpy = "^1.26.4" networkx = "^3.2.1" cvxpy = {version = "^1.4.2", optional = true} -tensorflow = {version = "^2.14.1", optional = true} +tensorflow = { version = "^2.14.1", markers = "sys_platform == 'linux' or sys_platform == 'darwin'", optional = true} [tool.poetry.group.dev] optional = true From 82ade86eaed41c6cf253f9ae88fab368c7d69aa2 Mon Sep 17 00:00:00 2001 From: scarrazza Date: Fri, 16 Feb 2024 06:36:41 +0100 Subject: [PATCH 197/200] fixing extra spaces added by poetry --- pyproject.toml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 82b35e3938..da2ee7a8d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,10 +77,6 @@ docs = "make -C doc html" docs-clean = "make -C doc clean" test-docs = "make -C doc doctest" - - - - [tool.poetry.group.cuda11] optional = true @@ -89,10 +85,6 @@ cupy-cuda11x = "^12.0.0" cuquantum-python-cu11 = "^23.3.0" qibojit = { git = "https://github.com/qiboteam/qibojit.git" } - - - - [tool.poetry.group.cuda12] optional = true From 498857db63e29a424bae90cfa2647b62ceaf93b5 Mon Sep 17 00:00:00 2001 From: Renato Mello Date: Fri, 16 Feb 2024 10:00:36 +0400 Subject: [PATCH 198/200] doc fix --- src/qibo/quantum_info/random_ensembles.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index d16b77f416..94159cf1b2 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -32,10 +32,10 @@ def _ppf(self, theta: float): def uniform_sampling_U3(ngates: int, seed=None, backend=None): - """Samples parameters for Haar-random :math:`U_{3}` (``qibo.gates.U3``). + """Samples parameters for Haar-random :class:`qibo.gates.U3`. Args: - ngates (int): Total number of :math:`U_{3}`s to be sampled. + ngates (int): Total number of :math:`U_{3}` gates to be sampled. seed (int or :class:`numpy.random.Generator`, optional): Either a generator of random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. @@ -44,7 +44,7 @@ def uniform_sampling_U3(ngates: int, seed=None, backend=None): Defaults to ``None``. Returns: - (ndarray): array of shape (``ngates``, :math:`3`). + ndarray: array of shape (``ngates``, :math:`3`). """ if not isinstance(ngates, int): raise_error( From 47b251845c8cbc6dea15348d91f6ec32240576f8 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Fri, 16 Feb 2024 09:58:45 +0100 Subject: [PATCH 199/200] chore: Remove no longer required exceptions for Codecov --- .github/codecov.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 1bf339e4b0..5571132e2b 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -6,7 +6,3 @@ coverage: github_checks: annotations: false - -ignore: - - "setup.py" - - "src/qibo/tests/test_custom_functions.py" From a47e60c0712bc99c80357d72ceb6cf5bc50e9a1a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 00:40:38 +0000 Subject: [PATCH 200/200] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.15.0 → v3.15.1](https://github.com/asottile/pyupgrade/compare/v3.15.0...v3.15.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b8632cdd54..9e5265c24b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: isort args: ["--profile", "black"] - repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 + rev: v3.15.1 hooks: - id: pyupgrade - repo: https://github.com/hadialqattan/pycln