From 129b60f4d475326b139aa15d016cb010b1ac0fa6 Mon Sep 17 00:00:00 2001 From: Shaobo Zhou Date: Sat, 29 Mar 2025 19:20:52 +0100 Subject: [PATCH 01/98] Update predictor(adding callbacks) --- src/mqt/predictor/rl/example_test.py | 6 ++ src/mqt/predictor/rl/predictor.py | 100 +++++++++++++++++++++------ 2 files changed, 83 insertions(+), 23 deletions(-) create mode 100644 src/mqt/predictor/rl/example_test.py diff --git a/src/mqt/predictor/rl/example_test.py b/src/mqt/predictor/rl/example_test.py new file mode 100644 index 000000000..f13162dc6 --- /dev/null +++ b/src/mqt/predictor/rl/example_test.py @@ -0,0 +1,6 @@ +from predictor import Predictor + +rl_pred = Predictor( + figure_of_merit="expected_fidelity", device_name="ibm_washington" +) +rl_pred.train_model(timesteps=100000, model_name="sample_model_rl") \ No newline at end of file diff --git a/src/mqt/predictor/rl/predictor.py b/src/mqt/predictor/rl/predictor.py index db6783782..6febe1dd4 100644 --- a/src/mqt/predictor/rl/predictor.py +++ b/src/mqt/predictor/rl/predictor.py @@ -3,11 +3,15 @@ from __future__ import annotations import logging +import os from typing import TYPE_CHECKING from sb3_contrib import MaskablePPO from sb3_contrib.common.maskable.policies import MaskableMultiInputActorCriticPolicy from sb3_contrib.common.maskable.utils import get_action_masks +from stable_baselines3.common.logger import configure +from stable_baselines3.common.callbacks import CheckpointCallback, EvalCallback, BaseCallback + from mqt.predictor import reward, rl @@ -18,6 +22,24 @@ PATH_LENGTH = 260 +class OffsetCheckpointCallback(BaseCallback): + def __init__(self, save_freq, save_path, name_prefix, offset=0, verbose=0): + super().__init__(verbose) + self.save_freq = save_freq + self.save_path = save_path + self.name_prefix = name_prefix + self.offset = offset + + def _on_step(self) -> bool: + total_steps = self.num_timesteps + self.offset + if total_steps % self.save_freq == 0: + path = f"{self.save_path}/{self.name_prefix}_{total_steps}_steps.zip" + self.model.save(path) + if self.verbose > 0: + print(f"✅ Saved checkpoint: {path}") + return True + + class Predictor: """The Predictor class is used to train a reinforcement learning model for a given figure of merit and device such that it acts as a compiler.""" @@ -66,38 +88,70 @@ def compile_as_predicted( def train_model( self, - timesteps: int = 1000, + timesteps: int = 100000, model_name: str = "model", verbose: int = 2, test: bool = False, + trained: int = 0, ) -> None: - """Trains all models for the given reward functions and device. + """Train or resume model training with offset checkpointing. Arguments: - timesteps: The number of timesteps to train the model. Defaults to 1000. - model_name: The name of the model. Defaults to "model". - verbose: The verbosity level. Defaults to 2. - test: Whether to train the model for testing purposes. Defaults to False. + timesteps: Total training timesteps desired. + model_name: Prefix for saved model and logs. + verbose: Verbosity level for PPO. + test: If True, uses tiny n_steps for quick test. + trained: Number of timesteps already trained (for resuming). """ - if test: - n_steps = 10 - progress_bar = False + n_steps = 10 if test else 2048 + progress_bar = not test + + log_dir = f"./{model_name}_{self.figure_of_merit}_{self.device_name}" + ckpt_path = f"./checkpoints/{model_name}_{trained}_steps.zip" + + logger.debug(f"🔁 Checking for checkpoint: {ckpt_path}") + + if os.path.exists(ckpt_path): + logger.info(f"📦 Loading checkpoint from {ckpt_path}") + model = MaskablePPO.load( + ckpt_path, + env=self.env, + tensorboard_log=log_dir, + verbose=verbose, + device="cuda", # or "cpu" depending on your setup + ) else: - n_steps = 2048 - progress_bar = True - - logger.debug("Start training for: " + self.figure_of_merit + " on " + self.device_name) - model = MaskablePPO( - MaskableMultiInputActorCriticPolicy, - self.env, - verbose=verbose, - tensorboard_log="./" + model_name + "_" + self.figure_of_merit + "_" + self.device_name, - gamma=0.98, - n_steps=n_steps, + logger.info(f"🆕 No checkpoint found, starting fresh training") + model = MaskablePPO( + MaskableMultiInputActorCriticPolicy, + self.env, + verbose=verbose, + tensorboard_log=log_dir, + gamma=0.98, + n_steps=n_steps, + ) + + remaining = timesteps - trained + + callback = OffsetCheckpointCallback( + save_freq=1000, + save_path="./checkpoints", + name_prefix=model_name, + offset=trained, + verbose=1, ) - # Training Loop: In each iteration, the agent collects n_steps steps (rollout), - # updates the policy for n_epochs, and then repeats the process until total_timesteps steps have been taken. - model.learn(total_timesteps=timesteps, progress_bar=progress_bar) + + tb_log_name = "ppo" + new_logger = configure(folder=os.path.join(log_dir, tb_log_name), format_strings=["stdout", "tensorboard"]) + model.set_logger(new_logger) + model.learn( + total_timesteps=remaining, + tb_log_name=tb_log_name, + callback=callback, + progress_bar=progress_bar, + ) + model.save( rl.helper.get_path_trained_model() / (model_name + "_" + self.figure_of_merit + "_" + self.device_name) ) + logger.info("✅ Final model saved.") \ No newline at end of file From 08889bd2c8ba130c21092503ce7cf56095ede815 Mon Sep 17 00:00:00 2001 From: Shaobo Zhou Date: Thu, 10 Apr 2025 16:06:35 +0200 Subject: [PATCH 02/98] Update --- src/mqt/predictor/rl/helper.py | 7 +- src/mqt/predictor/rl/predictor.py | 102 +++++++----------------------- 2 files changed, 29 insertions(+), 80 deletions(-) diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 1b6831049..083c28939 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -351,7 +351,7 @@ def get_state_sample(max_qubits: int | None = None) -> tuple[QuantumCircuit, str Returns: A tuple containing the random quantum circuit and the path to the file from which it was read. """ - file_list = list(get_path_training_circuits().glob("*.qasm")) + """ file_list = list(get_path_training_circuits().glob("*.qasm")) path_zip = get_path_training_circuits() / "training_data_compilation.zip" if len(file_list) == 0 and path_zip.exists(): @@ -359,7 +359,10 @@ def get_state_sample(max_qubits: int | None = None) -> tuple[QuantumCircuit, str zip_ref.extractall(get_path_training_circuits()) file_list = list(get_path_training_circuits().glob("*.qasm")) - assert len(file_list) > 0 + assert len(file_list) > 0 """ + #base_path = get_path_training_circuits() / "mqt_bench_training" + base_path = get_path_training_circuits() / "training_data_compilation" + file_list = list(base_path.rglob("*.qasm")) found_suitable_qc = False while not found_suitable_qc: diff --git a/src/mqt/predictor/rl/predictor.py b/src/mqt/predictor/rl/predictor.py index 6febe1dd4..64ebae0a6 100644 --- a/src/mqt/predictor/rl/predictor.py +++ b/src/mqt/predictor/rl/predictor.py @@ -3,15 +3,11 @@ from __future__ import annotations import logging -import os from typing import TYPE_CHECKING from sb3_contrib import MaskablePPO from sb3_contrib.common.maskable.policies import MaskableMultiInputActorCriticPolicy from sb3_contrib.common.maskable.utils import get_action_masks -from stable_baselines3.common.logger import configure -from stable_baselines3.common.callbacks import CheckpointCallback, EvalCallback, BaseCallback - from mqt.predictor import reward, rl @@ -22,24 +18,6 @@ PATH_LENGTH = 260 -class OffsetCheckpointCallback(BaseCallback): - def __init__(self, save_freq, save_path, name_prefix, offset=0, verbose=0): - super().__init__(verbose) - self.save_freq = save_freq - self.save_path = save_path - self.name_prefix = name_prefix - self.offset = offset - - def _on_step(self) -> bool: - total_steps = self.num_timesteps + self.offset - if total_steps % self.save_freq == 0: - path = f"{self.save_path}/{self.name_prefix}_{total_steps}_steps.zip" - self.model.save(path) - if self.verbose > 0: - print(f"✅ Saved checkpoint: {path}") - return True - - class Predictor: """The Predictor class is used to train a reinforcement learning model for a given figure of merit and device such that it acts as a compiler.""" @@ -88,70 +66,38 @@ def compile_as_predicted( def train_model( self, - timesteps: int = 100000, + timesteps: int = 1000, model_name: str = "model", verbose: int = 2, test: bool = False, - trained: int = 0, ) -> None: - """Train or resume model training with offset checkpointing. + """Trains all models for the given reward functions and device. Arguments: - timesteps: Total training timesteps desired. - model_name: Prefix for saved model and logs. - verbose: Verbosity level for PPO. - test: If True, uses tiny n_steps for quick test. - trained: Number of timesteps already trained (for resuming). + timesteps: The number of timesteps to train the model. Defaults to 1000. + model_name: The name of the model. Defaults to "model". + verbose: The verbosity level. Defaults to 2. + test: Whether to train the model for testing purposes. Defaults to False. """ - n_steps = 10 if test else 2048 - progress_bar = not test - - log_dir = f"./{model_name}_{self.figure_of_merit}_{self.device_name}" - ckpt_path = f"./checkpoints/{model_name}_{trained}_steps.zip" - - logger.debug(f"🔁 Checking for checkpoint: {ckpt_path}") - - if os.path.exists(ckpt_path): - logger.info(f"📦 Loading checkpoint from {ckpt_path}") - model = MaskablePPO.load( - ckpt_path, - env=self.env, - tensorboard_log=log_dir, - verbose=verbose, - device="cuda", # or "cpu" depending on your setup - ) + if test: + n_steps = 10 + progress_bar = False else: - logger.info(f"🆕 No checkpoint found, starting fresh training") - model = MaskablePPO( - MaskableMultiInputActorCriticPolicy, - self.env, - verbose=verbose, - tensorboard_log=log_dir, - gamma=0.98, - n_steps=n_steps, - ) - - remaining = timesteps - trained - - callback = OffsetCheckpointCallback( - save_freq=1000, - save_path="./checkpoints", - name_prefix=model_name, - offset=trained, - verbose=1, + n_steps = 500 + progress_bar = True + + logger.debug("Start training for: " + self.figure_of_merit + " on " + self.device_name) + model = MaskablePPO( + MaskableMultiInputActorCriticPolicy, + self.env, + verbose=verbose, + tensorboard_log="./" + model_name + "_" + self.figure_of_merit + "_" + self.device_name, + gamma=0.98, + n_steps=n_steps, ) - - tb_log_name = "ppo" - new_logger = configure(folder=os.path.join(log_dir, tb_log_name), format_strings=["stdout", "tensorboard"]) - model.set_logger(new_logger) - model.learn( - total_timesteps=remaining, - tb_log_name=tb_log_name, - callback=callback, - progress_bar=progress_bar, - ) - + # Training Loop: In each iteration, the agent collects n_steps steps (rollout), + # updates the policy for n_epochs, and then repeats the process until total_timesteps steps have been taken. + model.learn(total_timesteps=timesteps, progress_bar=progress_bar) model.save( rl.helper.get_path_trained_model() / (model_name + "_" + self.figure_of_merit + "_" + self.device_name) - ) - logger.info("✅ Final model saved.") \ No newline at end of file + ) \ No newline at end of file From 78dc1aa91d35a90ede315336608491622bdff854 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Tue, 29 Jul 2025 14:31:42 +0200 Subject: [PATCH 03/98] Implement new mapping actions Update action space and feature space Update actions Update action space --- src/mqt/predictor/rl/actions.py | 271 ++++++++++++++++++++++++++- src/mqt/predictor/rl/helper.py | 183 +++++++++++++++++- src/mqt/predictor/rl/predictorenv.py | 142 +++++++------- 3 files changed, 524 insertions(+), 72 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index fecca51df..de7d98a98 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -51,7 +51,9 @@ from qiskit.transpiler.passes import ( ApplyLayout, BasisTranslator, + BasicSwap, Collect2qBlocks, + CollectCliffords, CommutativeCancellation, CommutativeInverseCancellation, ConsolidateBlocks, @@ -67,7 +69,9 @@ OptimizeCliffords, RemoveDiagonalGatesBeforeMeasure, SabreLayout, + SabreSwap, Size, + TrivialLayout, UnitarySynthesis, VF2Layout, VF2PostLayout, @@ -80,6 +84,8 @@ get_bqskit_native_gates, ) +from mqt.predictor.rl.helper import SafeAIRouting, get_openqasm_gates + if TYPE_CHECKING: from collections.abc import Callable from typing import Any @@ -125,6 +131,7 @@ class Action: Callable[..., tuple[Any, ...] | Circuit], ] ) + stochastic: bool = False @dataclass @@ -180,7 +187,7 @@ def remove_action(name: str) -> None: "Optimize1qGatesDecomposition", CompilationOrigin.QISKIT, PassType.OPT, - [Optimize1qGatesDecomposition()], + [Optimize1qGatesDecomposition(basis=get_openqasm_gates())], ) ) @@ -240,16 +247,18 @@ def remove_action(name: str) -> None: "OptimizeCliffords", CompilationOrigin.QISKIT, PassType.OPT, - [OptimizeCliffords()], + [CollectCliffords(), OptimizeCliffords()], ) ) register_action( - DeviceIndependentAction( + DeviceDependentAction( "Opt2qBlocks", CompilationOrigin.QISKIT, PassType.OPT, - [Collect2qBlocks(), ConsolidateBlocks(), UnitarySynthesis()], + transpile_pass=lambda device: [Collect2qBlocks(), + ConsolidateBlocks(basis_gates=device.operation_names), + UnitarySynthesis(basis_gates=device.operation_names, coupling_map=device.build_coupling_map())], ) ) @@ -393,9 +402,69 @@ def remove_action(name: str) -> None: "SabreMapping", CompilationOrigin.QISKIT, PassType.MAPPING, - transpile_pass=lambda device: [ - SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=False) - ], + stochastic=True, + # Qiskit O3 by default uses (max_iterations, layout_trials, swap_trials) = (4, 20, 20) + transpile_pass=lambda device, max_iteration=(20,20): [ + SabreLayout( + coupling_map=CouplingMap(device.build_coupling_map()), + skip_routing=False, + layout_trials=max_iteration[0], + swap_trials=max_iteration[1], + max_iterations=4, + seed=None + ), + ], + ) +) + +register_action( + DeviceDependentAction( + "SabreLayout+BasicSwap", + CompilationOrigin.QISKIT, + PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device, max_iteration=(20,20): [ + SabreLayout( + coupling_map=CouplingMap(device.build_coupling_map()), + skip_routing=True, + layout_trials=max_iteration[0], + swap_trials=max_iteration[1], + max_iterations=4, + seed=None + ), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), + ], + ) +) + +register_action( + DeviceDependentAction( + "SabreLayout+AIRouting", + CompilationOrigin.QISKIT, + PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device, max_iteration=(20,20): [ + SabreLayout( + coupling_map=CouplingMap(device.build_coupling_map()), + skip_routing=True, + layout_trials=max_iteration[0], + swap_trials=max_iteration[1], + max_iterations=4, + seed=None + ), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="optimize", + local_mode=True + ), + ], ) ) @@ -421,6 +490,194 @@ def remove_action(name: str) -> None: ) ) +register_action( + DeviceDependentAction( + name="DenseLayout+BasicSwap", + origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, + transpile_pass=lambda device: [ + DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), + ], + ) +) + +register_action( + DeviceDependentAction( + name="DenseLayout+SabreSwap", + origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device, max_iteration=(20,20): [ + DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SabreSwap(coupling_map=CouplingMap(device.build_coupling_map()), heuristic="decay", trials=max_iteration[1], seed=None), + ], + ) +) + +register_action( + DeviceDependentAction( + name="DenseLayout+AIRouting", + origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device: [ + DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="optimize", + local_mode=True + ), + ], + ) +) + +register_action( + DeviceDependentAction( + name="VF2Layout+BasicSwap", + origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, + transpile_pass=lambda device: [ + VF2Layout( + coupling_map=CouplingMap(device.build_coupling_map()), + target=device, + ), + ConditionalController( + [ + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + == VF2LayoutStopReason.SOLUTION_FOUND, + ), + ConditionalController( + [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + # Run if VF2Layout did not find a solution + condition=lambda property_set: property_set["VF2Layout_stop_reason"] != VF2LayoutStopReason.SOLUTION_FOUND, + ), + BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), + ], + ) +) + +register_action( + DeviceDependentAction( + name="VF2Layout+SabreSwap", + origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device, max_iteration=(20,20): [ + VF2Layout( + coupling_map=CouplingMap(device.build_coupling_map()), + target=device, + ), + ConditionalController( + [ + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + == VF2LayoutStopReason.SOLUTION_FOUND, + ), + ConditionalController( + [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + # Run if VF2Layout did not find a solution + condition=lambda property_set: property_set["VF2Layout_stop_reason"] != VF2LayoutStopReason.SOLUTION_FOUND, + ), + SabreSwap(coupling_map=CouplingMap(device.build_coupling_map()), heuristic="decay", trials=max_iteration[1], seed=None), + ], + ) +) + +register_action( + DeviceDependentAction( + name="VF2Layout+AIRouting", + origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device:[ + VF2Layout( + coupling_map=CouplingMap(device.build_coupling_map()), + target=device, + ), + ConditionalController( + [ + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + == VF2LayoutStopReason.SOLUTION_FOUND, + ), + ConditionalController( + [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + # Run if VF2Layout did not find a solution + condition=lambda property_set: property_set["VF2Layout_stop_reason"] != VF2LayoutStopReason.SOLUTION_FOUND, + ), + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="optimize", + local_mode=True + ), + ], + ) +) + +register_action( + DeviceDependentAction( + name="SabreLayout+AIRouting", + origin=CompilationOrigin.QISKIT, + stochastic=True, + pass_type=PassType.MAPPING, + transpile_pass=lambda device, max_iteration=(20, 20): [ + SabreLayout( + coupling_map=CouplingMap(device.build_coupling_map()), + skip_routing=True, + layout_trials=max_iteration[0], + swap_trials=1, + max_iterations=4, + ), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="optimize", + local_mode=True, + ), + ], + ) +) + register_action( DeviceDependentAction( "BasisTranslator", diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 68bb9401d..f2c948c85 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -16,6 +16,10 @@ import numpy as np from qiskit import QuantumCircuit +from qiskit.converters import circuit_to_dag, dag_to_circuit +from qiskit.circuit import ClassicalRegister, QuantumRegister +from qiskit.transpiler import PassManager +from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.utils import calc_supermarq_features @@ -28,7 +32,140 @@ logger = logging.getLogger("mqt-predictor") +def extract_cregs_and_measurements(qc): + cregs = [ClassicalRegister(cr.size, name=cr.name) for cr in qc.cregs] + measurements = [ + (item.operation, item.qubits, item.clbits) + for item in qc.data + if item.operation.name == "measure" + ] + return cregs, measurements +def remove_cregs(qc): + qregs = [QuantumRegister(qr.size, name=qr.name) for qr in qc.qregs] + new_qc = QuantumCircuit(*qregs) + old_to_new = {} + for orig_qr, new_qr in zip(qc.qregs, new_qc.qregs): + for idx in range(orig_qr.size): + old_to_new[orig_qr[idx]] = new_qr[idx] + for item in qc.data: + instr = item.operation + qargs = [old_to_new[q] for q in item.qubits] + if instr.name not in ("measure", "barrier"): + new_qc.append(instr, qargs) + return new_qc + +def add_cregs_and_measurements(qc, cregs, measurements, qubit_map=None): + for cr in cregs: + qc.add_register(cr) + for instr, qargs, cargs in measurements: + if qubit_map: + new_qargs = [qubit_map[q] for q in qargs] + else: + new_qargs = qargs + qc.append(instr, new_qargs, cargs) + return qc + +class SafeAIRouting(AIRouting): + """ + Remove cregs before AIRouting and add them back afterwards + Necessary because there are cases AIRouting can't handle + """ + def run(self, dag): + # 1. Convert input dag to circuit + qc_orig = dag_to_circuit(dag) + + # 2. Extract classical registers and measurement instructions + cregs, measurements = extract_cregs_and_measurements(qc_orig) + + # 3. Remove cregs and measurements + qc_noclassical = remove_cregs(qc_orig) + + # 4. Convert back to dag and run routing (AIRouting) + dag_noclassical = circuit_to_dag(qc_noclassical) + dag_routed = super().run(dag_noclassical) + + # 5. Convert routed dag to circuit for restoration + qc_routed = dag_to_circuit(dag_routed) + + # 6. Build mapping from original qubits to qubits in routed circuit + final_layout = getattr(self, "property_set", {}).get("final_layout", None) + if final_layout is None and hasattr(dag_routed, "property_set"): + final_layout = dag_routed.property_set.get("final_layout", None) + + qubit_map = {} + for virt in qc_orig.qubits: + phys = final_layout[virt] + if isinstance(phys, int): + qubit_map[virt] = qc_routed.qubits[phys] + else: + try: + idx = qc_routed.qubits.index(phys) + except ValueError: + raise RuntimeError(f"Physical qubit {phys} not found in output circuit!") + qubit_map[virt] = qc_routed.qubits[idx] + # 7. Restore classical registers and measurement instructions + qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) + # 8. Return as dag + return circuit_to_dag(qc_final) + +def best_of_n_passmanager( + action, device, qc, max_iteration=(20,20), + metric_fn=None, +): + """ + Runs the given transpile_pass multiple times and keeps the best result. + action: the action dict with a 'transpile_pass' key (lambda/device->[passes]) + device: the backend or device + qc: input circuit + max_iteration: number of times to try + metric_fn: function(circ) -> float for scoring + require_layout: skip outputs with missing layouts + """ + best_val = None + best_result = None + best_property_set = None + + if action["name"] == "SabreLayout+AIRouting": + all_passes = action.transpile_pass(device, max_iteration) + else: + all_passes = action.transpile_pass(device) + + layout_passes = all_passes[:-1] + routing_pass = all_passes[-1:] + + # Run layout once + layout_pm = PassManager(layout_passes) + try: + layouted_qc = layout_pm.run(qc) + layout_props = dict(layout_pm.property_set) + except Exception as e: + return qc, {} + + # Run routing multiple times and optimize for the given metric + for i in range(max_iteration[1]): + pm = PassManager(routing_pass) + pm.property_set.update(layout_props) + try: + out_circ = pm.run(layouted_qc) + prop_set = dict(pm.property_set) + + val = metric_fn(out_circ) if metric_fn else out_circ.depth() + if best_val is None or val < best_val: + best_val = val + best_result = out_circ + best_property_set = prop_set + if best_val == 0: + break + except Exception as e: + print(f"[Routing] Trial {i+1} failed: {e}") + continue + if best_result is not None: + return best_result, best_property_set + else: + print("All mapping attempts failed; returning original circuit.") + return qc, {} + def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generator) -> tuple[QuantumCircuit, str]: """Returns a random quantum circuit from the training circuits folder. @@ -68,8 +205,51 @@ def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generat return qc, str(file_list[random_index]) +def get_openqasm_gates() -> list[str]: + """ Returns a list of all quantum gates within the openQASM 2.0 standard header. + + According to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc + Removes generic single qubit gates u1, u2, u3 since they are no meaningful features for RL -def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float64]]: + """ + return [ + "cx", + "id", + "u", + "p", + "x", + "y", + "z", + "h", + "r", + "s", + "sdg", + "t", + "tdg", + "rx", + "ry", + "rz", + "sx", + "sxdg", + "cz", + "cy", + "swap", + "ch", + "ccx", + "cswap", + "crx", + "cry", + "crz", + "cu1", + "cp", + "csx", + "cu", + "rxx", + "rzz", + "rccx", + ] + +def create_feature_dict(qc: QuantumCircuit, basis_gates: list[str], coupling_map) -> dict[str, int | NDArray[np.float64]]: """Creates a feature dictionary for a given quantum circuit. Arguments: @@ -82,7 +262,6 @@ def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float6 "num_qubits": qc.num_qubits, "depth": qc.depth(), } - supermarq_features = calc_supermarq_features(qc) # for all dict values, put them in a list each feature_dict["program_communication"] = np.array([supermarq_features.program_communication], dtype=np.float32) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index fbaa4875f..41d5121af 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -38,7 +38,8 @@ from joblib import load from pytket.circuit import Qubit from pytket.extensions.qiskit import qiskit_to_tk, tk_to_qiskit -from qiskit import QuantumCircuit +from qiskit import QuantumCircuit, transpile +from qiskit.circuit.library import RCCXGate from qiskit.passmanager.flow_controllers import DoWhileController from qiskit.transpiler import CouplingMap, PassManager, Target, TranspileLayout from qiskit.transpiler.passes import CheckMap, GatesInBasis @@ -54,7 +55,7 @@ figure_of_merit, ) from mqt.predictor.rl.actions import CompilationOrigin, DeviceDependentAction, PassType, get_actions_by_pass_type -from mqt.predictor.rl.helper import create_feature_dict, get_path_training_circuits, get_state_sample +from mqt.predictor.rl.helper import create_feature_dict, get_path_training_circuits, get_state_sample, get_openqasm_gates, best_of_n_passmanager from mqt.predictor.rl.parsing import ( final_layout_bqskit_to_qiskit, final_layout_pytket_to_qiskit, @@ -89,8 +90,6 @@ def __init__( self.action_set = {} self.actions_synthesis_indices = [] - self.actions_layout_indices = [] - self.actions_routing_indices = [] self.actions_mapping_indices = [] self.actions_opt_indices = [] self.actions_final_optimization_indices = [] @@ -110,14 +109,6 @@ def __init__( self.action_set[index] = elem self.actions_synthesis_indices.append(index) index += 1 - for elem in action_dict[PassType.LAYOUT]: - self.action_set[index] = elem - self.actions_layout_indices.append(index) - index += 1 - for elem in action_dict[PassType.ROUTING]: - self.action_set[index] = elem - self.actions_routing_indices.append(index) - index += 1 for elem in action_dict[PassType.OPT]: self.action_set[index] = elem self.actions_opt_indices.append(index) @@ -163,6 +154,7 @@ def __init__( } self.observation_space = Dict(spaces) self.filename = "" + self.max_iter = (20,20) # (layout_trials, routing _trials) def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any, Any]]: """Executes the given action and returns the new state, the reward, whether the episode is done, whether the episode is truncated and additional information. @@ -202,9 +194,14 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any reward_val = 0 done = False - # in case the Qiskit.QuantumCircuit has unitary or u gates in it, decompose them (because otherwise qiskit will throw an error when applying the BasisTranslator + # in case the Qiskit.QuantumCircuit has unitary or u gates or clifford in it, decompose them (because otherwise qiskit will throw an error when applying the BasisTranslator if self.state.count_ops().get("unitary"): - self.state = self.state.decompose(gates_to_decompose="unitary") + temp_circ = self.state.decompose(gates_to_decompose="unitary") + # qiskit fallback to ['id', 'u1', 'u2', 'u3', 'cx'] by default according to https://quantum.cloud.ibm.com/docs/en/api/qiskit/0.24/transpiler + self.state = transpile(temp_circ, basis_gates=get_openqasm_gates(), optimization_level=0) + elif self.state.count_ops().get("clifford"): + temp_circ = self.state.decompose(gates_to_decompose="clifford") + self.state = transpile(temp_circ, basis_gates=get_openqasm_gates(), optimization_level=0) self.state._layout = self.layout # noqa: SLF001 obs = create_feature_dict(self.state) @@ -319,55 +316,76 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: raise ValueError(msg) def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: - if action.name == "QiskitO3" and isinstance(action, DeviceDependentAction): - passes = action.transpile_pass( - self.device.operation_names, - CouplingMap(self.device.build_coupling_map()) if self.layout else None, - ) - pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) + if action.get("stochastic", False): + metric_fn = lambda circ: circ.count_ops().get("swap", 0) + # for stochastic actions, pass the layout/routing trials parameter + max_iteration = self.max_iter + if "Sabre" in action["name"] and "AIRouting" not in action["name"]: + # Internal trials for Sabre + transpile_pass = action.transpile_pass(self.device, max_iteration) + pm = PassManager(transpile_pass) + altered_qc = pm.run(self.state) + pm_property_set = dict(pm.property_set) + elif "AIRouting" in action["name"]: + # Run AIRouting in custom loop + altered_qc, pm_property_set = best_of_n_passmanager( + action, + self.device, + self.state, + max_iteration=max_iteration, + metric_fn=metric_fn, + ) else: - transpile_pass = ( - action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass - ) - pm = PassManager(transpile_pass) - - altered_qc = pm.run(self.state) - - if action_index in ( - self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices - ): - altered_qc = self._handle_qiskit_layout_postprocessing(action, pm, altered_qc) - - elif action_index in self.actions_routing_indices and self.layout: - self.layout.final_layout = pm.property_set["final_layout"] - + if action.name == "QiskitO3" and isinstance(action, DeviceDependentAction): + passes = action.transpile_pass( + self.device.operation_names, + CouplingMap(self.device.build_coupling_map()) if self.layout else None, + ) + pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) + altered_qc = pm.run(self.state) + pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + else: + transpile_pass = ( + action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass + ) + pm = PassManager(transpile_pass) + altered_qc = pm.run(self.state) + pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + if action_index in ( + self.actions_mapping_indices + self.actions_final_optimization_indices + ): + pm_property_set = dict(pm.property_set) + altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) + return altered_qc - + def _handle_qiskit_layout_postprocessing( - self, action: Action, pm: PassManager, altered_qc: QuantumCircuit + self, action: Action, pm_property_set: dict, altered_qc: QuantumCircuit, ) -> QuantumCircuit: if action.name == "VF2PostLayout": - assert pm.property_set["VF2PostLayout_stop_reason"] is not None - post_layout = pm.property_set["post_layout"] + assert pm_property_set["VF2PostLayout_stop_reason"] is not None + post_layout = pm_property_set["post_layout"] if post_layout: altered_qc, _ = postprocess_vf2postlayout(altered_qc, post_layout, self.layout) - elif action.name == "VF2Layout": - assert pm.property_set["VF2Layout_stop_reason"] == VF2LayoutStopReason.SOLUTION_FOUND - assert pm.property_set["layout"] else: - assert pm.property_set["layout"] + assert pm_property_set["layout"] - if pm.property_set["layout"]: + if pm_property_set["layout"]: self.layout = TranspileLayout( - initial_layout=pm.property_set["layout"], - input_qubit_mapping=pm.property_set["original_qubit_indices"], - final_layout=pm.property_set["final_layout"], + initial_layout=pm_property_set["layout"], + input_qubit_mapping=pm_property_set["original_qubit_indices"], + final_layout=pm_property_set["final_layout"], _output_qubit_list=altered_qc.qubits, _input_qubit_count=self.num_qubits_uncompiled_circuit, ) + if pm_property_set["final_layout"]: + self.layout.final_layout = pm_property_set["final_layout"] return altered_qc def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircuit: + if any(isinstance(gate[0], RCCXGate) for gate in self.state.data): + # RCCX could cause error + self.state = transpile(self.state, basis_gates=get_openqasm_gates()[:-1], optimization_level=0) tket_qc = qiskit_to_tk(self.state, preserve_param_uuid=True) transpile_pass = ( action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass @@ -383,7 +401,8 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui if action_index in self.actions_routing_indices: assert self.layout is not None self.layout.final_layout = final_layout_pytket_to_qiskit(tket_qc, altered_qc) - + # Decompose to the allowed gates (by default generic u gates are used) + altered_qc = transpile(altered_qc, basis_gates=get_openqasm_gates(), optimization_level=0) return altered_qc def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCircuit: @@ -424,25 +443,22 @@ def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCirc def determine_valid_actions_for_state(self) -> list[int]: """Determines and returns the valid actions for the current state.""" - check_nat_gates = GatesInBasis(target=self.device) + check_nat_gates = GatesInBasis(basis_gates=self.device.basis_gates) check_nat_gates(self.state) only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] - if not only_nat_gates: - actions = self.actions_synthesis_indices + self.actions_opt_indices - if self.layout is not None: - actions += self.actions_routing_indices - return actions - - check_mapping = CheckMap(coupling_map=self.device.build_coupling_map()) + check_mapping = CheckMap(coupling_map=CouplingMap(self.device.coupling_map)) check_mapping(self.state) mapped = check_mapping.property_set["is_swap_mapped"] - if mapped and self.layout is not None: # The circuit is correctly mapped. - return [self.action_terminate_index, *self.actions_opt_indices] - - if self.layout is not None: # The circuit is not yet mapped but a layout is set. - return self.actions_routing_indices + if not only_nat_gates: # not native gates yet + actions = self.actions_synthesis_indices + self.actions_opt_indices + return actions - # No layout applied yet - return self.actions_mapping_indices + self.actions_layout_indices + self.actions_opt_indices + if mapped and self.layout is not None: # The circuit is correctly mapped. + return [self.action_terminate_index, *self.actions_opt_indices, *self.actions_final_optimization_indices] + else: + # The circuit is not mapped yet + # Or the circuit was mapped but some optimization actions change its structure and the circuit is again unmapped + # In this case, re-do mapping completely as the previous layout is not optimal on the new structure + return self.actions_mapping_indices + self.actions_opt_indices \ No newline at end of file From a3ba8367324590b1b01f731c702e5052b11e3d3b Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Tue, 29 Jul 2025 17:51:24 +0200 Subject: [PATCH 04/98] Fix: resolve pre-commit issues and add missing annotations Fix: resolve pre-commit issues and add missing annotations Fix: resolve pre-commit issues and add missing annotations Remove example_test.py Remove example_test.py --- pyproject.toml | 1 + src/mqt/predictor/rl/example_test.py | 6 -- src/mqt/predictor/rl/helper.py | 94 +++++++++++++++++++++------- src/mqt/predictor/rl/predictorenv.py | 9 +-- 4 files changed, 79 insertions(+), 31 deletions(-) delete mode 100644 src/mqt/predictor/rl/example_test.py diff --git a/pyproject.toml b/pyproject.toml index 2d8a4f988..5c66b12d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ dependencies = [ "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` + "qiskit-ibm-transpiler>=0.2.0", ] classifiers = [ diff --git a/src/mqt/predictor/rl/example_test.py b/src/mqt/predictor/rl/example_test.py deleted file mode 100644 index f13162dc6..000000000 --- a/src/mqt/predictor/rl/example_test.py +++ /dev/null @@ -1,6 +0,0 @@ -from predictor import Predictor - -rl_pred = Predictor( - figure_of_merit="expected_fidelity", device_name="ibm_washington" -) -rl_pred.train_model(timesteps=100000, model_name="sample_model_rl") \ No newline at end of file diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index f2c948c85..1ea9cf6a7 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -12,16 +12,18 @@ import logging from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional, Callable, List, Tuple, Dict, Any import numpy as np from qiskit import QuantumCircuit from qiskit.converters import circuit_to_dag, dag_to_circuit -from qiskit.circuit import ClassicalRegister, QuantumRegister -from qiskit.transpiler import PassManager +from qiskit.circuit import ClassicalRegister, QuantumRegister, Instruction +from qiskit.transpiler import PassManager, Target +from qiskit.dagcircuit import DAGCircuit from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.utils import calc_supermarq_features +from mqt.predictor.rl.actions import Action if TYPE_CHECKING: from numpy.random import Generator @@ -32,7 +34,16 @@ logger = logging.getLogger("mqt-predictor") -def extract_cregs_and_measurements(qc): +def extract_cregs_and_measurements(qc: QuantumCircuit) -> Tuple[List[ClassicalRegister], List[tuple[Instruction, List, List]]]: + """ + Extracts classical registers and measurement operations from a quantum circuit. + + Args: + qc: The input QuantumCircuit. + + Returns: + A tuple containing a list of classical registers and a list of measurement operations. + """ cregs = [ClassicalRegister(cr.size, name=cr.name) for cr in qc.cregs] measurements = [ (item.operation, item.qubits, item.clbits) @@ -41,7 +52,16 @@ def extract_cregs_and_measurements(qc): ] return cregs, measurements -def remove_cregs(qc): +def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: + """ + Removes classical registers and measurement operations from the circuit. + + Args: + qc: The input QuantumCircuit. + + Returns: + A new QuantumCircuit with only quantum operations (no cregs or measurements). + """ qregs = [QuantumRegister(qr.size, name=qr.name) for qr in qc.qregs] new_qc = QuantumCircuit(*qregs) old_to_new = {} @@ -55,7 +75,24 @@ def remove_cregs(qc): new_qc.append(instr, qargs) return new_qc -def add_cregs_and_measurements(qc, cregs, measurements, qubit_map=None): +def add_cregs_and_measurements( + qc: QuantumCircuit, + cregs: List[ClassicalRegister], + measurements: List[Tuple[Instruction, List, List]], + qubit_map: Optional[Dict] = None, +) -> QuantumCircuit: + """ + Adds classical registers and measurement operations back to the quantum circuit. + + Args: + qc: The quantum circuit to which cregs and measurements are added. + cregs: List of ClassicalRegister to add. + measurements: List of measurement instructions as tuples (Instruction, qubits, clbits). + qubit_map: Optional dictionary mapping original qubits to new qubits. + + Returns: + The modified QuantumCircuit with cregs and measurements added. + """ for cr in cregs: qc.add_register(cr) for instr, qargs, cargs in measurements: @@ -68,10 +105,15 @@ def add_cregs_and_measurements(qc, cregs, measurements, qubit_map=None): class SafeAIRouting(AIRouting): """ - Remove cregs before AIRouting and add them back afterwards - Necessary because there are cases AIRouting can't handle + Custom AIRouting wrapper that removes classical registers before routing. + + This prevents failures in AIRouting when classical bits are present by + temporarily removing classical registers and measurements and restoring + them after routing is completed. """ - def run(self, dag): + def run(self, dag: DAGCircuit) -> DAGCircuit: + """Run the routing pass on a DAGCircuit.""" + # 1. Convert input dag to circuit qc_orig = dag_to_circuit(dag) @@ -101,8 +143,8 @@ def run(self, dag): else: try: idx = qc_routed.qubits.index(phys) - except ValueError: - raise RuntimeError(f"Physical qubit {phys} not found in output circuit!") + except ValueError as err: + raise RuntimeError(f"Physical qubit {phys} not found in output circuit!") from err qubit_map[virt] = qc_routed.qubits[idx] # 7. Restore classical registers and measurement instructions qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) @@ -110,17 +152,27 @@ def run(self, dag): return circuit_to_dag(qc_final) def best_of_n_passmanager( - action, device, qc, max_iteration=(20,20), - metric_fn=None, -): + action: Action, + device: Target, + qc: QuantumCircuit, + max_iteration: Tuple[int, int] = (20, 20), + metric_fn: Optional[Callable[[QuantumCircuit], float]] = None, +)-> tuple[QuantumCircuit, Dict[str, Any]]: """ Runs the given transpile_pass multiple times and keeps the best result. - action: the action dict with a 'transpile_pass' key (lambda/device->[passes]) - device: the backend or device - qc: input circuit - max_iteration: number of times to try - metric_fn: function(circ) -> float for scoring - require_layout: skip outputs with missing layouts + + Args: + action: The action dictionary with a 'transpile_pass' key + (lambda device -> [passes]). + device: The target backend or device. + qc: The input quantum circuit. + max_iteration: A tuple (layout_trials, routing_trials) specifying + how many times to try. + metric_fn: Optional function to score circuits; defaults to circuit depth. + + Returns: + A tuple containing the best transpiled circuit and its corresponding + property set. """ best_val = None best_result = None @@ -249,7 +301,7 @@ def get_openqasm_gates() -> list[str]: "rccx", ] -def create_feature_dict(qc: QuantumCircuit, basis_gates: list[str], coupling_map) -> dict[str, int | NDArray[np.float64]]: +def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float64]]: """Creates a feature dictionary for a given quantum circuit. Arguments: diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 41d5121af..5b9a0c668 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -316,17 +316,18 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: raise ValueError(msg) def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: - if action.get("stochastic", False): - metric_fn = lambda circ: circ.count_ops().get("swap", 0) + if getattr(action, "stochastic", False): + def metric_fn(circ: QuantumCircuit) -> float: + return float(circ.count_ops().get("swap", 0)) # for stochastic actions, pass the layout/routing trials parameter max_iteration = self.max_iter - if "Sabre" in action["name"] and "AIRouting" not in action["name"]: + if "Sabre" in action.name and "AIRouting" not in action.name: # Internal trials for Sabre transpile_pass = action.transpile_pass(self.device, max_iteration) pm = PassManager(transpile_pass) altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) - elif "AIRouting" in action["name"]: + elif "AIRouting" in action.name: # Run AIRouting in custom loop altered_qc, pm_property_set = best_of_n_passmanager( action, From 5935e6f1fb288d8d03137ae03c538f2dc8dac74f Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Tue, 29 Jul 2025 18:54:01 +0200 Subject: [PATCH 05/98] Fix: resolve pre-commit issues and add missing annotations Fix: resolve pre-commit issues and add missing annotations Fix: resolve pre-commit issues and add missing annotations Fix: resolve pre-commit issues and add missing annotations --- pyproject.toml | 4 ++-- src/mqt/predictor/rl/helper.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5c66b12d5..4297fbfd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ dependencies = [ "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler>=0.2.0", + "qiskit-ibm-transpiler[ai-local-mode]>=0.2.0" ] classifiers = [ @@ -164,7 +164,7 @@ implicit_reexport = true # recent versions of `gym` are typed, but stable-baselines3 pins a very old version of gym. # qiskit is not yet marked as typed, but is typed mostly. # the other libraries do not have type stubs. -module = ["qiskit.*", "joblib.*", "sklearn.*", "matplotlib.*", "gymnasium.*", "mqt.bench.*", "sb3_contrib.*", "bqskit.*", "qiskit_ibm_runtime.*", "networkx.*", "stable_baselines3.*"] +module = ["qiskit.*", "joblib.*", "sklearn.*", "matplotlib.*", "gymnasium.*", "mqt.bench.*", "sb3_contrib.*", "bqskit.*", "qiskit_ibm_runtime.*", "networkx.*", "stable_baselines3.*","qiskit_ibm_transpiler.*"] ignore_missing_imports = true [tool.ruff] diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 1ea9cf6a7..88351d673 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -17,10 +17,10 @@ import numpy as np from qiskit import QuantumCircuit from qiskit.converters import circuit_to_dag, dag_to_circuit -from qiskit.circuit import ClassicalRegister, QuantumRegister, Instruction +from qiskit.circuit import ClassicalRegister, QuantumRegister, Instruction, Qubit from qiskit.transpiler import PassManager, Target from qiskit.dagcircuit import DAGCircuit -from qiskit_ibm_transpiler.ai.routing import AIRouting +from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.utils import calc_supermarq_features from mqt.predictor.rl.actions import Action @@ -34,7 +34,7 @@ logger = logging.getLogger("mqt-predictor") -def extract_cregs_and_measurements(qc: QuantumCircuit) -> Tuple[List[ClassicalRegister], List[tuple[Instruction, List, List]]]: +def extract_cregs_and_measurements(qc: QuantumCircuit) -> Tuple[List[ClassicalRegister], List[tuple[Instruction, List[Any], List[Any]]]]: """ Extracts classical registers and measurement operations from a quantum circuit. @@ -78,8 +78,8 @@ def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: def add_cregs_and_measurements( qc: QuantumCircuit, cregs: List[ClassicalRegister], - measurements: List[Tuple[Instruction, List, List]], - qubit_map: Optional[Dict] = None, + measurements: List[Tuple[Instruction, List[Any], List[Any]]], + qubit_map: Optional[Dict[Qubit,Qubit]] = None, ) -> QuantumCircuit: """ Adds classical registers and measurement operations back to the quantum circuit. From f71fb29e59910af98db8cfbbecb62d9f4fda1d87 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Wed, 30 Jul 2025 18:39:40 +0200 Subject: [PATCH 06/98] Fix: resolve pre-commit issues and add missing annotations --- src/mqt/predictor/rl/helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 88351d673..4438c1964 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -178,7 +178,7 @@ def best_of_n_passmanager( best_result = None best_property_set = None - if action["name"] == "SabreLayout+AIRouting": + if action.name == "SabreLayout+AIRouting": all_passes = action.transpile_pass(device, max_iteration) else: all_passes = action.transpile_pass(device) From 3c7592b9bfe7762627b1fb31f8ddfc0c021bb2e5 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Wed, 30 Jul 2025 19:14:29 +0200 Subject: [PATCH 07/98] Fix: resolve pre-commit issues and add missing annotations --- src/mqt/predictor/rl/actions.py | 3 ++- src/mqt/predictor/rl/helper.py | 18 ++++++++++++++---- src/mqt/predictor/rl/predictorenv.py | 4 ++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index de7d98a98..d330576be 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -46,7 +46,7 @@ ) from qiskit.passmanager import ConditionalController from qiskit.transpiler import ( - CouplingMap, + CouplingMap, Target ) from qiskit.transpiler.passes import ( ApplyLayout, @@ -126,6 +126,7 @@ class Action: transpile_pass: ( list[qiskit_BasePass | tket_BasePass] | Callable[..., list[qiskit_BasePass | tket_BasePass]] + | Callable[[Target, tuple[int, int]], list[qiskit_BasePass | tket_BasePass]] | Callable[ ..., Callable[..., tuple[Any, ...] | Circuit], diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 4438c1964..1d7eb20ac 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -20,7 +20,6 @@ from qiskit.circuit import ClassicalRegister, QuantumRegister, Instruction, Qubit from qiskit.transpiler import PassManager, Target from qiskit.dagcircuit import DAGCircuit -from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.utils import calc_supermarq_features from mqt.predictor.rl.actions import Action @@ -28,6 +27,9 @@ if TYPE_CHECKING: from numpy.random import Generator from numpy.typing import NDArray + from qiskit_ibm_transpiler.ai.routing import AIRouting +else: + AIRouting = object # type: ignore[misc] import zipfile from importlib import resources @@ -103,7 +105,7 @@ def add_cregs_and_measurements( qc.append(instr, new_qargs, cargs) return qc -class SafeAIRouting(AIRouting): +class SafeAIRouting(AIRouting): # type: ignore[misc] """ Custom AIRouting wrapper that removes classical registers before routing. @@ -137,9 +139,15 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: qubit_map = {} for virt in qc_orig.qubits: - phys = final_layout[virt] + try: + phys = final_layout[virt] # This is now safe due to above check + except KeyError as err: + raise RuntimeError(f"Virtual qubit {virt} not found in final layout!") from err if isinstance(phys, int): - qubit_map[virt] = qc_routed.qubits[phys] + try: + qubit_map[virt] = qc_routed.qubits[phys] + except IndexError as err: + raise RuntimeError(f"Physical index {phys} is out of range in routed circuit!") from err else: try: idx = qc_routed.qubits.index(phys) @@ -183,6 +191,8 @@ def best_of_n_passmanager( else: all_passes = action.transpile_pass(device) + assert isinstance(all_passes, list) + layout_passes = all_passes[:-1] routing_pass = all_passes[-1:] diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 5b9a0c668..cd44a37ec 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -361,7 +361,7 @@ def metric_fn(circ: QuantumCircuit) -> float: return altered_qc def _handle_qiskit_layout_postprocessing( - self, action: Action, pm_property_set: dict, altered_qc: QuantumCircuit, + self, action: Action, pm_property_set: dict[str, any], altered_qc: QuantumCircuit, ) -> QuantumCircuit: if action.name == "VF2PostLayout": assert pm_property_set["VF2PostLayout_stop_reason"] is not None @@ -379,7 +379,7 @@ def _handle_qiskit_layout_postprocessing( _output_qubit_list=altered_qc.qubits, _input_qubit_count=self.num_qubits_uncompiled_circuit, ) - if pm_property_set["final_layout"]: + if self.layout is not None and pm_property_set["final_layout"]: self.layout.final_layout = pm_property_set["final_layout"] return altered_qc From 6db5c27b45c2febcaab67957e940d7d6b70bcc34 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Fri, 1 Aug 2025 19:42:43 +0200 Subject: [PATCH 08/98] Fix mypy errors --- pyproject.toml | 6 +- src/mqt/predictor/rl/actions.py | 523 +++++++++++++++++---------- src/mqt/predictor/rl/helper.py | 220 ++--------- src/mqt/predictor/rl/predictorenv.py | 82 +++-- 4 files changed, 419 insertions(+), 412 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4297fbfd2..825fcefb3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,8 @@ dependencies = [ "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler[ai-local-mode]>=0.2.0" + "qiskit-ibm-transpiler>=0.11.1", + "qiskit-ibm-ai-local-transpiler>=0.3.2" ] classifiers = [ @@ -248,3 +249,6 @@ fom = "fom" [tool.repo-review] ignore = ["GH200"] + +[tool.uv] +override-dependencies = ["networkx==2.8.5"] diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index d330576be..626921958 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -14,7 +14,7 @@ from collections import defaultdict from dataclasses import dataclass from enum import Enum -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from bqskit import MachineModel from bqskit import compile as bqskit_compile @@ -26,7 +26,8 @@ RemoveRedundancies, RoutingPass, ) -from qiskit.circuit import StandardEquivalenceLibrary +from qiskit import QuantumCircuit +from qiskit.circuit import ClassicalRegister, Instruction, QuantumRegister, Qubit, StandardEquivalenceLibrary from qiskit.circuit.library import ( CXGate, CYGate, @@ -44,14 +45,13 @@ YGate, ZGate, ) +from qiskit.converters import circuit_to_dag, dag_to_circuit from qiskit.passmanager import ConditionalController -from qiskit.transpiler import ( - CouplingMap, Target -) +from qiskit.transpiler import CouplingMap from qiskit.transpiler.passes import ( ApplyLayout, - BasisTranslator, BasicSwap, + BasisTranslator, Collect2qBlocks, CollectCliffords, CommutativeCancellation, @@ -78,20 +78,20 @@ ) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler.preset_passmanagers import common +from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.rl.parsing import ( PreProcessTKETRoutingAfterQiskitLayout, get_bqskit_native_gates, ) -from mqt.predictor.rl.helper import SafeAIRouting, get_openqasm_gates - if TYPE_CHECKING: from collections.abc import Callable from typing import Any from bqskit import Circuit from pytket._tket.passes import BasePass as tket_BasePass + from qiskit.dagcircuit import DAGCircuit from qiskit.transpiler.basepasses import BasePass as qiskit_BasePass @@ -126,13 +126,12 @@ class Action: transpile_pass: ( list[qiskit_BasePass | tket_BasePass] | Callable[..., list[qiskit_BasePass | tket_BasePass]] - | Callable[[Target, tuple[int, int]], list[qiskit_BasePass | tket_BasePass]] | Callable[ ..., Callable[..., tuple[Any, ...] | Circuit], ] ) - stochastic: bool = False + stochastic: bool | None = False @dataclass @@ -183,6 +182,51 @@ def remove_action(name: str) -> None: del _ACTIONS[name] +def get_openqasm_gates() -> list[str]: + """Returns a list of all quantum gates within the openQASM 2.0 standard header. + + According to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc + Removes generic single qubit gates u1, u2, u3 since they are no meaningful features for RL + + """ + return [ + "cx", + "id", + "u", + "p", + "x", + "y", + "z", + "h", + "r", + "s", + "sdg", + "t", + "tdg", + "rx", + "ry", + "rz", + "sx", + "sxdg", + "cz", + "cy", + "swap", + "ch", + "ccx", + "cswap", + "crx", + "cry", + "crz", + "cu1", + "cp", + "csx", + "cu", + "rxx", + "rzz", + "rccx", + ] + + register_action( DeviceIndependentAction( "Optimize1qGatesDecomposition", @@ -257,9 +301,11 @@ def remove_action(name: str) -> None: "Opt2qBlocks", CompilationOrigin.QISKIT, PassType.OPT, - transpile_pass=lambda device: [Collect2qBlocks(), - ConsolidateBlocks(basis_gates=device.operation_names), - UnitarySynthesis(basis_gates=device.operation_names, coupling_map=device.build_coupling_map())], + transpile_pass=lambda native_gate, coupling_map: [ + Collect2qBlocks(), + ConsolidateBlocks(basis_gates=native_gate), + UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), + ], ) ) @@ -405,16 +451,16 @@ def remove_action(name: str) -> None: PassType.MAPPING, stochastic=True, # Qiskit O3 by default uses (max_iterations, layout_trials, swap_trials) = (4, 20, 20) - transpile_pass=lambda device, max_iteration=(20,20): [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=False, - layout_trials=max_iteration[0], - swap_trials=max_iteration[1], - max_iterations=4, - seed=None - ), - ], + transpile_pass=lambda device, max_iteration=(20, 20): [ + SabreLayout( + coupling_map=CouplingMap(device.build_coupling_map()), + skip_routing=False, + layout_trials=max_iteration[0], + swap_trials=max_iteration[1], + max_iterations=4, + seed=None, + ), + ], ) ) @@ -424,20 +470,20 @@ def remove_action(name: str) -> None: CompilationOrigin.QISKIT, PassType.MAPPING, stochastic=True, - transpile_pass=lambda device, max_iteration=(20,20): [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=True, - layout_trials=max_iteration[0], - swap_trials=max_iteration[1], - max_iterations=4, - seed=None - ), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), - ], + transpile_pass=lambda device, max_iteration=(20, 20): [ + SabreLayout( + coupling_map=CouplingMap(device.build_coupling_map()), + skip_routing=True, + layout_trials=max_iteration[0], + swap_trials=max_iteration[1], + max_iterations=4, + seed=None, + ), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), + ], ) ) @@ -447,25 +493,20 @@ def remove_action(name: str) -> None: CompilationOrigin.QISKIT, PassType.MAPPING, stochastic=True, - transpile_pass=lambda device, max_iteration=(20,20): [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=True, - layout_trials=max_iteration[0], - swap_trials=max_iteration[1], - max_iterations=4, - seed=None - ), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting( - coupling_map=device.build_coupling_map(), - optimization_level=3, - layout_mode="optimize", - local_mode=True - ), - ], + transpile_pass=lambda device, max_iteration=(20, 20): [ + SabreLayout( + coupling_map=CouplingMap(device.build_coupling_map()), + skip_routing=True, + layout_trials=max_iteration[0], + swap_trials=max_iteration[1], + max_iterations=4, + seed=None, + ), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), + ], ) ) @@ -495,14 +536,14 @@ def remove_action(name: str) -> None: DeviceDependentAction( name="DenseLayout+BasicSwap", origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, + pass_type=PassType.MAPPING, transpile_pass=lambda device: [ - DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), - ], + DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), + ], ) ) @@ -511,14 +552,19 @@ def remove_action(name: str) -> None: name="DenseLayout+SabreSwap", origin=CompilationOrigin.QISKIT, pass_type=PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device, max_iteration=(20,20): [ - DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SabreSwap(coupling_map=CouplingMap(device.build_coupling_map()), heuristic="decay", trials=max_iteration[1], seed=None), - ], + stochastic=True, + transpile_pass=lambda device, max_iteration=(20, 20): [ + DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SabreSwap( + coupling_map=CouplingMap(device.build_coupling_map()), + heuristic="decay", + trials=max_iteration[1], + seed=None, + ), + ], ) ) @@ -526,20 +572,15 @@ def remove_action(name: str) -> None: DeviceDependentAction( name="DenseLayout+AIRouting", origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, + pass_type=PassType.MAPPING, stochastic=True, transpile_pass=lambda device: [ - DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting( - coupling_map=device.build_coupling_map(), - optimization_level=3, - layout_mode="optimize", - local_mode=True - ), - ], + DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), + ], ) ) @@ -547,33 +588,34 @@ def remove_action(name: str) -> None: DeviceDependentAction( name="VF2Layout+BasicSwap", origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, + pass_type=PassType.MAPPING, transpile_pass=lambda device: [ - VF2Layout( - coupling_map=CouplingMap(device.build_coupling_map()), - target=device, - ), - ConditionalController( - [ - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - == VF2LayoutStopReason.SOLUTION_FOUND, - ), - ConditionalController( - [ - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - # Run if VF2Layout did not find a solution - condition=lambda property_set: property_set["VF2Layout_stop_reason"] != VF2LayoutStopReason.SOLUTION_FOUND, - ), - BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), - ], + VF2Layout( + coupling_map=CouplingMap(device.build_coupling_map()), + target=device, + ), + ConditionalController( + [ + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + == VF2LayoutStopReason.SOLUTION_FOUND, + ), + ConditionalController( + [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + # Run if VF2Layout did not find a solution + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + != VF2LayoutStopReason.SOLUTION_FOUND, + ), + BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), + ], ) ) @@ -581,34 +623,40 @@ def remove_action(name: str) -> None: DeviceDependentAction( name="VF2Layout+SabreSwap", origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, + pass_type=PassType.MAPPING, stochastic=True, - transpile_pass=lambda device, max_iteration=(20,20): [ - VF2Layout( - coupling_map=CouplingMap(device.build_coupling_map()), - target=device, - ), - ConditionalController( - [ - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - == VF2LayoutStopReason.SOLUTION_FOUND, - ), - ConditionalController( - [ - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - # Run if VF2Layout did not find a solution - condition=lambda property_set: property_set["VF2Layout_stop_reason"] != VF2LayoutStopReason.SOLUTION_FOUND, - ), - SabreSwap(coupling_map=CouplingMap(device.build_coupling_map()), heuristic="decay", trials=max_iteration[1], seed=None), - ], + transpile_pass=lambda device, max_iteration=(20, 20): [ + VF2Layout( + coupling_map=CouplingMap(device.build_coupling_map()), + target=device, + ), + ConditionalController( + [ + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + == VF2LayoutStopReason.SOLUTION_FOUND, + ), + ConditionalController( + [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + # Run if VF2Layout did not find a solution + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + != VF2LayoutStopReason.SOLUTION_FOUND, + ), + SabreSwap( + coupling_map=CouplingMap(device.build_coupling_map()), + heuristic="decay", + trials=max_iteration[1], + seed=None, + ), + ], ) ) @@ -616,65 +664,34 @@ def remove_action(name: str) -> None: DeviceDependentAction( name="VF2Layout+AIRouting", origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device:[ - VF2Layout( - coupling_map=CouplingMap(device.build_coupling_map()), - target=device, - ), - ConditionalController( - [ - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - == VF2LayoutStopReason.SOLUTION_FOUND, - ), - ConditionalController( - [ - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - # Run if VF2Layout did not find a solution - condition=lambda property_set: property_set["VF2Layout_stop_reason"] != VF2LayoutStopReason.SOLUTION_FOUND, - ), - SafeAIRouting( - coupling_map=device.build_coupling_map(), - optimization_level=3, - layout_mode="optimize", - local_mode=True - ), - ], - ) -) - -register_action( - DeviceDependentAction( - name="SabreLayout+AIRouting", - origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, stochastic=True, - pass_type=PassType.MAPPING, - transpile_pass=lambda device, max_iteration=(20, 20): [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=True, - layout_trials=max_iteration[0], - swap_trials=1, - max_iterations=4, + transpile_pass=lambda device: [ + VF2Layout( + coupling_map=CouplingMap(device.build_coupling_map()), + target=device, ), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting( - coupling_map=device.build_coupling_map(), - optimization_level=3, - layout_mode="optimize", - local_mode=True, + ConditionalController( + [ + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + == VF2LayoutStopReason.SOLUTION_FOUND, ), + ConditionalController( + [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], + # Run if VF2Layout did not find a solution + condition=lambda property_set: property_set["VF2Layout_stop_reason"] + != VF2LayoutStopReason.SOLUTION_FOUND, + ), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), ], ) ) @@ -723,3 +740,125 @@ def get_actions_by_pass_type() -> dict[PassType, list[Action]]: for action in _ACTIONS.values(): result[action.pass_type].append(action) return result + + +def extract_cregs_and_measurements( + qc: QuantumCircuit, +) -> tuple[list[ClassicalRegister], list[tuple[Instruction, list[Any], list[Any]]]]: + """Extracts classical registers and measurement operations from a quantum circuit. + + Args: + qc: The input QuantumCircuit. + + Returns: + A tuple containing a list of classical registers and a list of measurement operations. + """ + cregs = [ClassicalRegister(cr.size, name=cr.name) for cr in qc.cregs] + measurements = [(item.operation, item.qubits, item.clbits) for item in qc.data if item.operation.name == "measure"] + return cregs, measurements + + +def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: + """Removes classical registers and measurement operations from the circuit. + + Args: + qc: The input QuantumCircuit. + + Returns: + A new QuantumCircuit with only quantum operations (no cregs or measurements). + """ + qregs = [QuantumRegister(qr.size, name=qr.name) for qr in qc.qregs] + new_qc = QuantumCircuit(*qregs) + old_to_new = {} + for orig_qr, new_qr in zip(qc.qregs, new_qc.qregs, strict=False): + for idx in range(orig_qr.size): + old_to_new[orig_qr[idx]] = new_qr[idx] + for item in qc.data: + instr = item.operation + qargs = [old_to_new[q] for q in item.qubits] + if instr.name not in ("measure", "barrier"): + new_qc.append(instr, qargs) + return new_qc + + +def add_cregs_and_measurements( + qc: QuantumCircuit, + cregs: list[ClassicalRegister], + measurements: list[tuple[Instruction, list[Any], list[Any]]], + qubit_map: dict[Qubit, Qubit] | None = None, +) -> QuantumCircuit: + """Adds classical registers and measurement operations back to the quantum circuit. + + Args: + qc: The quantum circuit to which cregs and measurements are added. + cregs: List of ClassicalRegister to add. + measurements: List of measurement instructions as tuples (Instruction, qubits, clbits). + qubit_map: Optional dictionary mapping original qubits to new qubits. + + Returns: + The modified QuantumCircuit with cregs and measurements added. + """ + for cr in cregs: + qc.add_register(cr) + for instr, qargs, cargs in measurements: + new_qargs = [qubit_map[q] for q in qargs] if qubit_map else qargs + qc.append(instr, new_qargs, cargs) + return qc + + +class SafeAIRouting(AIRouting): # type: ignore[misc] + """Custom AIRouting wrapper that removes classical registers before routing. + + This prevents failures in AIRouting when classical bits are present by + temporarily removing classical registers and measurements and restoring + them after routing is completed. + """ + + def run(self, dag: DAGCircuit) -> DAGCircuit: + """Run the routing pass on a DAGCircuit.""" + # 1. Convert input dag to circuit + qc_orig = dag_to_circuit(dag) + + # 2. Extract classical registers and measurement instructions + cregs, measurements = extract_cregs_and_measurements(qc_orig) + + # 3. Remove cregs and measurements + qc_noclassical = remove_cregs(qc_orig) + + # 4. Convert back to dag and run routing (AIRouting) + dag_noclassical = circuit_to_dag(qc_noclassical) + dag_routed = super().run(dag_noclassical) + + # 5. Convert routed dag to circuit for restoration + qc_routed = dag_to_circuit(dag_routed) + + # 6. Build mapping from original qubits to qubits in routed circuit + final_layout = getattr(self, "property_set", {}).get("final_layout", None) + if final_layout is None and hasattr(dag_routed, "property_set"): + final_layout = dag_routed.property_set.get("final_layout", None) + + assert final_layout is not None, "final_layout is None — cannot map virtual qubits" + qubit_map = {} + for virt in qc_orig.qubits: + try: + phys = final_layout[virt] + except KeyError as err: + msg = f"Virtual qubit {virt} not found in final layout!" + raise RuntimeError(msg) from err + if isinstance(phys, int): + try: + qubit_map[virt] = qc_routed.qubits[phys] + except IndexError as err: + msg = f"Physical index {phys} is out of range in routed circuit!" + raise RuntimeError(msg) from err + else: + try: + idx = qc_routed.qubits.index(phys) + except ValueError as err: + msg = f"Physical qubit {phys} not found in output circuit!" + raise RuntimeError(msg) from err + qubit_map[virt] = qc_routed.qubits[idx] + # 7. Restore classical registers and measurement instructions + qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) + # 8. Return as dag + return circuit_to_dag(qc_final) diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 1d7eb20ac..558ba262f 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -12,162 +12,38 @@ import logging from pathlib import Path -from typing import TYPE_CHECKING, Optional, Callable, List, Tuple, Dict, Any +from typing import TYPE_CHECKING, Any import numpy as np from qiskit import QuantumCircuit -from qiskit.converters import circuit_to_dag, dag_to_circuit -from qiskit.circuit import ClassicalRegister, QuantumRegister, Instruction, Qubit from qiskit.transpiler import PassManager, Target -from qiskit.dagcircuit import DAGCircuit from mqt.predictor.utils import calc_supermarq_features -from mqt.predictor.rl.actions import Action if TYPE_CHECKING: + from collections.abc import Callable + from numpy.random import Generator from numpy.typing import NDArray - from qiskit_ibm_transpiler.ai.routing import AIRouting -else: - AIRouting = object # type: ignore[misc] + + from mqt.predictor.rl.actions import Action + + # from mqt.predictor.rl.actions import Action import zipfile from importlib import resources logger = logging.getLogger("mqt-predictor") -def extract_cregs_and_measurements(qc: QuantumCircuit) -> Tuple[List[ClassicalRegister], List[tuple[Instruction, List[Any], List[Any]]]]: - """ - Extracts classical registers and measurement operations from a quantum circuit. - - Args: - qc: The input QuantumCircuit. - - Returns: - A tuple containing a list of classical registers and a list of measurement operations. - """ - cregs = [ClassicalRegister(cr.size, name=cr.name) for cr in qc.cregs] - measurements = [ - (item.operation, item.qubits, item.clbits) - for item in qc.data - if item.operation.name == "measure" - ] - return cregs, measurements - -def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: - """ - Removes classical registers and measurement operations from the circuit. - - Args: - qc: The input QuantumCircuit. - - Returns: - A new QuantumCircuit with only quantum operations (no cregs or measurements). - """ - qregs = [QuantumRegister(qr.size, name=qr.name) for qr in qc.qregs] - new_qc = QuantumCircuit(*qregs) - old_to_new = {} - for orig_qr, new_qr in zip(qc.qregs, new_qc.qregs): - for idx in range(orig_qr.size): - old_to_new[orig_qr[idx]] = new_qr[idx] - for item in qc.data: - instr = item.operation - qargs = [old_to_new[q] for q in item.qubits] - if instr.name not in ("measure", "barrier"): - new_qc.append(instr, qargs) - return new_qc - -def add_cregs_and_measurements( - qc: QuantumCircuit, - cregs: List[ClassicalRegister], - measurements: List[Tuple[Instruction, List[Any], List[Any]]], - qubit_map: Optional[Dict[Qubit,Qubit]] = None, -) -> QuantumCircuit: - """ - Adds classical registers and measurement operations back to the quantum circuit. - - Args: - qc: The quantum circuit to which cregs and measurements are added. - cregs: List of ClassicalRegister to add. - measurements: List of measurement instructions as tuples (Instruction, qubits, clbits). - qubit_map: Optional dictionary mapping original qubits to new qubits. - - Returns: - The modified QuantumCircuit with cregs and measurements added. - """ - for cr in cregs: - qc.add_register(cr) - for instr, qargs, cargs in measurements: - if qubit_map: - new_qargs = [qubit_map[q] for q in qargs] - else: - new_qargs = qargs - qc.append(instr, new_qargs, cargs) - return qc - -class SafeAIRouting(AIRouting): # type: ignore[misc] - """ - Custom AIRouting wrapper that removes classical registers before routing. - - This prevents failures in AIRouting when classical bits are present by - temporarily removing classical registers and measurements and restoring - them after routing is completed. - """ - def run(self, dag: DAGCircuit) -> DAGCircuit: - """Run the routing pass on a DAGCircuit.""" - - # 1. Convert input dag to circuit - qc_orig = dag_to_circuit(dag) - - # 2. Extract classical registers and measurement instructions - cregs, measurements = extract_cregs_and_measurements(qc_orig) - - # 3. Remove cregs and measurements - qc_noclassical = remove_cregs(qc_orig) - - # 4. Convert back to dag and run routing (AIRouting) - dag_noclassical = circuit_to_dag(qc_noclassical) - dag_routed = super().run(dag_noclassical) - - # 5. Convert routed dag to circuit for restoration - qc_routed = dag_to_circuit(dag_routed) - - # 6. Build mapping from original qubits to qubits in routed circuit - final_layout = getattr(self, "property_set", {}).get("final_layout", None) - if final_layout is None and hasattr(dag_routed, "property_set"): - final_layout = dag_routed.property_set.get("final_layout", None) - - qubit_map = {} - for virt in qc_orig.qubits: - try: - phys = final_layout[virt] # This is now safe due to above check - except KeyError as err: - raise RuntimeError(f"Virtual qubit {virt} not found in final layout!") from err - if isinstance(phys, int): - try: - qubit_map[virt] = qc_routed.qubits[phys] - except IndexError as err: - raise RuntimeError(f"Physical index {phys} is out of range in routed circuit!") from err - else: - try: - idx = qc_routed.qubits.index(phys) - except ValueError as err: - raise RuntimeError(f"Physical qubit {phys} not found in output circuit!") from err - qubit_map[virt] = qc_routed.qubits[idx] - # 7. Restore classical registers and measurement instructions - qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) - # 8. Return as dag - return circuit_to_dag(qc_final) def best_of_n_passmanager( action: Action, device: Target, qc: QuantumCircuit, - max_iteration: Tuple[int, int] = (20, 20), - metric_fn: Optional[Callable[[QuantumCircuit], float]] = None, -)-> tuple[QuantumCircuit, Dict[str, Any]]: - """ - Runs the given transpile_pass multiple times and keeps the best result. + max_iteration: tuple[int, int] = (20, 20), + metric_fn: Callable[[QuantumCircuit], float] | None = None, +) -> tuple[QuantumCircuit, dict[str, Any]]: + """Runs the given transpile_pass multiple times and keeps the best result. Args: action: The action dictionary with a 'transpile_pass' key @@ -186,12 +62,21 @@ def best_of_n_passmanager( best_result = None best_property_set = None - if action.name == "SabreLayout+AIRouting": - all_passes = action.transpile_pass(device, max_iteration) + if callable(action.transpile_pass): + try: + if action.name == "SabreLayout+AIRouting": + all_passes = action.transpile_pass(device, max_iteration) + else: + all_passes = action.transpile_pass(device) + except TypeError as e: + msg = f"Error calling transpile_pass for {action.name}: {e}" + raise ValueError(msg) from e else: - all_passes = action.transpile_pass(device) + all_passes = action.transpile_pass - assert isinstance(all_passes, list) + if not isinstance(all_passes, list): + msg = f"Expected list of passes, got {type(all_passes)}" + raise TypeError(msg) layout_passes = all_passes[:-1] routing_pass = all_passes[-1:] @@ -201,7 +86,7 @@ def best_of_n_passmanager( try: layouted_qc = layout_pm.run(qc) layout_props = dict(layout_pm.property_set) - except Exception as e: + except Exception: return qc, {} # Run routing multiple times and optimize for the given metric @@ -220,14 +105,16 @@ def best_of_n_passmanager( if best_val == 0: break except Exception as e: - print(f"[Routing] Trial {i+1} failed: {e}") + print(f"[Routing] Trial {i + 1} failed: {e}") continue if best_result is not None: + if best_property_set is None: + best_property_set = {} return best_result, best_property_set - else: - print("All mapping attempts failed; returning original circuit.") - return qc, {} - + print("All mapping attempts failed; returning original circuit.") + return qc, {} + + def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generator) -> tuple[QuantumCircuit, str]: """Returns a random quantum circuit from the training circuits folder. @@ -267,49 +154,6 @@ def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generat return qc, str(file_list[random_index]) -def get_openqasm_gates() -> list[str]: - """ Returns a list of all quantum gates within the openQASM 2.0 standard header. - - According to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc - Removes generic single qubit gates u1, u2, u3 since they are no meaningful features for RL - - """ - return [ - "cx", - "id", - "u", - "p", - "x", - "y", - "z", - "h", - "r", - "s", - "sdg", - "t", - "tdg", - "rx", - "ry", - "rz", - "sx", - "sxdg", - "cz", - "cy", - "swap", - "ch", - "ccx", - "cswap", - "crx", - "cry", - "crz", - "cu1", - "cp", - "csx", - "cu", - "rxx", - "rzz", - "rccx", - ] def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float64]]: """Creates a feature dictionary for a given quantum circuit. diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index cd44a37ec..b152f2c47 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -39,11 +39,9 @@ from pytket.circuit import Qubit from pytket.extensions.qiskit import qiskit_to_tk, tk_to_qiskit from qiskit import QuantumCircuit, transpile -from qiskit.circuit.library import RCCXGate from qiskit.passmanager.flow_controllers import DoWhileController from qiskit.transpiler import CouplingMap, PassManager, Target, TranspileLayout from qiskit.transpiler.passes import CheckMap, GatesInBasis -from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from mqt.predictor.hellinger import get_hellinger_model_path from mqt.predictor.reward import ( @@ -54,8 +52,19 @@ expected_fidelity, figure_of_merit, ) -from mqt.predictor.rl.actions import CompilationOrigin, DeviceDependentAction, PassType, get_actions_by_pass_type -from mqt.predictor.rl.helper import create_feature_dict, get_path_training_circuits, get_state_sample, get_openqasm_gates, best_of_n_passmanager +from mqt.predictor.rl.actions import ( + CompilationOrigin, + DeviceDependentAction, + PassType, + get_actions_by_pass_type, + get_openqasm_gates, +) +from mqt.predictor.rl.helper import ( + best_of_n_passmanager, + create_feature_dict, + get_path_training_circuits, + get_state_sample, +) from mqt.predictor.rl.parsing import ( final_layout_bqskit_to_qiskit, final_layout_pytket_to_qiskit, @@ -90,6 +99,8 @@ def __init__( self.action_set = {} self.actions_synthesis_indices = [] + self.actions_layout_indices = [] + self.actions_routing_indices = [] self.actions_mapping_indices = [] self.actions_opt_indices = [] self.actions_final_optimization_indices = [] @@ -113,6 +124,14 @@ def __init__( self.action_set[index] = elem self.actions_opt_indices.append(index) index += 1 + for elem in action_dict[PassType.LAYOUT]: + self.action_set[index] = elem + self.actions_layout_indices.append(index) + index += 1 + for elem in action_dict[PassType.ROUTING]: + self.action_set[index] = elem + self.actions_routing_indices.append(index) + index += 1 for elem in action_dict[PassType.MAPPING]: self.action_set[index] = elem self.actions_mapping_indices.append(index) @@ -154,7 +173,7 @@ def __init__( } self.observation_space = Dict(spaces) self.filename = "" - self.max_iter = (20,20) # (layout_trials, routing _trials) + self.max_iter = (20, 20) # (layout_trials, routing _trials) def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any, Any]]: """Executes the given action and returns the new state, the reward, whether the episode is done, whether the episode is truncated and additional information. @@ -317,12 +336,15 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: if getattr(action, "stochastic", False): + def metric_fn(circ: QuantumCircuit) -> float: return float(circ.count_ops().get("swap", 0)) + # for stochastic actions, pass the layout/routing trials parameter max_iteration = self.max_iter if "Sabre" in action.name and "AIRouting" not in action.name: # Internal trials for Sabre + assert callable(action.transpile_pass) transpile_pass = action.transpile_pass(self.device, max_iteration) pm = PassManager(transpile_pass) altered_qc = pm.run(self.state) @@ -330,19 +352,22 @@ def metric_fn(circ: QuantumCircuit) -> float: elif "AIRouting" in action.name: # Run AIRouting in custom loop altered_qc, pm_property_set = best_of_n_passmanager( - action, + action, self.device, - self.state, + self.state, max_iteration=max_iteration, metric_fn=metric_fn, ) else: - if action.name == "QiskitO3" and isinstance(action, DeviceDependentAction): + if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): passes = action.transpile_pass( self.device.operation_names, CouplingMap(self.device.build_coupling_map()) if self.layout else None, ) - pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) + if action.name == "QiskitO3": + pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) + else: + pm = PassManager(passes) altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} else: @@ -352,16 +377,17 @@ def metric_fn(circ: QuantumCircuit) -> float: pm = PassManager(transpile_pass) altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} - if action_index in ( - self.actions_mapping_indices + self.actions_final_optimization_indices - ): + if action_index in (self.actions_mapping_indices + self.actions_final_optimization_indices): pm_property_set = dict(pm.property_set) altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) - + return altered_qc - + def _handle_qiskit_layout_postprocessing( - self, action: Action, pm_property_set: dict[str, any], altered_qc: QuantumCircuit, + self, + action: Action, + pm_property_set: dict[str, Any], + altered_qc: QuantumCircuit, ) -> QuantumCircuit: if action.name == "VF2PostLayout": assert pm_property_set["VF2PostLayout_stop_reason"] is not None @@ -384,9 +410,6 @@ def _handle_qiskit_layout_postprocessing( return altered_qc def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircuit: - if any(isinstance(gate[0], RCCXGate) for gate in self.state.data): - # RCCX could cause error - self.state = transpile(self.state, basis_gates=get_openqasm_gates()[:-1], optimization_level=0) tket_qc = qiskit_to_tk(self.state, preserve_param_uuid=True) transpile_pass = ( action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass @@ -397,14 +420,13 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui qbs = tket_qc.qubits tket_qc.rename_units({qbs[i]: Qubit("q", i) for i in range(len(qbs))}) - altered_qc = tk_to_qiskit(tket_qc) + altered_qc = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) if action_index in self.actions_routing_indices: assert self.layout is not None self.layout.final_layout = final_layout_pytket_to_qiskit(tket_qc, altered_qc) # Decompose to the allowed gates (by default generic u gates are used) - altered_qc = transpile(altered_qc, basis_gates=get_openqasm_gates(), optimization_level=0) - return altered_qc + return transpile(altered_qc, basis_gates=get_openqasm_gates(), optimization_level=0) def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCircuit: """Applies the given BQSKit action to the current state and returns the altered state. @@ -444,22 +466,20 @@ def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCirc def determine_valid_actions_for_state(self) -> list[int]: """Determines and returns the valid actions for the current state.""" - check_nat_gates = GatesInBasis(basis_gates=self.device.basis_gates) + check_nat_gates = GatesInBasis(target=self.device) check_nat_gates(self.state) only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] - check_mapping = CheckMap(coupling_map=CouplingMap(self.device.coupling_map)) + check_mapping = CheckMap(coupling_map=CouplingMap(self.device.build_coupling_map())) check_mapping(self.state) mapped = check_mapping.property_set["is_swap_mapped"] - if not only_nat_gates: # not native gates yet - actions = self.actions_synthesis_indices + self.actions_opt_indices - return actions + if not only_nat_gates: # not native gates yet + return self.actions_synthesis_indices + self.actions_opt_indices if mapped and self.layout is not None: # The circuit is correctly mapped. return [self.action_terminate_index, *self.actions_opt_indices, *self.actions_final_optimization_indices] - else: - # The circuit is not mapped yet - # Or the circuit was mapped but some optimization actions change its structure and the circuit is again unmapped - # In this case, re-do mapping completely as the previous layout is not optimal on the new structure - return self.actions_mapping_indices + self.actions_opt_indices \ No newline at end of file + # The circuit is not mapped yet + # Or the circuit was mapped but some optimization actions change its structure and the circuit is again unmapped + # In this case, re-do mapping completely as the previous layout is not optimal on the new structure + return self.actions_mapping_indices + self.actions_opt_indices From 47841c5824e1f89304f54bd1379e72e2d8a7f6a2 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Fri, 1 Aug 2025 19:46:36 +0200 Subject: [PATCH 09/98] Fix mypy errors --- uv.lock | 205 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 128 insertions(+), 77 deletions(-) diff --git a/uv.lock b/uv.lock index 64725fb60..215a0a69d 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.13'", @@ -11,6 +11,9 @@ resolution-markers = [ "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", ] +[manifest] +overrides = [{ name = "networkx", specifier = "==2.8.5" }] + [[package]] name = "absl-py" version = "2.3.1" @@ -107,6 +110,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] +[[package]] +name = "backoff" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001, upload-time = "2022-10-05T19:19:32.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148, upload-time = "2022-10-05T19:19:30.546Z" }, +] + [[package]] name = "beautifulsoup4" version = "4.13.4" @@ -1492,8 +1504,7 @@ name = "mqt-bench" version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "networkx" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, { name = "qiskit", extra = ["qasm3-import"] }, @@ -1515,6 +1526,9 @@ dependencies = [ { name = "pytket" }, { name = "pytket-qiskit" }, { name = "qiskit" }, + { name = "qiskit-ibm-ai-local-transpiler" }, + { name = "qiskit-ibm-transpiler" }, + { name = "rich" }, { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "scikit-learn" }, @@ -1570,6 +1584,9 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.60.0" }, { name = "qiskit", specifier = "!=1.3.2" }, + { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.3.2" }, + { name = "qiskit-ibm-transpiler", specifier = ">=0.11.1" }, + { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "tensorboard", specifier = ">=2.17.0" }, @@ -1696,31 +1713,11 @@ wheels = [ [[package]] name = "networkx" -version = "3.4.2" +version = "2.8.5" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", -] -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/af/fe794d69bcc4882c4905b49c8b207b8dc4dd7ea26e6142781eac8203ea05/networkx-2.8.5.tar.gz", hash = "sha256:15a7b81a360791c458c55a417418ea136c13378cfdc06a2dcdc12bd2f9cf09c1", size = 1955125, upload-time = "2022-07-18T21:25:02.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, -] - -[[package]] -name = "networkx" -version = "3.5" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13'", - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", -] -sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, + { url = "https://files.pythonhosted.org/packages/95/1b/14b5b17c52f7329b875e4ad2dcad23c808778b42ef6d250a7223d4dc378a/networkx-2.8.5-py3-none-any.whl", hash = "sha256:a762f4b385692d9c3a6f2912d058d76d29a827deaedf9e63ed14d397b8030687", size = 2020253, upload-time = "2022-07-18T21:24:59.008Z" }, ] [[package]] @@ -2493,8 +2490,7 @@ dependencies = [ { name = "graphviz" }, { name = "jinja2" }, { name = "lark" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "networkx" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, { name = "qwasm" }, @@ -2523,7 +2519,7 @@ wheels = [ [[package]] name = "pytket-qiskit" -version = "0.71.0" +version = "0.66.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, @@ -2532,10 +2528,9 @@ dependencies = [ { name = "qiskit" }, { name = "qiskit-aer" }, { name = "qiskit-ibm-runtime" }, - { name = "symengine" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/31/7150385fe20c9d946d73a2251f50630ddf7e612e99f8427d06cb91932e20/pytket_qiskit-0.71.0-py3-none-any.whl", hash = "sha256:4e64f44fdc1cbd4c1f94d4f9de59c7b393ff1cda639c06de5cad01c770fc3000", size = 57187, upload-time = "2025-07-21T09:27:09.443Z" }, + { url = "https://files.pythonhosted.org/packages/73/4d/6395c0a6a2e6f08f493b031887aadc2b276d12b21c3b9b6f30036a43b498/pytket_qiskit-0.66.0-py3-none-any.whl", hash = "sha256:15d72ae6190e2280356e64bf387ca2d2d51714c395739b364fe3bbf9bd4bd096", size = 56193, upload-time = "2025-03-26T15:18:24.58Z" }, ] [[package]] @@ -2675,7 +2670,7 @@ wheels = [ [[package]] name = "qiskit" -version = "2.1.1" +version = "1.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, @@ -2686,17 +2681,21 @@ dependencies = [ { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "scipy", version = "1.16.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "stevedore" }, + { name = "symengine" }, + { name = "sympy" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/97/903041c27db9105f5036a579b2b7ee2a0caa21c6061fa29e0ccbd35aa19a/qiskit-2.1.1.tar.gz", hash = "sha256:148f62d314cd138a1f4da305c6293b19c73115323e77123b13a048cdcbc1fcdd", size = 3600302, upload-time = "2025-07-10T21:30:11.665Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/ac/25993f01e39cf04c9dccfd83f9b0817b5b8b1766f4afb8c34e6fba85155f/qiskit-1.4.3.tar.gz", hash = "sha256:e4e311190c159578f253d219dc860241ccb71955ca08725bb092c74cf7fbdac5", size = 3939859, upload-time = "2025-05-12T15:28:05.09Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/3a/26a99184f830be25a14ef7cbc40f19b98721ac018aa0c4db18c5dedc774c/qiskit-2.1.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:00f8fe1980a80e8e79e01352f2502cd3ca4fe89d07872bc9a244ba9cba304a7d", size = 7283884, upload-time = "2025-07-10T21:30:02.576Z" }, - { url = "https://files.pythonhosted.org/packages/60/a1/2a63ab52a5166346599df7bec2e41fd2be9876ccf01637c73603beebdcb5/qiskit-2.1.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e00985d1b348bf8cc60b686a64a150af2043538e81a61b48400ff71064588fdd", size = 6817779, upload-time = "2025-07-10T21:30:04.513Z" }, - { url = "https://files.pythonhosted.org/packages/ba/87/1a184f6dcd614f57362d9b0be1c718ff857c1a3d69ca0f426c84adda6755/qiskit-2.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:10f546148c86fd15cdbc68270e1d3937a021bd718779dff95f912c8b7cfad7bd", size = 7437467, upload-time = "2025-07-10T21:30:06.524Z" }, - { url = "https://files.pythonhosted.org/packages/82/d7/d0fc92d20b266692db8aedc5e259a2d4cff76613ec155178f855144c7a71/qiskit-2.1.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3765cef67ccc8b3d54b86ede2266c282039da045be1b10e64660a4bbf815680", size = 7696275, upload-time = "2025-07-11T13:15:14.672Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/ba384695bc9c9cb5795ef3ab47f33eb579460dc928115918d4eb0046ae9f/qiskit-2.1.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca95a1ab710eb3e0fc65dd876734b5c6fc6df1bb78249f86913d77ed1984983f", size = 7411176, upload-time = "2025-07-11T13:15:16.62Z" }, - { url = "https://files.pythonhosted.org/packages/75/dc/551c6afe0aa087ebe53988173290904ded5bf93e56b22503d8311d421d82/qiskit-2.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b41c66958c2e0550bc1047524cd754dce2277bea0a1db1085c052cc5bb07ec6", size = 7458353, upload-time = "2025-07-10T21:30:08.223Z" }, - { url = "https://files.pythonhosted.org/packages/83/6c/988791f56e6ab2999e1a4c7e60831b0f02c3e29a467400bced501ce6b637/qiskit-2.1.1-cp39-abi3-win_amd64.whl", hash = "sha256:e7225798221ecf0c8a5cf2e96c37d6d9d00674a412e8c397542fe387909b80db", size = 7234838, upload-time = "2025-07-10T21:30:10.121Z" }, + { url = "https://files.pythonhosted.org/packages/66/d5/126a6ddc7a9138b436cfee3772c5b082ea8f8216feed729f02c5bda32d66/qiskit-1.4.3-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:65caf291bbe93f136b85281cb4a807c138fc4315fc17bdda9382cb4bfa18abdf", size = 6570998, upload-time = "2025-05-12T15:27:51.659Z" }, + { url = "https://files.pythonhosted.org/packages/67/95/c4bf1fe91c456570c9536e5505ccd878f358f4b8e6b06c8fd8cbc09093a0/qiskit-1.4.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:6e9f41eca2f4d522f59e48a47eb8b81ed3fdd35f56cefb41cc0db47768ccde47", size = 6251292, upload-time = "2025-05-12T15:27:53.929Z" }, + { url = "https://files.pythonhosted.org/packages/23/70/713fae76998831e9cb458e3605a9429915b9f9fbb92244c8699903868be2/qiskit-1.4.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a04c6baca379bae8e6fc626bd06f0dda3f2ee7961205839b5a431b7f8d1e3978", size = 6396599, upload-time = "2025-05-12T18:02:22.029Z" }, + { url = "https://files.pythonhosted.org/packages/d6/93/6cadc22a5184e4e868c28dd6a83beacf6e4641088f106e3cd97e0cd160a8/qiskit-1.4.3-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ca6eeaf29ae2cf3789e7474b062845c59c6e4164276569949f9170cfcaec6b1", size = 6730964, upload-time = "2025-05-12T15:27:55.962Z" }, + { url = "https://files.pythonhosted.org/packages/ef/9c/53a7fd3a18ec3526e56fa68d9af1a164ba4cea2302a03be7b621678b1694/qiskit-1.4.3-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc82934e5b5192a75adca57bfa8194166e6bce1023da3b82e02db6c279a5d0fc", size = 6801019, upload-time = "2025-05-12T18:02:24.857Z" }, + { url = "https://files.pythonhosted.org/packages/40/a2/1355e3a8a00f9310ea80ab5887095bd3122918c8a61d62895e6519e442c0/qiskit-1.4.3-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03355819fb9747a937bfffb0aba59d44c4654536b87c62dcd00d4e4e1550190f", size = 7895620, upload-time = "2025-05-12T18:02:27.104Z" }, + { url = "https://files.pythonhosted.org/packages/85/35/a442b69b1507112f4fba392354d933f1ef65f66dc72bfce0c03be27f70c7/qiskit-1.4.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d90b25ad017839b0bf1b5d05d8bd4066b7f83e3c14839947994f5fd56a5f5e2", size = 6762841, upload-time = "2025-05-12T15:27:58.379Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f8/c9d116275bec7d0942f364ed6461b384e2ccd1c6bb5df8fe5d998d24ae41/qiskit-1.4.3-cp39-abi3-win32.whl", hash = "sha256:74cb30e34189ca9c1263994705a0cf8d97cead5f7375dedab3be4e783173785d", size = 6138538, upload-time = "2025-05-12T15:28:00.754Z" }, + { url = "https://files.pythonhosted.org/packages/ae/a7/7f736138e67f3f89e4a8b42bb480a9dcd582da9a87f4d723a3c4221766b0/qiskit-1.4.3-cp39-abi3-win_amd64.whl", hash = "sha256:554b5ad8c6198881923998fd0124660eec534c985c731d1e3c09c6421377c29e", size = 6517946, upload-time = "2025-05-12T15:28:03.189Z" }, ] [package.optional-dependencies] @@ -2752,6 +2751,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/f2/0e2260961c721ba0889e3f7fcdd69e5a7a24694b135d7ad5b6fe55e84e16/qiskit_aer-0.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:de793b75f19d762981198d6c770c991a5d4e0d32bc1768416cfa1520e28bdcf8", size = 9524145, upload-time = "2025-06-04T12:05:20.308Z" }, ] +[[package]] +name = "qiskit-ibm-ai-local-transpiler" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema" }, + { name = "networkx" }, + { name = "qiskit" }, + { name = "qiskit-ibm-runtime" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/2b/d4a31925f23a4614587bd256f1a5b46d53f667971243df2bff62ceb1286e/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6b13b0978b0bb906c1175a63b1c2c00070ed7f3ff9c302d9b8a8e104f5a8ec39", size = 97513406, upload-time = "2025-07-02T15:25:39.934Z" }, + { url = "https://files.pythonhosted.org/packages/54/70/b80685df8b5b957c6e61e44eec9c13f0b72c8a4458734048c5de875d1eb8/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:94a59d360c4470dac7a8467b86cd3787430b917c3d7aa1635279087459168a19", size = 98170843, upload-time = "2025-07-02T15:24:43.794Z" }, + { url = "https://files.pythonhosted.org/packages/10/ec/d62bb53f8dfc16cc908696809f5508b161f8c6709f6be44b410281c4e184/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4933917d137e07a7c889e11c9db30d6f48fc09fe1ecd2e6f856bf451e2e5fba8", size = 97637275, upload-time = "2025-07-02T15:23:20.273Z" }, + { url = "https://files.pythonhosted.org/packages/78/34/807162739e60cbd1f9365d5d00ce583445c4b5ac5e381384c892b69ebf25/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:d4a426b7798a4064487a1d50b0bf019ea1f5eec2a74580aaa2cb945c9b35b385", size = 97416246, upload-time = "2025-07-02T15:23:46.745Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f3/d653647764d13142f028ede9cd772fdb04e73259af622c3207210936d073/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0dd30e5679fb7c2371a11380a3b2c485410a3cb5f23628a94188d50cb4f197ff", size = 97513399, upload-time = "2025-07-02T15:23:59.758Z" }, + { url = "https://files.pythonhosted.org/packages/ba/20/1885c4064bbfd9919e0e03ccff97c3b4afdbeb3bc8effaf9253b5502afc8/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3fa93eb41ad5c14480b726c9737a98017c3a1723326e18c2b2c3c964a6de0b9", size = 98170686, upload-time = "2025-07-02T15:21:48.295Z" }, + { url = "https://files.pythonhosted.org/packages/58/c4/072723658abfd11169a63462396e8765b09f5a204a8d9401ad44da0e5004/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8703192d174ef0f71272bb50fe74b5612690cd9ee9e933a3346567327a04e8eb", size = 97636848, upload-time = "2025-07-02T15:23:38.279Z" }, + { url = "https://files.pythonhosted.org/packages/ae/01/4b4dc70144d08e0694d3a92aa0c7486a9dbb48f8442a7ada92d14f1bdfc7/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:5af2024463e2c34e58e56ead767d6b0f9ee14c3d4d1a01fce3f2ca0230479147", size = 97416835, upload-time = "2025-07-02T15:24:51.17Z" }, + { url = "https://files.pythonhosted.org/packages/31/f7/1e3a0eaf8250ba30a1c0dd4bb9a375d414cf18015cba5d6a85f369de13b9/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7d601b5f508582a6aec4f2fbe04ed50cc52d30e133fc8051178e5558ecaabe13", size = 97512749, upload-time = "2025-07-02T15:27:47.411Z" }, + { url = "https://files.pythonhosted.org/packages/05/fc/df0b6e3a9bdd1690aad940144130f247825fa0710270baba9614805d0071/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d99f87b76c2ae68678afa6f70f8632842a017c1a917774a89de12c9db58f557", size = 98169638, upload-time = "2025-07-02T15:20:13.497Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b4/90a577916747678edcde64dba3a724796ed8cb99915a3e3962f90791ae23/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49da8a583a117b4bc1c51d92a2075718b0cd7e5f000afbc80235e52b2568f70", size = 97636994, upload-time = "2025-07-02T15:23:41.209Z" }, + { url = "https://files.pythonhosted.org/packages/7a/cb/bd0f3995d06c9a2cafa7c49f990dd15e4a2b6860fd43cf6c29d9b9446018/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:aeaa9acacda590f5fd3f668bc16a75f2a515ba6002a1088c617b1b1546076886", size = 97417172, upload-time = "2025-07-02T15:23:07.882Z" }, +] + [[package]] name = "qiskit-ibm-runtime" version = "0.40.1" @@ -2773,6 +2797,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/2e/7ef9afa14f94affb7afd472edd70358c1a0c66e5cbeac1b2a29ce84b8a5d/qiskit_ibm_runtime-0.40.1-py3-none-any.whl", hash = "sha256:5a67e4c55b6e0a2bc9041c1ec7b8c5adc43a50f7dfb8a2521a0c2f3ed4aaa712", size = 3196409, upload-time = "2025-06-05T15:59:49.117Z" }, ] +[[package]] +name = "qiskit-ibm-transpiler" +version = "0.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backoff" }, + { name = "networkx" }, + { name = "qiskit" }, + { name = "qiskit-qasm3-import" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/ac/d6f176107a0a07aeae583dbde3e7812cd31f670f0d285a0167ece51f040e/qiskit_ibm_transpiler-0.13.1.tar.gz", hash = "sha256:83631565b3adb6ce3825a82af8b6276e3f5e87d193c6efd01b7edae3bf56b31c", size = 46935, upload-time = "2025-07-21T09:42:49.367Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/a4/4127dccc7ecfca71d0df5310ced026790ffd1e8da196fc360011416bcffa/qiskit_ibm_transpiler-0.13.1-py3-none-any.whl", hash = "sha256:5ebd20cf2b6fea77a2cf0263a113bfe37f4e2ac2a836469e4fe714565f886060", size = 61069, upload-time = "2025-07-21T09:42:47.889Z" }, +] + [[package]] name = "qiskit-qasm3-import" version = "0.6.0" @@ -2841,6 +2881,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/5d/836b97537a390cf811b0488490c389c5a614f0a93acb23f347bd37a2d914/requests_ntlm-1.3.0-py3-none-any.whl", hash = "sha256:4c7534a7d0e482bb0928531d621be4b2c74ace437e88c5a357ceb7452d25a510", size = 6577, upload-time = "2024-06-09T23:52:03.241Z" }, ] +[[package]] +name = "rich" +version = "14.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, +] + [[package]] name = "roman-numerals-py" version = "3.1.0" @@ -3614,39 +3667,39 @@ wheels = [ [[package]] name = "symengine" -version = "0.14.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/ae/051d3e2ffd128f4a8fa67d380bb7be45637d39e206b4c3737c087a3d4b71/symengine-0.14.1.tar.gz", hash = "sha256:4e9e4b4ec56371c2151803ae0403dab07dd1c74ce88e9abca433bebeb6e2f0f0", size = 938282, upload-time = "2025-04-21T04:03:04.916Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/64/7a9c565d804cc1aafdf4941a2fa3985a6b660ac70ac15080e5112113beeb/symengine-0.14.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0f977360c9993dae163951386ea5b865d8310f323cf11234e62b6535f330d3ac", size = 25935332, upload-time = "2025-04-21T04:00:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/08/9d/deba31c5a38cf26244298ebb63fee5d730638d23b6ab055ecf4988bcf485/symengine-0.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:524249b3224617f91e4e0b81c4134fa496024ddf67b383163586d74683f064a3", size = 22999100, upload-time = "2025-04-21T04:00:46.425Z" }, - { url = "https://files.pythonhosted.org/packages/87/77/13b5faf6b7873df3f2365aa2e43c7dac3e5cb7f037d7d0b60c648132fba9/symengine-0.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f2fb2b9ba7038cba436783a5c1bddc40ba84c7812a4b9c50571fd47ff265038", size = 60837233, upload-time = "2025-04-21T04:00:50.435Z" }, - { url = "https://files.pythonhosted.org/packages/46/cb/9bce97ad8135a32b47e90b3f57084bdc0bb844aa866b3ca0bc88987a2ac4/symengine-0.14.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a010412317d93e37fbee3f4bc04886408653e863997993424e7b9e4d8c85c150", size = 90826835, upload-time = "2025-04-21T04:00:55.849Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8f/3c335e44db300f4d91f7b098661a2add403367833cc27d26dc235520661a/symengine-0.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb14724ab6a6844d04adbd48d7aadcadfe4974193e87eedac93963a6e88bf53", size = 50356243, upload-time = "2025-04-21T04:01:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/d9f33b8a08bdfc07fff733c7f869deb5a0e8c93f5cb95ed4cb9d16294dfb/symengine-0.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:4635fa8855fcadae8c60f27f498388699b7ee88c6be7c3e23564eb0907f6b397", size = 18755307, upload-time = "2025-04-21T04:01:04.187Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f8/689900a258a68b121d7c61a6705b5332969dd95517f9be1d66a4937a17e1/symengine-0.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:43a394acef2355bbcbed089c8f83a7dbdac28f4f979e094b549f571fc411dea6", size = 25992552, upload-time = "2025-04-21T04:01:07.102Z" }, - { url = "https://files.pythonhosted.org/packages/6e/10/82291c78d6dbc17b2e4371559a3945920ecc536ec36b6c8dde28165064f9/symengine-0.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7eb37cd5a9eb0c1c5e35c515139fd1221d937b269aef3569b92c7bb4e251be4", size = 23052876, upload-time = "2025-04-21T04:01:09.679Z" }, - { url = "https://files.pythonhosted.org/packages/30/1a/2199515b7d4f3aa74262e3eb31916a593c4daa7da53bb2c9cbd2cc13fad8/symengine-0.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7657663cfb0d87d66848f7cacda0b2447e127584bc9ec65120e75ce68b21b809", size = 60873086, upload-time = "2025-04-21T04:01:14.285Z" }, - { url = "https://files.pythonhosted.org/packages/07/ce/1e7d9abea217cee8a543ff1fb395b4462e9a4df8072e25b42984e8a6938e/symengine-0.14.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94535da1085a4927364fbb4a8705f7f504897ac53da2cc6d6a8edc897e49c4da", size = 90878511, upload-time = "2025-04-21T04:01:21.764Z" }, - { url = "https://files.pythonhosted.org/packages/6e/23/4bcd98c8a79bc0d584786eb765f33dffca1136fe9b506c6e336d61fad844/symengine-0.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32a29b9462446c9e7f3bf464c7faa847ac2a2d75f0f3fd2f7c0606f9b9384cb", size = 50397966, upload-time = "2025-04-21T04:01:27.732Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/72612eae87f3d0ca58ae4e2207eaee9f8c1dfddc6862a1dc8e2257d67e14/symengine-0.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:f639a488886a066c4d8f19f2a4fd2213de2ea428153d8e1bf425c14f8bc74d57", size = 18803262, upload-time = "2025-04-21T04:01:31.136Z" }, - { url = "https://files.pythonhosted.org/packages/59/ab/3ef6b6385b277511a2e80f5425629af6566c491200ced6ba4a5b33db6b9c/symengine-0.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4c657fba40960dc143d90b20fe49ae769d5c82b323b9dd459f5e3dea4796df8f", size = 25962842, upload-time = "2025-04-21T04:01:34.359Z" }, - { url = "https://files.pythonhosted.org/packages/58/8d/e47e7e9166b4d53cacb0ad722164a6a2bfbb459d62bee105a05998f7b2aa/symengine-0.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9789c62a8ade18f368241525e910dae745fdde1f3b8bb782e5ac8bbfad505e92", size = 23046175, upload-time = "2025-04-21T04:01:37.275Z" }, - { url = "https://files.pythonhosted.org/packages/be/76/6c2227ca8076c238b65341beb3ce4a5bb29174afce3eb9f124b319242693/symengine-0.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcab68fe738a50df3a1b2415f75395c588aab237cb636818332e6cda7ddcf5fb", size = 60719492, upload-time = "2025-04-21T04:01:40.806Z" }, - { url = "https://files.pythonhosted.org/packages/bb/d8/e2dad8babfbb6c8abdb2c443aefca0ae65078c2a0c1f791117a2e659b005/symengine-0.14.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f58a88571a5f7ceca499d7f7834c00d129a55d4c2104a463ba8e3ec24c252e89", size = 90545323, upload-time = "2025-04-21T04:01:46.143Z" }, - { url = "https://files.pythonhosted.org/packages/64/4f/84948cd8384deb43465c14daea81e53159b1c22a2fd55c4f087c47f180df/symengine-0.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a55b8f78541d57a28beda6971bed0a7ddbd585148bb030221f7ca3a0c8e2517", size = 50278629, upload-time = "2025-04-21T04:01:51.673Z" }, - { url = "https://files.pythonhosted.org/packages/d6/7f/4d6b6998a69af3614cc4cb5953acc23b116b35e0596be4dd991397f0cdce/symengine-0.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:5091ce86728022d2c7e0e864ab23070494c1f24fb430ab3437d46806e854651e", size = 18754027, upload-time = "2025-04-21T04:01:55.355Z" }, - { url = "https://files.pythonhosted.org/packages/db/09/c382abfa3e83f11be0ade2ab063f11cc4a3a906b5194f62956856ba766b6/symengine-0.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9859c0c926475dfed666707afba04639a6d46ab48bc463faf50c79b6513de861", size = 25960338, upload-time = "2025-04-21T04:01:57.962Z" }, - { url = "https://files.pythonhosted.org/packages/13/8d/d4b541515b0fa5c390109572d035d397e28ac6f4bd69bee88806b231a65f/symengine-0.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:431545ef66b20efa24e5de9d754ffb184ad9ed29743740c0e9d815c1a1ec37a8", size = 23040715, upload-time = "2025-04-21T04:02:00.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/c7/4ca78ac8df7dacf35bfa77411c317d65adc6add07f58a4d210060b678511/symengine-0.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e69fe8be6e1d1f5209abeb7a8308a074d981b9f1f166086f23f6eed20d861e7f", size = 60716721, upload-time = "2025-04-21T04:02:04.19Z" }, - { url = "https://files.pythonhosted.org/packages/04/92/1d1d9084ccf1749af477273ac952ab68970175a62ef093b32d83dd3efc53/symengine-0.14.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b51617f42213ceb49786b474195d17e7d62e492d0592caa4b404f0e1b1acf58", size = 90546321, upload-time = "2025-04-21T04:02:09.873Z" }, - { url = "https://files.pythonhosted.org/packages/8d/23/922e6fd625ef08c4b703790d3accdcc48e6b340538de25a29ee8b5bebe6c/symengine-0.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e91af61b854e82ae5382e5f91e66d83ac007c0b19b3946f747bc4fc6ca25d66", size = 50277827, upload-time = "2025-04-21T04:02:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/7b/05/29090873cc7b3d23b492a192fa51ada148c80de016db2dc29225230f6499/symengine-0.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:d232d03ceb008d6eb24cb3e1f423af44d3d78cfe09aed801d9fc68ef7b41b611", size = 18753449, upload-time = "2025-04-21T04:02:38.332Z" }, - { url = "https://files.pythonhosted.org/packages/d8/23/0a542b0d3af0b017c129852265aa1a208f152855fd9feb0c1480d846b784/symengine-0.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1324f94852cf2541be29de31899d00bdcab547fea9e9534bcc548062c3f33038", size = 25893789, upload-time = "2025-04-21T04:02:19.407Z" }, - { url = "https://files.pythonhosted.org/packages/e3/38/d22630f658238e33138ceb57b368fd99555472f5e4be561bbc27cf4b134d/symengine-0.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e4b61cb16a559f2e098d52285b27fac4e6ee15194368cef5b78727f71a490bb5", size = 22991458, upload-time = "2025-04-21T04:02:22.396Z" }, - { url = "https://files.pythonhosted.org/packages/be/28/9ae2ee8c3a6e5b35b25a42625de4cd8ef432121dd4ff75bca6809b9e61ac/symengine-0.14.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58f8e1756c9f8cdb7f6cdf189b3752f20cb464f82bf1c7a3873156b12c567896", size = 60604042, upload-time = "2025-04-21T04:02:25.915Z" }, - { url = "https://files.pythonhosted.org/packages/7d/c0/233806912e5515505a058d2527a53117e0e6cd8e59525f1c7cb870805a47/symengine-0.14.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a96f1adfed8cfad62a4f58fe2f32b42718e0938afef0bffeb8131d862ca71a9b", size = 90280432, upload-time = "2025-04-21T04:02:31.02Z" }, - { url = "https://files.pythonhosted.org/packages/bd/93/a6f379c6bd9554efc4cd5475e75fc164d6c44e69d98ddf6553f12a2532aa/symengine-0.14.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c4f500fdd09cbd3cde34a027a964e47b4fc7bfcd5ec8b9a4e654a37036d364b", size = 50183106, upload-time = "2025-04-21T04:02:35.537Z" }, +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/ff/a2041497a482a0ae585672fe12cc8983c7fc46ce792811b55a067e5e5516/symengine-0.13.0.tar.gz", hash = "sha256:ab83a08897ebf12579702c2b71ba73d4732fb706cc4291d810aedf39c690c14c", size = 114237, upload-time = "2024-09-30T22:06:25.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/ed/964f75a2dc5b0e2c97b732f44dfb9c40fe7c0f5e21a1ecc2edff89db3d81/symengine-0.13.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:259fd4111c7a70c72bdff5686de1949e8132baeb612eacdaf8837720c6fe449b", size = 25867912, upload-time = "2024-09-30T22:03:05.097Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ce/c74dfbaf487a428984644b3cb5e1131c4808f60eab1456f37a107f20b87a/symengine-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44f2eb28a1e36db0bbd6679435412f79da9743bf9c1cb3eff25e0c343b7ddd48", size = 22711016, upload-time = "2024-09-30T22:03:09.144Z" }, + { url = "https://files.pythonhosted.org/packages/4b/65/df699e2b4c2bbf608394b05d1095d77b3f02569e09960f7840f708c7c5dc/symengine-0.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d141712fa14d9138bd19e64b10392f850c68d88cd7db29f1bda33e32d1095559", size = 61000047, upload-time = "2024-09-30T22:03:13.613Z" }, + { url = "https://files.pythonhosted.org/packages/ff/a9/623d97da0da9615367484127dd3b5d1049675832fb9a6a3572f2e072bb86/symengine-0.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:830226d933bfcdb93546e4062541627d9a3bc7a178a63fb16c002eb5c5221938", size = 90017189, upload-time = "2024-09-30T22:03:20.545Z" }, + { url = "https://files.pythonhosted.org/packages/79/a0/d30329ef1bd2b188cb5bbf6d9394e72fa9f38b33a6caa2128ee187716259/symengine-0.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a08090163819a0bbfa97d64bd2d8dac2c5268147ed9c242799d7f7e8728a6f4e", size = 49698796, upload-time = "2024-09-30T22:03:31.169Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e3/cf99b6353b46b8d9ff05e8d7d24764c8afed7c46b888eece99c6e04cc295/symengine-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1e435dcd8ed25e4c7c21ab1c0376be910efc7f35da76d532367df27b359f0358", size = 17830331, upload-time = "2024-09-30T22:03:35.649Z" }, + { url = "https://files.pythonhosted.org/packages/47/a7/e69cff22c2b169b469faa390f0102fbdefe1dfede893a086454483db0fc3/symengine-0.13.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:da0eba7e106095cdce88eb275c8a9d7c4586ad88f229394c53e1184155c00745", size = 25878286, upload-time = "2024-09-30T22:03:39.216Z" }, + { url = "https://files.pythonhosted.org/packages/60/40/bb3faf5a3d4cc99cf5252cc3f4f5267568abd4aae6439374623841cc0025/symengine-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b0c175f4f895a73a925508af03faf7efd6cad8593256bbdb5346bd996d3ec5c8", size = 22721741, upload-time = "2024-09-30T22:03:42.574Z" }, + { url = "https://files.pythonhosted.org/packages/de/da/d6350f60f11abc7ee56fcb6b996deba7b31584b5942a4c5db7d3d4f324dd/symengine-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e58d1e2abd08381aa0cf24c88c0e8b7f592df92619b51e32d36835fbd2dd6ae8", size = 60999516, upload-time = "2024-09-30T22:03:47.206Z" }, + { url = "https://files.pythonhosted.org/packages/d1/ee/db107db7d0557aa8dbc9485741a60dd4f869d3da32180710506f9ba942b9/symengine-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db745f2c7a3c5e83510cf4decb43201f43552dfb05ad8af9787c89708be9ede", size = 90019965, upload-time = "2024-09-30T22:03:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f0/0642f5d9681ff26e57c317d0514315cf1b0dfe1bc8f68ee14a13a270d704/symengine-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2572c98b09ac284db6ecff63f6170461194dc94c4209afd34c092ec67873d85", size = 49690621, upload-time = "2024-09-30T22:03:59.467Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/4300eda41959e3839115b2cb0ddb21818804f5eb129cf92eb9cc55c6efe5/symengine-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:12727f02a2919f005aee48e68e0cbb70cf857b19385857b4d985d1c9b075f620", size = 17831939, upload-time = "2024-09-30T22:04:03.649Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b2/786d3efb98ae1c8e0a9869d6901f24a6633bd621f9e4e1427c86bff35abb/symengine-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cf91d24f1bfd6d53228593c7804dd106b71b19674d5afc4fa322d516e1793bdd", size = 25853458, upload-time = "2024-09-30T22:04:06.435Z" }, + { url = "https://files.pythonhosted.org/packages/3f/74/78b9e7f17c9b9b345d8ef0dbdefebbfc2c7f00693949c6b5808f8a9e54d8/symengine-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5615b7eb68890917abd390ebb10434a949165f6064741c1a8cc345fee14e855", size = 22713256, upload-time = "2024-09-30T22:04:10.002Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a8/69f429946e9a9e63a141dcbe519df8a8c3d56aa75fa8440716871efd8b75/symengine-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb92bdf0890de264abaeacbfbdbd4dd7444b94057bd47958d913b662e549ad8a", size = 60847852, upload-time = "2024-09-30T22:04:14.415Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/a613d5fa73c1b05eb4f0a4bc2bfa21314d37c89dcdb355da684b5f9bea46/symengine-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3bce486fbc0b87970ed1b10ca9d5cafb1fd6b66382fe631261d83592851d7e", size = 89691094, upload-time = "2024-09-30T22:04:21.012Z" }, + { url = "https://files.pythonhosted.org/packages/90/9f/5a171a9edff23eb0e33e0a2dca295a8b25fd64491ebe8cf765e489bd2bcd/symengine-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7e6bae9cfcdde2775d92fbb0abe3ef04e32f65ebc4c2d164ca33f4da202d4a7", size = 49584342, upload-time = "2024-09-30T22:04:28.117Z" }, + { url = "https://files.pythonhosted.org/packages/07/16/a69dffc665e5007a0b4f1500fc401316aa070d109f83bc6887802dce199d/symengine-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:bced0a1dbdb94737c299384c85ddbad6944ce8dadc334f7bb8dbbd8f6c965807", size = 17787218, upload-time = "2024-09-30T22:04:32.066Z" }, + { url = "https://files.pythonhosted.org/packages/f2/51/36ea8d87b61f34d585d09ff585cdc2ba136c501e0a96e861fe81fd0efa5b/symengine-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d34df77971538e4c29f2d8e5ef7f459c2179465e6cdb7dfd48b79b87ecd8f4d", size = 25838153, upload-time = "2024-09-30T22:04:35.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/f7/73cd707633c01760df27d340ac2868788fa0a35034aa09f51f6a289d9a07/symengine-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ab2661d9b18867e7c6edbfa7a74b8b0a2a694bd24aa08003dc3214f77cb9d6f2", size = 22706111, upload-time = "2024-09-30T22:04:38.922Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e7/a1ddc4cc3f2604b18965342523cddd6160b6406d1ef21b58a2dea1c46312/symengine-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53f27b9013878ee4419d8e853664d8ae4b68419e3f4b9b5b7f503d32bf904755", size = 60848269, upload-time = "2024-09-30T22:04:43.816Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f5/b127d236a8ccce8b85cec8bcb0221cbb6a4e651d6f5511da925e10714a4c/symengine-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27987f75ce08c64f453e2b9b74fec6ffc5ca418c4deca0b75580979d4a4e242a", size = 89679345, upload-time = "2024-09-30T22:04:50.53Z" }, + { url = "https://files.pythonhosted.org/packages/49/d0/b07c71dfb6f7f47f90495d67cb0b2264f94f2fb9380e528fe4fcec4c5cfa/symengine-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ea9410330ea15ed4137d7a0a3c43caccacb71490e18036ce5182d08c93baf8", size = 49582795, upload-time = "2024-09-30T22:04:56.705Z" }, + { url = "https://files.pythonhosted.org/packages/de/c6/3ce562ec269b033a738b99aa75729d564bfe465a765a5b5810200924f5c9/symengine-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:5031eb7a5c6675d5195bb57f93cc7d9ac5a7a9a826d4ad6f6b2927746ed7e6e6", size = 17786679, upload-time = "2024-09-30T22:05:30.754Z" }, + { url = "https://files.pythonhosted.org/packages/ca/0f/02031b4ed54fb088ade94082e4658160333c2d5c6629ca7e567ea5a23720/symengine-0.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ce0e5dfb19943bcf3e44a4485bcac4c5533ba3705c63083494eed0b3bf246076", size = 25795209, upload-time = "2024-09-30T22:05:05.713Z" }, + { url = "https://files.pythonhosted.org/packages/34/c0/03e9e34a4e2af73dd786fb966ee3ad7ffa57659e79e4ac390be9e9f6aded/symengine-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c3b77dc54bf1181f6bd3b3338c4e6e5973a8b0fa20a189d15563ef5626e57b04", size = 22670484, upload-time = "2024-09-30T22:05:08.721Z" }, + { url = "https://files.pythonhosted.org/packages/9d/13/66c8510403089ee157f0a8930a2e043e6f4de9ee514c8084adb958934058/symengine-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca7c3f6c168f6f5b06b421833c3d3baae56067a94b671bdffbe09b8e4fefd9be", size = 60739889, upload-time = "2024-09-30T22:05:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/70/fe/d0c778204d855257865e713fcbfef11dde34621e07fee439d4d117f43203/symengine-0.13.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:847523de682416811bacb3ad11507e663b3522fbb35cd27184757e9956d0eaf0", size = 89405899, upload-time = "2024-09-30T22:05:20.504Z" }, + { url = "https://files.pythonhosted.org/packages/66/f6/f546e527caf35b7d0f14dbcea278134d4e46d7431821b9ca9f5ec3388a6a/symengine-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2fc1b7d96426463f0c9011e9fb88459d906477c1baa8a996dde6fb2bfa99d4", size = 49474632, upload-time = "2024-09-30T22:05:26.083Z" }, ] [[package]] @@ -3762,8 +3815,7 @@ dependencies = [ { name = "filelock", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "fsspec", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "jinja2", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "networkx", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "sympy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "typing-extensions", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, ] @@ -3790,8 +3842,7 @@ dependencies = [ { name = "filelock", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "fsspec", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "jinja2", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')" }, - { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, + { name = "networkx", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, From b1ac8ce1a9d49df18af267a548bae0e0f0496da8 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Sun, 3 Aug 2025 11:27:24 +0200 Subject: [PATCH 10/98] Fix dependencies issues --- pyproject.toml | 9 +- src/mqt/predictor/rl/predictorenv.py | 12 +- uv.lock | 452 +++++++++++++++------------ 3 files changed, 264 insertions(+), 209 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 825fcefb3..e1acedfb7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "mqt.bench>=2.0.0", "qiskit!=1.3.2", # 1.3.2 causes a Qiskit error when using the CommutativeInverseCancellation pass, see https://github.com/Qiskit/qiskit/issues/13742 "pytket>=1.29.0", # lowest version that supports the used pytket AutoRebase pass instead of auto_rebase - "pytket_qiskit>=0.60.0", + "pytket_qiskit>=0.71.0", "sb3_contrib>=2.0.0", "tqdm>=4.66.0", "rich>=12.6.0", @@ -44,7 +44,8 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 - "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. + "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", + "torch>=2.4.0; python_version >= '3.12' and sys_platform != 'darwin' and 'x86_64' not in platform_machine", "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1", "qiskit-ibm-ai-local-transpiler>=0.3.2" @@ -251,4 +252,6 @@ fom = "fom" ignore = ["GH200"] [tool.uv] -override-dependencies = ["networkx==2.8.5"] +override-dependencies = [ + "networkx==2.8.5", +] diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index b152f2c47..5f1d4603e 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -391,21 +391,21 @@ def _handle_qiskit_layout_postprocessing( ) -> QuantumCircuit: if action.name == "VF2PostLayout": assert pm_property_set["VF2PostLayout_stop_reason"] is not None - post_layout = pm_property_set["post_layout"] + post_layout = pm_property_set.get("post_layout") if post_layout: altered_qc, _ = postprocess_vf2postlayout(altered_qc, post_layout, self.layout) - else: - assert pm_property_set["layout"] - if pm_property_set["layout"]: + layout = pm_property_set.get("layout") + if layout: self.layout = TranspileLayout( - initial_layout=pm_property_set["layout"], + initial_layout=layout, input_qubit_mapping=pm_property_set["original_qubit_indices"], final_layout=pm_property_set["final_layout"], _output_qubit_list=altered_qc.qubits, _input_qubit_count=self.num_qubits_uncompiled_circuit, ) - if self.layout is not None and pm_property_set["final_layout"]: + + if self.layout is not None and pm_property_set.get("final_layout"): self.layout.final_layout = pm_property_set["final_layout"] return altered_qc diff --git a/uv.lock b/uv.lock index 215a0a69d..4e3e5bdde 100644 --- a/uv.lock +++ b/uv.lock @@ -2,9 +2,11 @@ version = 1 revision = 3 requires-python = ">=3.10" resolution-markers = [ - "python_full_version >= '3.13'", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", @@ -164,11 +166,11 @@ wheels = [ [[package]] name = "certifi" -version = "2025.7.14" +version = "2025.8.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" }, + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, ] [[package]] @@ -404,9 +406,11 @@ name = "contourpy" version = "1.3.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -935,8 +939,10 @@ name = "gymnasium" version = "1.2.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", ] @@ -1074,9 +1080,11 @@ name = "ipython" version = "9.4.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -1405,7 +1413,7 @@ wheels = [ [[package]] name = "matplotlib" -version = "3.10.3" +version = "3.10.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, @@ -1420,41 +1428,62 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/26/91/d49359a21893183ed2a5b6c76bec40e0b1dcbf8ca148f864d134897cfc75/matplotlib-3.10.3.tar.gz", hash = "sha256:2f82d2c5bb7ae93aaaa4cd42aca65d76ce6376f83304fa3a630b569aca274df0", size = 34799811, upload-time = "2025-05-08T19:10:54.39Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/ea/2bba25d289d389c7451f331ecd593944b3705f06ddf593fa7be75037d308/matplotlib-3.10.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:213fadd6348d106ca7db99e113f1bea1e65e383c3ba76e8556ba4a3054b65ae7", size = 8167862, upload-time = "2025-05-08T19:09:39.563Z" }, - { url = "https://files.pythonhosted.org/packages/41/81/cc70b5138c926604e8c9ed810ed4c79e8116ba72e02230852f5c12c87ba2/matplotlib-3.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3bec61cb8221f0ca6313889308326e7bb303d0d302c5cc9e523b2f2e6c73deb", size = 8042149, upload-time = "2025-05-08T19:09:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9a/0ff45b6bfa42bb16de597e6058edf2361c298ad5ef93b327728145161bbf/matplotlib-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c21ae75651c0231b3ba014b6d5e08fb969c40cdb5a011e33e99ed0c9ea86ecb", size = 8453719, upload-time = "2025-05-08T19:09:44.901Z" }, - { url = "https://files.pythonhosted.org/packages/85/c7/1866e972fed6d71ef136efbc980d4d1854ab7ef1ea8152bbd995ca231c81/matplotlib-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e39755580b08e30e3620efc659330eac5d6534ab7eae50fa5e31f53ee4e30", size = 8590801, upload-time = "2025-05-08T19:09:47.404Z" }, - { url = "https://files.pythonhosted.org/packages/5d/b9/748f6626d534ab7e255bdc39dc22634d337cf3ce200f261b5d65742044a1/matplotlib-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf4636203e1190871d3a73664dea03d26fb019b66692cbfd642faafdad6208e8", size = 9402111, upload-time = "2025-05-08T19:09:49.474Z" }, - { url = "https://files.pythonhosted.org/packages/1f/78/8bf07bd8fb67ea5665a6af188e70b57fcb2ab67057daa06b85a08e59160a/matplotlib-3.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:fd5641a9bb9d55f4dd2afe897a53b537c834b9012684c8444cc105895c8c16fd", size = 8057213, upload-time = "2025-05-08T19:09:51.489Z" }, - { url = "https://files.pythonhosted.org/packages/f5/bd/af9f655456f60fe1d575f54fb14704ee299b16e999704817a7645dfce6b0/matplotlib-3.10.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0ef061f74cd488586f552d0c336b2f078d43bc00dc473d2c3e7bfee2272f3fa8", size = 8178873, upload-time = "2025-05-08T19:09:53.857Z" }, - { url = "https://files.pythonhosted.org/packages/c2/86/e1c86690610661cd716eda5f9d0b35eaf606ae6c9b6736687cfc8f2d0cd8/matplotlib-3.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96985d14dc5f4a736bbea4b9de9afaa735f8a0fc2ca75be2fa9e96b2097369d", size = 8052205, upload-time = "2025-05-08T19:09:55.684Z" }, - { url = "https://files.pythonhosted.org/packages/54/51/a9f8e49af3883dacddb2da1af5fca1f7468677f1188936452dd9aaaeb9ed/matplotlib-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5f0283da91e9522bdba4d6583ed9d5521566f63729ffb68334f86d0bb98049", size = 8465823, upload-time = "2025-05-08T19:09:57.442Z" }, - { url = "https://files.pythonhosted.org/packages/e7/e3/c82963a3b86d6e6d5874cbeaa390166458a7f1961bab9feb14d3d1a10f02/matplotlib-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdfa07c0ec58035242bc8b2c8aae37037c9a886370eef6850703d7583e19964b", size = 8606464, upload-time = "2025-05-08T19:09:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/0e/34/24da1027e7fcdd9e82da3194c470143c551852757a4b473a09a012f5b945/matplotlib-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c0b9849a17bce080a16ebcb80a7b714b5677d0ec32161a2cc0a8e5a6030ae220", size = 9413103, upload-time = "2025-05-08T19:10:03.208Z" }, - { url = "https://files.pythonhosted.org/packages/a6/da/948a017c3ea13fd4a97afad5fdebe2f5bbc4d28c0654510ce6fd6b06b7bd/matplotlib-3.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:eef6ed6c03717083bc6d69c2d7ee8624205c29a8e6ea5a31cd3492ecdbaee1e1", size = 8065492, upload-time = "2025-05-08T19:10:05.271Z" }, - { url = "https://files.pythonhosted.org/packages/eb/43/6b80eb47d1071f234ef0c96ca370c2ca621f91c12045f1401b5c9b28a639/matplotlib-3.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ab1affc11d1f495ab9e6362b8174a25afc19c081ba5b0775ef00533a4236eea", size = 8179689, upload-time = "2025-05-08T19:10:07.602Z" }, - { url = "https://files.pythonhosted.org/packages/0f/70/d61a591958325c357204870b5e7b164f93f2a8cca1dc6ce940f563909a13/matplotlib-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a818d8bdcafa7ed2eed74487fdb071c09c1ae24152d403952adad11fa3c65b4", size = 8050466, upload-time = "2025-05-08T19:10:09.383Z" }, - { url = "https://files.pythonhosted.org/packages/e7/75/70c9d2306203148cc7902a961240c5927dd8728afedf35e6a77e105a2985/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748ebc3470c253e770b17d8b0557f0aa85cf8c63fd52f1a61af5b27ec0b7ffee", size = 8456252, upload-time = "2025-05-08T19:10:11.958Z" }, - { url = "https://files.pythonhosted.org/packages/c4/91/ba0ae1ff4b3f30972ad01cd4a8029e70a0ec3b8ea5be04764b128b66f763/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed70453fd99733293ace1aec568255bc51c6361cb0da94fa5ebf0649fdb2150a", size = 8601321, upload-time = "2025-05-08T19:10:14.47Z" }, - { url = "https://files.pythonhosted.org/packages/d2/88/d636041eb54a84b889e11872d91f7cbf036b3b0e194a70fa064eb8b04f7a/matplotlib-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbed9917b44070e55640bd13419de83b4c918e52d97561544814ba463811cbc7", size = 9406972, upload-time = "2025-05-08T19:10:16.569Z" }, - { url = "https://files.pythonhosted.org/packages/b1/79/0d1c165eac44405a86478082e225fce87874f7198300bbebc55faaf6d28d/matplotlib-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:cf37d8c6ef1a48829443e8ba5227b44236d7fcaf7647caa3178a4ff9f7a5be05", size = 8067954, upload-time = "2025-05-08T19:10:18.663Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c1/23cfb566a74c696a3b338d8955c549900d18fe2b898b6e94d682ca21e7c2/matplotlib-3.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9f2efccc8dcf2b86fc4ee849eea5dcaecedd0773b30f47980dc0cbeabf26ec84", size = 8180318, upload-time = "2025-05-08T19:10:20.426Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0c/02f1c3b66b30da9ee343c343acbb6251bef5b01d34fad732446eaadcd108/matplotlib-3.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ddbba06a6c126e3301c3d272a99dcbe7f6c24c14024e80307ff03791a5f294e", size = 8051132, upload-time = "2025-05-08T19:10:22.569Z" }, - { url = "https://files.pythonhosted.org/packages/b4/ab/8db1a5ac9b3a7352fb914133001dae889f9fcecb3146541be46bed41339c/matplotlib-3.10.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748302b33ae9326995b238f606e9ed840bf5886ebafcb233775d946aa8107a15", size = 8457633, upload-time = "2025-05-08T19:10:24.749Z" }, - { url = "https://files.pythonhosted.org/packages/f5/64/41c4367bcaecbc03ef0d2a3ecee58a7065d0a36ae1aa817fe573a2da66d4/matplotlib-3.10.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a80fcccbef63302c0efd78042ea3c2436104c5b1a4d3ae20f864593696364ac7", size = 8601031, upload-time = "2025-05-08T19:10:27.03Z" }, - { url = "https://files.pythonhosted.org/packages/12/6f/6cc79e9e5ab89d13ed64da28898e40fe5b105a9ab9c98f83abd24e46d7d7/matplotlib-3.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55e46cbfe1f8586adb34f7587c3e4f7dedc59d5226719faf6cb54fc24f2fd52d", size = 9406988, upload-time = "2025-05-08T19:10:29.056Z" }, - { url = "https://files.pythonhosted.org/packages/b1/0f/eed564407bd4d935ffabf561ed31099ed609e19287409a27b6d336848653/matplotlib-3.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:151d89cb8d33cb23345cd12490c76fd5d18a56581a16d950b48c6ff19bb2ab93", size = 8068034, upload-time = "2025-05-08T19:10:31.221Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e5/2f14791ff69b12b09e9975e1d116d9578ac684460860ce542c2588cb7a1c/matplotlib-3.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c26dd9834e74d164d06433dc7be5d75a1e9890b926b3e57e74fa446e1a62c3e2", size = 8218223, upload-time = "2025-05-08T19:10:33.114Z" }, - { url = "https://files.pythonhosted.org/packages/5c/08/30a94afd828b6e02d0a52cae4a29d6e9ccfcf4c8b56cc28b021d3588873e/matplotlib-3.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:24853dad5b8c84c8c2390fc31ce4858b6df504156893292ce8092d190ef8151d", size = 8094985, upload-time = "2025-05-08T19:10:35.337Z" }, - { url = "https://files.pythonhosted.org/packages/89/44/f3bc6b53066c889d7a1a3ea8094c13af6a667c5ca6220ec60ecceec2dabe/matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f7878214d369d7d4215e2a9075fef743be38fa401d32e6020bab2dfabaa566", size = 8483109, upload-time = "2025-05-08T19:10:37.611Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c7/473bc559beec08ebee9f86ca77a844b65747e1a6c2691e8c92e40b9f42a8/matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6929fc618cb6db9cb75086f73b3219bbb25920cb24cee2ea7a12b04971a4158", size = 8618082, upload-time = "2025-05-08T19:10:39.892Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e9/6ce8edd264c8819e37bbed8172e0ccdc7107fe86999b76ab5752276357a4/matplotlib-3.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c7818292a5cc372a2dc4c795e5c356942eb8350b98ef913f7fda51fe175ac5d", size = 9413699, upload-time = "2025-05-08T19:10:42.376Z" }, - { url = "https://files.pythonhosted.org/packages/1b/92/9a45c91089c3cf690b5badd4be81e392ff086ccca8a1d4e3a08463d8a966/matplotlib-3.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4f23ffe95c5667ef8a2b56eea9b53db7f43910fa4a2d5472ae0f72b64deab4d5", size = 8139044, upload-time = "2025-05-08T19:10:44.551Z" }, - { url = "https://files.pythonhosted.org/packages/3d/d1/f54d43e95384b312ffa4a74a4326c722f3b8187aaaa12e9a84cdf3037131/matplotlib-3.10.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:86ab63d66bbc83fdb6733471d3bff40897c1e9921cba112accd748eee4bce5e4", size = 8162896, upload-time = "2025-05-08T19:10:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/24/a4/fbfc00c2346177c95b353dcf9b5a004106abe8730a62cb6f27e79df0a698/matplotlib-3.10.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a48f9c08bf7444b5d2391a83e75edb464ccda3c380384b36532a0962593a1751", size = 8039702, upload-time = "2025-05-08T19:10:49.634Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b9/59e120d24a2ec5fc2d30646adb2efb4621aab3c6d83d66fb2a7a182db032/matplotlib-3.10.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb73d8aa75a237457988f9765e4dfe1c0d2453c5ca4eabc897d4309672c8e014", size = 8594298, upload-time = "2025-05-08T19:10:51.738Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/43/91/f2939bb60b7ebf12478b030e0d7f340247390f402b3b189616aad790c366/matplotlib-3.10.5.tar.gz", hash = "sha256:352ed6ccfb7998a00881692f38b4ca083c691d3e275b4145423704c34c909076", size = 34804044, upload-time = "2025-07-31T18:09:33.805Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/89/5355cdfe43242cb4d1a64a67cb6831398b665ad90e9702c16247cbd8d5ab/matplotlib-3.10.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5d4773a6d1c106ca05cb5a5515d277a6bb96ed09e5c8fab6b7741b8fcaa62c8f", size = 8229094, upload-time = "2025-07-31T18:07:36.507Z" }, + { url = "https://files.pythonhosted.org/packages/34/bc/ba802650e1c69650faed261a9df004af4c6f21759d7a1ec67fe972f093b3/matplotlib-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc88af74e7ba27de6cbe6faee916024ea35d895ed3d61ef6f58c4ce97da7185a", size = 8091464, upload-time = "2025-07-31T18:07:38.864Z" }, + { url = "https://files.pythonhosted.org/packages/ac/64/8d0c8937dee86c286625bddb1902efacc3e22f2b619f5b5a8df29fe5217b/matplotlib-3.10.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:64c4535419d5617f7363dad171a5a59963308e0f3f813c4bed6c9e6e2c131512", size = 8653163, upload-time = "2025-07-31T18:07:41.141Z" }, + { url = "https://files.pythonhosted.org/packages/11/dc/8dfc0acfbdc2fc2336c72561b7935cfa73db9ca70b875d8d3e1b3a6f371a/matplotlib-3.10.5-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a277033048ab22d34f88a3c5243938cef776493f6201a8742ed5f8b553201343", size = 9490635, upload-time = "2025-07-31T18:07:42.936Z" }, + { url = "https://files.pythonhosted.org/packages/54/02/e3fdfe0f2e9fb05f3a691d63876639dbf684170fdcf93231e973104153b4/matplotlib-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e4a6470a118a2e93022ecc7d3bd16b3114b2004ea2bf014fff875b3bc99b70c6", size = 9539036, upload-time = "2025-07-31T18:07:45.18Z" }, + { url = "https://files.pythonhosted.org/packages/c1/29/82bf486ff7f4dbedfb11ccc207d0575cbe3be6ea26f75be514252bde3d70/matplotlib-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:7e44cada61bec8833c106547786814dd4a266c1b2964fd25daa3804f1b8d4467", size = 8093529, upload-time = "2025-07-31T18:07:49.553Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c7/1f2db90a1d43710478bb1e9b57b162852f79234d28e4f48a28cc415aa583/matplotlib-3.10.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:dcfc39c452c6a9f9028d3e44d2d721484f665304857188124b505b2c95e1eecf", size = 8239216, upload-time = "2025-07-31T18:07:51.947Z" }, + { url = "https://files.pythonhosted.org/packages/82/6d/ca6844c77a4f89b1c9e4d481c412e1d1dbabf2aae2cbc5aa2da4a1d6683e/matplotlib-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:903352681b59f3efbf4546985142a9686ea1d616bb054b09a537a06e4b892ccf", size = 8102130, upload-time = "2025-07-31T18:07:53.65Z" }, + { url = "https://files.pythonhosted.org/packages/1d/1e/5e187a30cc673a3e384f3723e5f3c416033c1d8d5da414f82e4e731128ea/matplotlib-3.10.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:080c3676a56b8ee1c762bcf8fca3fe709daa1ee23e6ef06ad9f3fc17332f2d2a", size = 8666471, upload-time = "2025-07-31T18:07:55.304Z" }, + { url = "https://files.pythonhosted.org/packages/03/c0/95540d584d7d645324db99a845ac194e915ef75011a0d5e19e1b5cee7e69/matplotlib-3.10.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4b4984d5064a35b6f66d2c11d668565f4389b1119cc64db7a4c1725bc11adffc", size = 9500518, upload-time = "2025-07-31T18:07:57.199Z" }, + { url = "https://files.pythonhosted.org/packages/ba/2e/e019352099ea58b4169adb9c6e1a2ad0c568c6377c2b677ee1f06de2adc7/matplotlib-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3967424121d3a46705c9fa9bdb0931de3228f13f73d7bb03c999c88343a89d89", size = 9552372, upload-time = "2025-07-31T18:07:59.41Z" }, + { url = "https://files.pythonhosted.org/packages/b7/81/3200b792a5e8b354f31f4101ad7834743ad07b6d620259f2059317b25e4d/matplotlib-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:33775bbeb75528555a15ac29396940128ef5613cf9a2d31fb1bfd18b3c0c0903", size = 8100634, upload-time = "2025-07-31T18:08:01.801Z" }, + { url = "https://files.pythonhosted.org/packages/52/46/a944f6f0c1f5476a0adfa501969d229ce5ae60cf9a663be0e70361381f89/matplotlib-3.10.5-cp311-cp311-win_arm64.whl", hash = "sha256:c61333a8e5e6240e73769d5826b9a31d8b22df76c0778f8480baf1b4b01c9420", size = 7978880, upload-time = "2025-07-31T18:08:03.407Z" }, + { url = "https://files.pythonhosted.org/packages/66/1e/c6f6bcd882d589410b475ca1fc22e34e34c82adff519caf18f3e6dd9d682/matplotlib-3.10.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:00b6feadc28a08bd3c65b2894f56cf3c94fc8f7adcbc6ab4516ae1e8ed8f62e2", size = 8253056, upload-time = "2025-07-31T18:08:05.385Z" }, + { url = "https://files.pythonhosted.org/packages/53/e6/d6f7d1b59413f233793dda14419776f5f443bcccb2dfc84b09f09fe05dbe/matplotlib-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee98a5c5344dc7f48dc261b6ba5d9900c008fc12beb3fa6ebda81273602cc389", size = 8110131, upload-time = "2025-07-31T18:08:07.293Z" }, + { url = "https://files.pythonhosted.org/packages/66/2b/bed8a45e74957549197a2ac2e1259671cd80b55ed9e1fe2b5c94d88a9202/matplotlib-3.10.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a17e57e33de901d221a07af32c08870ed4528db0b6059dce7d7e65c1122d4bea", size = 8669603, upload-time = "2025-07-31T18:08:09.064Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a7/315e9435b10d057f5e52dfc603cd353167ae28bb1a4e033d41540c0067a4/matplotlib-3.10.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97b9d6443419085950ee4a5b1ee08c363e5c43d7176e55513479e53669e88468", size = 9508127, upload-time = "2025-07-31T18:08:10.845Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d9/edcbb1f02ca99165365d2768d517898c22c6040187e2ae2ce7294437c413/matplotlib-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ceefe5d40807d29a66ae916c6a3915d60ef9f028ce1927b84e727be91d884369", size = 9566926, upload-time = "2025-07-31T18:08:13.186Z" }, + { url = "https://files.pythonhosted.org/packages/3b/d9/6dd924ad5616c97b7308e6320cf392c466237a82a2040381163b7500510a/matplotlib-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:c04cba0f93d40e45b3c187c6c52c17f24535b27d545f757a2fffebc06c12b98b", size = 8107599, upload-time = "2025-07-31T18:08:15.116Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f3/522dc319a50f7b0279fbe74f86f7a3506ce414bc23172098e8d2bdf21894/matplotlib-3.10.5-cp312-cp312-win_arm64.whl", hash = "sha256:a41bcb6e2c8e79dc99c5511ae6f7787d2fb52efd3d805fff06d5d4f667db16b2", size = 7978173, upload-time = "2025-07-31T18:08:21.518Z" }, + { url = "https://files.pythonhosted.org/packages/8d/05/4f3c1f396075f108515e45cb8d334aff011a922350e502a7472e24c52d77/matplotlib-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:354204db3f7d5caaa10e5de74549ef6a05a4550fdd1c8f831ab9bca81efd39ed", size = 8253586, upload-time = "2025-07-31T18:08:23.107Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2c/e084415775aac7016c3719fe7006cdb462582c6c99ac142f27303c56e243/matplotlib-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b072aac0c3ad563a2b3318124756cb6112157017f7431626600ecbe890df57a1", size = 8110715, upload-time = "2025-07-31T18:08:24.675Z" }, + { url = "https://files.pythonhosted.org/packages/52/1b/233e3094b749df16e3e6cd5a44849fd33852e692ad009cf7de00cf58ddf6/matplotlib-3.10.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d52fd5b684d541b5a51fb276b2b97b010c75bee9aa392f96b4a07aeb491e33c7", size = 8669397, upload-time = "2025-07-31T18:08:26.778Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ec/03f9e003a798f907d9f772eed9b7c6a9775d5bd00648b643ebfb88e25414/matplotlib-3.10.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee7a09ae2f4676276f5a65bd9f2bd91b4f9fbaedf49f40267ce3f9b448de501f", size = 9508646, upload-time = "2025-07-31T18:08:28.848Z" }, + { url = "https://files.pythonhosted.org/packages/91/e7/c051a7a386680c28487bca27d23b02d84f63e3d2a9b4d2fc478e6a42e37e/matplotlib-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ba6c3c9c067b83481d647af88b4e441d532acdb5ef22178a14935b0b881188f4", size = 9567424, upload-time = "2025-07-31T18:08:30.726Z" }, + { url = "https://files.pythonhosted.org/packages/36/c2/24302e93ff431b8f4173ee1dd88976c8d80483cadbc5d3d777cef47b3a1c/matplotlib-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:07442d2692c9bd1cceaa4afb4bbe5b57b98a7599de4dabfcca92d3eea70f9ebe", size = 8107809, upload-time = "2025-07-31T18:08:33.928Z" }, + { url = "https://files.pythonhosted.org/packages/0b/33/423ec6a668d375dad825197557ed8fbdb74d62b432c1ed8235465945475f/matplotlib-3.10.5-cp313-cp313-win_arm64.whl", hash = "sha256:48fe6d47380b68a37ccfcc94f009530e84d41f71f5dae7eda7c4a5a84aa0a674", size = 7978078, upload-time = "2025-07-31T18:08:36.764Z" }, + { url = "https://files.pythonhosted.org/packages/51/17/521fc16ec766455c7bb52cc046550cf7652f6765ca8650ff120aa2d197b6/matplotlib-3.10.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b80eb8621331449fc519541a7461987f10afa4f9cfd91afcd2276ebe19bd56c", size = 8295590, upload-time = "2025-07-31T18:08:38.521Z" }, + { url = "https://files.pythonhosted.org/packages/f8/12/23c28b2c21114c63999bae129fce7fd34515641c517ae48ce7b7dcd33458/matplotlib-3.10.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47a388908e469d6ca2a6015858fa924e0e8a2345a37125948d8e93a91c47933e", size = 8158518, upload-time = "2025-07-31T18:08:40.195Z" }, + { url = "https://files.pythonhosted.org/packages/81/f8/aae4eb25e8e7190759f3cb91cbeaa344128159ac92bb6b409e24f8711f78/matplotlib-3.10.5-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8b6b49167d208358983ce26e43aa4196073b4702858670f2eb111f9a10652b4b", size = 8691815, upload-time = "2025-07-31T18:08:42.238Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ba/450c39ebdd486bd33a359fc17365ade46c6a96bf637bbb0df7824de2886c/matplotlib-3.10.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a8da0453a7fd8e3da114234ba70c5ba9ef0e98f190309ddfde0f089accd46ea", size = 9522814, upload-time = "2025-07-31T18:08:44.914Z" }, + { url = "https://files.pythonhosted.org/packages/89/11/9c66f6a990e27bb9aa023f7988d2d5809cb98aa39c09cbf20fba75a542ef/matplotlib-3.10.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52c6573dfcb7726a9907b482cd5b92e6b5499b284ffacb04ffbfe06b3e568124", size = 9573917, upload-time = "2025-07-31T18:08:47.038Z" }, + { url = "https://files.pythonhosted.org/packages/b3/69/8b49394de92569419e5e05e82e83df9b749a0ff550d07631ea96ed2eb35a/matplotlib-3.10.5-cp313-cp313t-win_amd64.whl", hash = "sha256:a23193db2e9d64ece69cac0c8231849db7dd77ce59c7b89948cf9d0ce655a3ce", size = 8181034, upload-time = "2025-07-31T18:08:48.943Z" }, + { url = "https://files.pythonhosted.org/packages/47/23/82dc435bb98a2fc5c20dffcac8f0b083935ac28286413ed8835df40d0baa/matplotlib-3.10.5-cp313-cp313t-win_arm64.whl", hash = "sha256:56da3b102cf6da2776fef3e71cd96fcf22103a13594a18ac9a9b31314e0be154", size = 8023337, upload-time = "2025-07-31T18:08:50.791Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e0/26b6cfde31f5383503ee45dcb7e691d45dadf0b3f54639332b59316a97f8/matplotlib-3.10.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:96ef8f5a3696f20f55597ffa91c28e2e73088df25c555f8d4754931515512715", size = 8253591, upload-time = "2025-07-31T18:08:53.254Z" }, + { url = "https://files.pythonhosted.org/packages/c1/89/98488c7ef7ea20ea659af7499628c240a608b337af4be2066d644cfd0a0f/matplotlib-3.10.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:77fab633e94b9da60512d4fa0213daeb76d5a7b05156840c4fd0399b4b818837", size = 8112566, upload-time = "2025-07-31T18:08:55.116Z" }, + { url = "https://files.pythonhosted.org/packages/52/67/42294dfedc82aea55e1a767daf3263aacfb5a125f44ba189e685bab41b6f/matplotlib-3.10.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27f52634315e96b1debbfdc5c416592edcd9c4221bc2f520fd39c33db5d9f202", size = 9513281, upload-time = "2025-07-31T18:08:56.885Z" }, + { url = "https://files.pythonhosted.org/packages/e7/68/f258239e0cf34c2cbc816781c7ab6fca768452e6bf1119aedd2bd4a882a3/matplotlib-3.10.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:525f6e28c485c769d1f07935b660c864de41c37fd716bfa64158ea646f7084bb", size = 9780873, upload-time = "2025-07-31T18:08:59.241Z" }, + { url = "https://files.pythonhosted.org/packages/89/64/f4881554006bd12e4558bd66778bdd15d47b00a1f6c6e8b50f6208eda4b3/matplotlib-3.10.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1f5f3ec4c191253c5f2b7c07096a142c6a1c024d9f738247bfc8e3f9643fc975", size = 9568954, upload-time = "2025-07-31T18:09:01.244Z" }, + { url = "https://files.pythonhosted.org/packages/06/f8/42779d39c3f757e1f012f2dda3319a89fb602bd2ef98ce8faf0281f4febd/matplotlib-3.10.5-cp314-cp314-win_amd64.whl", hash = "sha256:707f9c292c4cd4716f19ab8a1f93f26598222cd931e0cd98fbbb1c5994bf7667", size = 8237465, upload-time = "2025-07-31T18:09:03.206Z" }, + { url = "https://files.pythonhosted.org/packages/cf/f8/153fd06b5160f0cd27c8b9dd797fcc9fb56ac6a0ebf3c1f765b6b68d3c8a/matplotlib-3.10.5-cp314-cp314-win_arm64.whl", hash = "sha256:21a95b9bf408178d372814de7baacd61c712a62cae560b5e6f35d791776f6516", size = 8108898, upload-time = "2025-07-31T18:09:05.231Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/c4b082a382a225fe0d2a73f1f57cf6f6f132308805b493a54c8641006238/matplotlib-3.10.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a6b310f95e1102a8c7c817ef17b60ee5d1851b8c71b63d9286b66b177963039e", size = 8295636, upload-time = "2025-07-31T18:09:07.306Z" }, + { url = "https://files.pythonhosted.org/packages/30/73/2195fa2099718b21a20da82dfc753bf2af58d596b51aefe93e359dd5915a/matplotlib-3.10.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:94986a242747a0605cb3ff1cb98691c736f28a59f8ffe5175acaeb7397c49a5a", size = 8158575, upload-time = "2025-07-31T18:09:09.083Z" }, + { url = "https://files.pythonhosted.org/packages/f6/e9/a08cdb34618a91fa08f75e6738541da5cacde7c307cea18ff10f0d03fcff/matplotlib-3.10.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ff10ea43288f0c8bab608a305dc6c918cc729d429c31dcbbecde3b9f4d5b569", size = 9522815, upload-time = "2025-07-31T18:09:11.191Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/34d8b7e0d1bb6d06ef45db01dfa560d5a67b1c40c0b998ce9ccde934bb09/matplotlib-3.10.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f6adb644c9d040ffb0d3434e440490a66cf73dbfa118a6f79cd7568431f7a012", size = 9783514, upload-time = "2025-07-31T18:09:13.307Z" }, + { url = "https://files.pythonhosted.org/packages/12/09/d330d1e55dcca2e11b4d304cc5227f52e2512e46828d6249b88e0694176e/matplotlib-3.10.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4fa40a8f98428f789a9dcacd625f59b7bc4e3ef6c8c7c80187a7a709475cf592", size = 9573932, upload-time = "2025-07-31T18:09:15.335Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3b/f70258ac729aa004aca673800a53a2b0a26d49ca1df2eaa03289a1c40f81/matplotlib-3.10.5-cp314-cp314t-win_amd64.whl", hash = "sha256:95672a5d628b44207aab91ec20bf59c26da99de12b88f7e0b1fb0a84a86ff959", size = 8322003, upload-time = "2025-07-31T18:09:17.416Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/3601f8ce6d76a7c81c7f25a0e15fde0d6b66226dd187aa6d2838e6374161/matplotlib-3.10.5-cp314-cp314t-win_arm64.whl", hash = "sha256:2efaf97d72629e74252e0b5e3c46813e9eeaa94e011ecf8084a971a31a97f40b", size = 8153849, upload-time = "2025-07-31T18:09:19.673Z" }, + { url = "https://files.pythonhosted.org/packages/e4/eb/7d4c5de49eb78294e1a8e2be8a6ecff8b433e921b731412a56cd1abd3567/matplotlib-3.10.5-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b5fa2e941f77eb579005fb804026f9d0a1082276118d01cc6051d0d9626eaa7f", size = 8222360, upload-time = "2025-07-31T18:09:21.813Z" }, + { url = "https://files.pythonhosted.org/packages/16/8a/e435db90927b66b16d69f8f009498775f4469f8de4d14b87856965e58eba/matplotlib-3.10.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1fc0d2a3241cdcb9daaca279204a3351ce9df3c0e7e621c7e04ec28aaacaca30", size = 8087462, upload-time = "2025-07-31T18:09:23.504Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/06c0e00064362f5647f318e00b435be2ff76a1bdced97c5eaf8347311fbe/matplotlib-3.10.5-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8dee65cb1424b7dc982fe87895b5613d4e691cc57117e8af840da0148ca6c1d7", size = 8659802, upload-time = "2025-07-31T18:09:25.256Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d6/e921be4e1a5f7aca5194e1f016cb67ec294548e530013251f630713e456d/matplotlib-3.10.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:160e125da27a749481eaddc0627962990f6029811dbeae23881833a011a0907f", size = 8233224, upload-time = "2025-07-31T18:09:27.512Z" }, + { url = "https://files.pythonhosted.org/packages/ec/74/a2b9b04824b9c349c8f1b2d21d5af43fa7010039427f2b133a034cb09e59/matplotlib-3.10.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac3d50760394d78a3c9be6b28318fe22b494c4fcf6407e8fd4794b538251899b", size = 8098539, upload-time = "2025-07-31T18:09:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/fc/66/cd29ebc7f6c0d2a15d216fb572573e8fc38bd5d6dec3bd9d7d904c0949f7/matplotlib-3.10.5-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c49465bf689c4d59d174d0c7795fb42a21d4244d11d70e52b8011987367ac61", size = 8672192, upload-time = "2025-07-31T18:09:31.407Z" }, ] [[package]] @@ -1501,7 +1530,7 @@ wheels = [ [[package]] name = "mqt-bench" -version = "2.0.0" +version = "2.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "networkx" }, @@ -1510,9 +1539,9 @@ dependencies = [ { name = "qiskit", extra = ["qasm3-import"] }, { name = "scikit-learn" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/c6/2b9e60596a77eff566dc2dc3ebb0292be2f28cbfecaaa945628f54e50b34/mqt_bench-2.0.0.tar.gz", hash = "sha256:cf9883a806f93f060f5dc7759d87c4a80659a1b726e0d663a831fd6556dc1599", size = 870449, upload-time = "2025-06-24T10:25:39.964Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/c4/0bc70612ec338bf24ae8d94a1319a9151f0618f5b14eb6132cba36b479aa/mqt_bench-2.0.1.tar.gz", hash = "sha256:0e6d9d7c28577e3a8d3ef95a19642d634390f8a620efae9f6087e3360759ce92", size = 890344, upload-time = "2025-07-28T12:34:27.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/2c/b42f4ebdc21f08cd2f056dece821e97f0d69fa31662a254a4072e9e031c8/mqt_bench-2.0.0-py3-none-any.whl", hash = "sha256:c1d1d67f9c2a6ccd61ed7ca6e4f145dffeefde7dc27687e652f7bd52f0bd22e9", size = 71017, upload-time = "2025-06-24T10:25:38.461Z" }, + { url = "https://files.pythonhosted.org/packages/05/22/ac7ab7398708af9f205b595e4f2a1559622d7ddbf9a6f41b2a3f143e4b31/mqt_bench-2.0.1-py3-none-any.whl", hash = "sha256:5e0d0765688aef43ef334967fbb98433f6b56574f54e9ee89c421ead3f1038f7", size = 71008, upload-time = "2025-07-28T12:34:25.713Z" }, ] [[package]] @@ -1534,6 +1563,7 @@ dependencies = [ { name = "scikit-learn" }, { name = "tensorboard" }, { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "torch", version = "2.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12' and 'x86_64' not in platform_machine and sys_platform != 'darwin'" }, { name = "tqdm" }, { name = "typing-extensions" }, ] @@ -1582,7 +1612,7 @@ requires-dist = [ { name = "numpy", marker = "python_full_version >= '3.13'", specifier = ">=2.1" }, { name = "numpy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=1.22,<2" }, { name = "pytket", specifier = ">=1.29.0" }, - { name = "pytket-qiskit", specifier = ">=0.60.0" }, + { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = "!=1.3.2" }, { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.3.2" }, { name = "qiskit-ibm-transpiler", specifier = ">=0.11.1" }, @@ -1591,6 +1621,7 @@ requires-dist = [ { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "tensorboard", specifier = ">=2.17.0" }, { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.2.2,<2.3.0" }, + { name = "torch", marker = "python_full_version >= '3.12' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", specifier = ">=2.4.0" }, { name = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, ] @@ -1763,8 +1794,10 @@ name = "numpy" version = "2.3.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] sdist = { url = "https://files.pythonhosted.org/packages/37/7d/3fec4199c5ffb892bed55cff901e4f39a58c81df9c44c280499e92cad264/numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48", size = 20489306, upload-time = "2025-07-24T21:32:07.553Z" } @@ -2519,7 +2552,7 @@ wheels = [ [[package]] name = "pytket-qiskit" -version = "0.66.0" +version = "0.71.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, @@ -2528,9 +2561,10 @@ dependencies = [ { name = "qiskit" }, { name = "qiskit-aer" }, { name = "qiskit-ibm-runtime" }, + { name = "symengine" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/73/4d/6395c0a6a2e6f08f493b031887aadc2b276d12b21c3b9b6f30036a43b498/pytket_qiskit-0.66.0-py3-none-any.whl", hash = "sha256:15d72ae6190e2280356e64bf387ca2d2d51714c395739b364fe3bbf9bd4bd096", size = 56193, upload-time = "2025-03-26T15:18:24.58Z" }, + { url = "https://files.pythonhosted.org/packages/a0/31/7150385fe20c9d946d73a2251f50630ddf7e612e99f8427d06cb91932e20/pytket_qiskit-0.71.0-py3-none-any.whl", hash = "sha256:4e64f44fdc1cbd4c1f94d4f9de59c7b393ff1cda639c06de5cad01c770fc3000", size = 57187, upload-time = "2025-07-21T09:27:09.443Z" }, ] [[package]] @@ -2610,92 +2644,100 @@ wheels = [ [[package]] name = "pyzmq" -version = "27.0.0" +version = "27.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f1/06/50a4e9648b3e8b992bef8eb632e457307553a89d294103213cfd47b3da69/pyzmq-27.0.0.tar.gz", hash = "sha256:b1f08eeb9ce1510e6939b6e5dcd46a17765e2333daae78ecf4606808442e52cf", size = 280478, upload-time = "2025-06-13T14:09:07.087Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/09/1681d4b047626d352c083770618ac29655ab1f5c20eee31dc94c000b9b7b/pyzmq-27.0.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:b973ee650e8f442ce482c1d99ca7ab537c69098d53a3d046676a484fd710c87a", size = 1329291, upload-time = "2025-06-13T14:06:57.945Z" }, - { url = "https://files.pythonhosted.org/packages/9d/b2/9c9385225fdd54db9506ed8accbb9ea63ca813ba59d43d7f282a6a16a30b/pyzmq-27.0.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:661942bc7cd0223d569d808f2e5696d9cc120acc73bf3e88a1f1be7ab648a7e4", size = 905952, upload-time = "2025-06-13T14:07:03.232Z" }, - { url = "https://files.pythonhosted.org/packages/41/73/333c72c7ec182cdffe25649e3da1c3b9f3cf1cede63cfdc23d1384d4a601/pyzmq-27.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50360fb2a056ffd16e5f4177eee67f1dd1017332ea53fb095fe7b5bf29c70246", size = 666165, upload-time = "2025-06-13T14:07:04.667Z" }, - { url = "https://files.pythonhosted.org/packages/a5/fe/fc7b9c1a50981928e25635a926653cb755364316db59ccd6e79cfb9a0b4f/pyzmq-27.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf209a6dc4b420ed32a7093642843cbf8703ed0a7d86c16c0b98af46762ebefb", size = 853755, upload-time = "2025-06-13T14:07:06.93Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/740ed4b6e8fa160cd19dc5abec8db68f440564b2d5b79c1d697d9862a2f7/pyzmq-27.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c2dace4a7041cca2fba5357a2d7c97c5effdf52f63a1ef252cfa496875a3762d", size = 1654868, upload-time = "2025-06-13T14:07:08.224Z" }, - { url = "https://files.pythonhosted.org/packages/97/00/875b2ecfcfc78ab962a59bd384995186818524ea957dc8ad3144611fae12/pyzmq-27.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:63af72b2955fc77caf0a77444baa2431fcabb4370219da38e1a9f8d12aaebe28", size = 2033443, upload-time = "2025-06-13T14:07:09.653Z" }, - { url = "https://files.pythonhosted.org/packages/60/55/6dd9c470c42d713297c5f2a56f7903dc1ebdb4ab2edda996445c21651900/pyzmq-27.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e8c4adce8e37e75c4215297d7745551b8dcfa5f728f23ce09bf4e678a9399413", size = 1891288, upload-time = "2025-06-13T14:07:11.099Z" }, - { url = "https://files.pythonhosted.org/packages/28/5d/54b0ef50d40d7c65a627f4a4b4127024ba9820f2af8acd933a4d30ae192e/pyzmq-27.0.0-cp310-cp310-win32.whl", hash = "sha256:5d5ef4718ecab24f785794e0e7536436698b459bfbc19a1650ef55280119d93b", size = 567936, upload-time = "2025-06-13T14:07:12.468Z" }, - { url = "https://files.pythonhosted.org/packages/18/ea/dedca4321de748ca48d3bcdb72274d4d54e8d84ea49088d3de174bd45d88/pyzmq-27.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:e40609380480b3d12c30f841323f42451c755b8fece84235236f5fe5ffca8c1c", size = 628686, upload-time = "2025-06-13T14:07:14.051Z" }, - { url = "https://files.pythonhosted.org/packages/d4/a7/fcdeedc306e71e94ac262cba2d02337d885f5cdb7e8efced8e5ffe327808/pyzmq-27.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:6b0397b0be277b46762956f576e04dc06ced265759e8c2ff41a0ee1aa0064198", size = 559039, upload-time = "2025-06-13T14:07:15.289Z" }, - { url = "https://files.pythonhosted.org/packages/44/df/84c630654106d9bd9339cdb564aa941ed41b023a0264251d6743766bb50e/pyzmq-27.0.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:21457825249b2a53834fa969c69713f8b5a79583689387a5e7aed880963ac564", size = 1332718, upload-time = "2025-06-13T14:07:16.555Z" }, - { url = "https://files.pythonhosted.org/packages/c1/8e/f6a5461a07654d9840d256476434ae0ff08340bba562a455f231969772cb/pyzmq-27.0.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1958947983fef513e6e98eff9cb487b60bf14f588dc0e6bf35fa13751d2c8251", size = 908248, upload-time = "2025-06-13T14:07:18.033Z" }, - { url = "https://files.pythonhosted.org/packages/7c/93/82863e8d695a9a3ae424b63662733ae204a295a2627d52af2f62c2cd8af9/pyzmq-27.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0dc628b5493f9a8cd9844b8bee9732ef587ab00002157c9329e4fc0ef4d3afa", size = 668647, upload-time = "2025-06-13T14:07:19.378Z" }, - { url = "https://files.pythonhosted.org/packages/f3/85/15278769b348121eacdbfcbd8c4d40f1102f32fa6af5be1ffc032ed684be/pyzmq-27.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7bbe9e1ed2c8d3da736a15694d87c12493e54cc9dc9790796f0321794bbc91f", size = 856600, upload-time = "2025-06-13T14:07:20.906Z" }, - { url = "https://files.pythonhosted.org/packages/d4/af/1c469b3d479bd095edb28e27f12eee10b8f00b356acbefa6aeb14dd295d1/pyzmq-27.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dc1091f59143b471d19eb64f54bae4f54bcf2a466ffb66fe45d94d8d734eb495", size = 1657748, upload-time = "2025-06-13T14:07:22.549Z" }, - { url = "https://files.pythonhosted.org/packages/8c/f4/17f965d0ee6380b1d6326da842a50e4b8b9699745161207945f3745e8cb5/pyzmq-27.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7011ade88c8e535cf140f8d1a59428676fbbce7c6e54fefce58bf117aefb6667", size = 2034311, upload-time = "2025-06-13T14:07:23.966Z" }, - { url = "https://files.pythonhosted.org/packages/e0/6e/7c391d81fa3149fd759de45d298003de6cfab343fb03e92c099821c448db/pyzmq-27.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2c386339d7e3f064213aede5d03d054b237937fbca6dd2197ac8cf3b25a6b14e", size = 1893630, upload-time = "2025-06-13T14:07:25.899Z" }, - { url = "https://files.pythonhosted.org/packages/0e/e0/eaffe7a86f60e556399e224229e7769b717f72fec0706b70ab2c03aa04cb/pyzmq-27.0.0-cp311-cp311-win32.whl", hash = "sha256:0546a720c1f407b2172cb04b6b094a78773491497e3644863cf5c96c42df8cff", size = 567706, upload-time = "2025-06-13T14:07:27.595Z" }, - { url = "https://files.pythonhosted.org/packages/c9/05/89354a8cffdcce6e547d48adaaf7be17007fc75572123ff4ca90a4ca04fc/pyzmq-27.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:15f39d50bd6c9091c67315ceb878a4f531957b121d2a05ebd077eb35ddc5efed", size = 630322, upload-time = "2025-06-13T14:07:28.938Z" }, - { url = "https://files.pythonhosted.org/packages/fa/07/4ab976d5e1e63976719389cc4f3bfd248a7f5f2bb2ebe727542363c61b5f/pyzmq-27.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c5817641eebb391a2268c27fecd4162448e03538387093cdbd8bf3510c316b38", size = 558435, upload-time = "2025-06-13T14:07:30.256Z" }, - { url = "https://files.pythonhosted.org/packages/93/a7/9ad68f55b8834ede477842214feba6a4c786d936c022a67625497aacf61d/pyzmq-27.0.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:cbabc59dcfaac66655c040dfcb8118f133fb5dde185e5fc152628354c1598e52", size = 1305438, upload-time = "2025-06-13T14:07:31.676Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ee/26aa0f98665a22bc90ebe12dced1de5f3eaca05363b717f6fb229b3421b3/pyzmq-27.0.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:cb0ac5179cba4b2f94f1aa208fbb77b62c4c9bf24dd446278b8b602cf85fcda3", size = 895095, upload-time = "2025-06-13T14:07:33.104Z" }, - { url = "https://files.pythonhosted.org/packages/cf/85/c57e7ab216ecd8aa4cc7e3b83b06cc4e9cf45c87b0afc095f10cd5ce87c1/pyzmq-27.0.0-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53a48f0228eab6cbf69fde3aa3c03cbe04e50e623ef92ae395fce47ef8a76152", size = 651826, upload-time = "2025-06-13T14:07:34.831Z" }, - { url = "https://files.pythonhosted.org/packages/69/9a/9ea7e230feda9400fb0ae0d61d7d6ddda635e718d941c44eeab22a179d34/pyzmq-27.0.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:111db5f395e09f7e775f759d598f43cb815fc58e0147623c4816486e1a39dc22", size = 839750, upload-time = "2025-06-13T14:07:36.553Z" }, - { url = "https://files.pythonhosted.org/packages/08/66/4cebfbe71f3dfbd417011daca267539f62ed0fbc68105357b68bbb1a25b7/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c8878011653dcdc27cc2c57e04ff96f0471e797f5c19ac3d7813a245bcb24371", size = 1641357, upload-time = "2025-06-13T14:07:38.21Z" }, - { url = "https://files.pythonhosted.org/packages/ac/f6/b0f62578c08d2471c791287149cb8c2aaea414ae98c6e995c7dbe008adfb/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:c0ed2c1f335ba55b5fdc964622254917d6b782311c50e138863eda409fbb3b6d", size = 2020281, upload-time = "2025-06-13T14:07:39.599Z" }, - { url = "https://files.pythonhosted.org/packages/37/b9/4f670b15c7498495da9159edc374ec09c88a86d9cd5a47d892f69df23450/pyzmq-27.0.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e918d70862d4cfd4b1c187310015646a14e1f5917922ab45b29f28f345eeb6be", size = 1877110, upload-time = "2025-06-13T14:07:41.027Z" }, - { url = "https://files.pythonhosted.org/packages/66/31/9dee25c226295b740609f0d46db2fe972b23b6f5cf786360980524a3ba92/pyzmq-27.0.0-cp312-abi3-win32.whl", hash = "sha256:88b4e43cab04c3c0f0d55df3b1eef62df2b629a1a369b5289a58f6fa8b07c4f4", size = 559297, upload-time = "2025-06-13T14:07:42.533Z" }, - { url = "https://files.pythonhosted.org/packages/9b/12/52da5509800f7ff2d287b2f2b4e636e7ea0f001181cba6964ff6c1537778/pyzmq-27.0.0-cp312-abi3-win_amd64.whl", hash = "sha256:dce4199bf5f648a902ce37e7b3afa286f305cd2ef7a8b6ec907470ccb6c8b371", size = 619203, upload-time = "2025-06-13T14:07:43.843Z" }, - { url = "https://files.pythonhosted.org/packages/93/6d/7f2e53b19d1edb1eb4f09ec7c3a1f945ca0aac272099eab757d15699202b/pyzmq-27.0.0-cp312-abi3-win_arm64.whl", hash = "sha256:56e46bbb85d52c1072b3f809cc1ce77251d560bc036d3a312b96db1afe76db2e", size = 551927, upload-time = "2025-06-13T14:07:45.51Z" }, - { url = "https://files.pythonhosted.org/packages/19/62/876b27c4ff777db4ceba1c69ea90d3c825bb4f8d5e7cd987ce5802e33c55/pyzmq-27.0.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c36ad534c0c29b4afa088dc53543c525b23c0797e01b69fef59b1a9c0e38b688", size = 1340826, upload-time = "2025-06-13T14:07:46.881Z" }, - { url = "https://files.pythonhosted.org/packages/43/69/58ef8f4f59d3bcd505260c73bee87b008850f45edca40ddaba54273c35f4/pyzmq-27.0.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:67855c14173aec36395d7777aaba3cc527b393821f30143fd20b98e1ff31fd38", size = 897283, upload-time = "2025-06-13T14:07:49.562Z" }, - { url = "https://files.pythonhosted.org/packages/43/15/93a0d0396700a60475ad3c5d42c5f1c308d3570bc94626b86c71ef9953e0/pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8617c7d43cd8ccdb62aebe984bfed77ca8f036e6c3e46dd3dddda64b10f0ab7a", size = 660567, upload-time = "2025-06-13T14:07:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/0e/b3/fe055513e498ca32f64509abae19b9c9eb4d7c829e02bd8997dd51b029eb/pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:67bfbcbd0a04c575e8103a6061d03e393d9f80ffdb9beb3189261e9e9bc5d5e9", size = 847681, upload-time = "2025-06-13T14:07:52.77Z" }, - { url = "https://files.pythonhosted.org/packages/b6/4f/ff15300b00b5b602191f3df06bbc8dd4164e805fdd65bb77ffbb9c5facdc/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5cd11d46d7b7e5958121b3eaf4cd8638eff3a720ec527692132f05a57f14341d", size = 1650148, upload-time = "2025-06-13T14:07:54.178Z" }, - { url = "https://files.pythonhosted.org/packages/c4/6f/84bdfff2a224a6f26a24249a342e5906993c50b0761e311e81b39aef52a7/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:b801c2e40c5aa6072c2f4876de8dccd100af6d9918d4d0d7aa54a1d982fd4f44", size = 2023768, upload-time = "2025-06-13T14:07:55.714Z" }, - { url = "https://files.pythonhosted.org/packages/64/39/dc2db178c26a42228c5ac94a9cc595030458aa64c8d796a7727947afbf55/pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:20d5cb29e8c5f76a127c75b6e7a77e846bc4b655c373baa098c26a61b7ecd0ef", size = 1885199, upload-time = "2025-06-13T14:07:57.166Z" }, - { url = "https://files.pythonhosted.org/packages/c7/21/dae7b06a1f8cdee5d8e7a63d99c5d129c401acc40410bef2cbf42025e26f/pyzmq-27.0.0-cp313-cp313t-win32.whl", hash = "sha256:a20528da85c7ac7a19b7384e8c3f8fa707841fd85afc4ed56eda59d93e3d98ad", size = 575439, upload-time = "2025-06-13T14:07:58.959Z" }, - { url = "https://files.pythonhosted.org/packages/eb/bc/1709dc55f0970cf4cb8259e435e6773f9946f41a045c2cb90e870b7072da/pyzmq-27.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d8229f2efece6a660ee211d74d91dbc2a76b95544d46c74c615e491900dc107f", size = 639933, upload-time = "2025-06-13T14:08:00.777Z" }, - { url = "https://files.pythonhosted.org/packages/09/6f/be6523a7f3821c0b5370912ef02822c028611360e0d206dd945bdbf9eaef/pyzmq-27.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:656c1866505a5735d0660b7da6d7147174bbf59d4975fc2b7f09f43c9bc25745", size = 835950, upload-time = "2025-06-13T14:08:35Z" }, - { url = "https://files.pythonhosted.org/packages/c6/1e/a50fdd5c15018de07ab82a61bc460841be967ee7bbe7abee3b714d66f7ac/pyzmq-27.0.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74175b9e12779382432dd1d1f5960ebe7465d36649b98a06c6b26be24d173fab", size = 799876, upload-time = "2025-06-13T14:08:36.849Z" }, - { url = "https://files.pythonhosted.org/packages/88/a1/89eb5b71f5a504f8f887aceb8e1eb3626e00c00aa8085381cdff475440dc/pyzmq-27.0.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8c6de908465697a8708e4d6843a1e884f567962fc61eb1706856545141d0cbb", size = 567400, upload-time = "2025-06-13T14:08:38.95Z" }, - { url = "https://files.pythonhosted.org/packages/56/aa/4571dbcff56cfb034bac73fde8294e123c975ce3eea89aff31bf6dc6382b/pyzmq-27.0.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c644aaacc01d0df5c7072826df45e67301f191c55f68d7b2916d83a9ddc1b551", size = 747031, upload-time = "2025-06-13T14:08:40.413Z" }, - { url = "https://files.pythonhosted.org/packages/46/e0/d25f30fe0991293c5b2f5ef3b070d35fa6d57c0c7428898c3ab4913d0297/pyzmq-27.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:10f70c1d9a446a85013a36871a296007f6fe4232b530aa254baf9da3f8328bc0", size = 544726, upload-time = "2025-06-13T14:08:41.997Z" }, - { url = "https://files.pythonhosted.org/packages/98/a6/92394373b8dbc1edc9d53c951e8d3989d518185174ee54492ec27711779d/pyzmq-27.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd1dc59763effd1576f8368047c9c31468fce0af89d76b5067641137506792ae", size = 835948, upload-time = "2025-06-13T14:08:43.516Z" }, - { url = "https://files.pythonhosted.org/packages/56/f3/4dc38d75d9995bfc18773df3e41f2a2ca9b740b06f1a15dbf404077e7588/pyzmq-27.0.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:60e8cc82d968174650c1860d7b716366caab9973787a1c060cf8043130f7d0f7", size = 799874, upload-time = "2025-06-13T14:08:45.017Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ba/64af397e0f421453dc68e31d5e0784d554bf39013a2de0872056e96e58af/pyzmq-27.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14fe7aaac86e4e93ea779a821967360c781d7ac5115b3f1a171ced77065a0174", size = 567400, upload-time = "2025-06-13T14:08:46.855Z" }, - { url = "https://files.pythonhosted.org/packages/63/87/ec956cbe98809270b59a22891d5758edae147a258e658bf3024a8254c855/pyzmq-27.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6ad0562d4e6abb785be3e4dd68599c41be821b521da38c402bc9ab2a8e7ebc7e", size = 747031, upload-time = "2025-06-13T14:08:48.419Z" }, - { url = "https://files.pythonhosted.org/packages/be/8a/4a3764a68abc02e2fbb0668d225b6fda5cd39586dd099cee8b2ed6ab0452/pyzmq-27.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:9df43a2459cd3a3563404c1456b2c4c69564daa7dbaf15724c09821a3329ce46", size = 544726, upload-time = "2025-06-13T14:08:49.903Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/30/5f/557d2032a2f471edbcc227da724c24a1c05887b5cda1e3ae53af98b9e0a5/pyzmq-27.0.1.tar.gz", hash = "sha256:45c549204bc20e7484ffd2555f6cf02e572440ecf2f3bdd60d4404b20fddf64b", size = 281158, upload-time = "2025-08-03T05:05:40.352Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/0b/ccf4d0b152a6a11f0fc01e73978202fe0e8fe0e91e20941598e83a170bee/pyzmq-27.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:90a4da42aa322de8a3522461e3b5fe999935763b27f69a02fced40f4e3cf9682", size = 1329293, upload-time = "2025-08-03T05:02:56.001Z" }, + { url = "https://files.pythonhosted.org/packages/bc/76/48706d291951b1300d3cf985e503806901164bf1581f27c4b6b22dbab2fa/pyzmq-27.0.1-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:e648dca28178fc879c814cf285048dd22fd1f03e1104101106505ec0eea50a4d", size = 905953, upload-time = "2025-08-03T05:02:59.061Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8a/df3135b96712068d184c53120c7dbf3023e5e362a113059a4f85cd36c6a0/pyzmq-27.0.1-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bca8abc31799a6f3652d13f47e0b0e1cab76f9125f2283d085a3754f669b607", size = 666165, upload-time = "2025-08-03T05:03:00.789Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ed/341a7148e08d2830f480f53ab3d136d88fc5011bb367b516d95d0ebb46dd/pyzmq-27.0.1-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:092f4011b26d6b0201002f439bd74b38f23f3aefcb358621bdc3b230afc9b2d5", size = 853756, upload-time = "2025-08-03T05:03:03.347Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bc/d26fe010477c3e901f0f5a3e70446950dde9aa217f1d1a13534eb0fccfe5/pyzmq-27.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f02f30a4a6b3efe665ab13a3dd47109d80326c8fd286311d1ba9f397dc5f247", size = 1654870, upload-time = "2025-08-03T05:03:05.331Z" }, + { url = "https://files.pythonhosted.org/packages/32/21/9b488086bf3f55b2eb26db09007a3962f62f3b81c5c6295a6ff6aaebd69c/pyzmq-27.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f293a1419266e3bf3557d1f8778f9e1ffe7e6b2c8df5c9dca191caf60831eb74", size = 2033444, upload-time = "2025-08-03T05:03:07.318Z" }, + { url = "https://files.pythonhosted.org/packages/3d/53/85b64a792223cd43393d25e03c8609df41aac817ea5ce6a27eceeed433ee/pyzmq-27.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ce181dd1a7c6c012d0efa8ab603c34b5ee9d86e570c03415bbb1b8772eeb381c", size = 1891289, upload-time = "2025-08-03T05:03:08.96Z" }, + { url = "https://files.pythonhosted.org/packages/23/5b/078aae8fe1c4cdba1a77a598870c548fd52b4d4a11e86b8116bbef47d9f3/pyzmq-27.0.1-cp310-cp310-win32.whl", hash = "sha256:f65741cc06630652e82aa68ddef4986a3ab9073dd46d59f94ce5f005fa72037c", size = 566693, upload-time = "2025-08-03T05:03:10.711Z" }, + { url = "https://files.pythonhosted.org/packages/24/e1/4471fff36416ebf1ffe43577b9c7dcf2ff4798f2171f0d169640a48d2305/pyzmq-27.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:44909aa3ed2234d69fe81e1dade7be336bcfeab106e16bdaa3318dcde4262b93", size = 631649, upload-time = "2025-08-03T05:03:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/e8/4c/8edac8dd56f223124aa40403d2c097bbad9b0e2868a67cad9a2a029863aa/pyzmq-27.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:4401649bfa0a38f0f8777f8faba7cd7eb7b5b8ae2abc7542b830dd09ad4aed0d", size = 559274, upload-time = "2025-08-03T05:03:13.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/18/a8e0da6ababbe9326116fb1c890bf1920eea880e8da621afb6bc0f39a262/pyzmq-27.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:9729190bd770314f5fbba42476abf6abe79a746eeda11d1d68fd56dd70e5c296", size = 1332721, upload-time = "2025-08-03T05:03:15.237Z" }, + { url = "https://files.pythonhosted.org/packages/75/a4/9431ba598651d60ebd50dc25755402b770322cf8432adcc07d2906e53a54/pyzmq-27.0.1-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:696900ef6bc20bef6a242973943574f96c3f97d2183c1bd3da5eea4f559631b1", size = 908249, upload-time = "2025-08-03T05:03:16.933Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/e624e1793689e4e685d2ee21c40277dd4024d9d730af20446d88f69be838/pyzmq-27.0.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f96a63aecec22d3f7fdea3c6c98df9e42973f5856bb6812c3d8d78c262fee808", size = 668649, upload-time = "2025-08-03T05:03:18.49Z" }, + { url = "https://files.pythonhosted.org/packages/6c/29/0652a39d4e876e0d61379047ecf7752685414ad2e253434348246f7a2a39/pyzmq-27.0.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c512824360ea7490390566ce00bee880e19b526b312b25cc0bc30a0fe95cb67f", size = 856601, upload-time = "2025-08-03T05:03:20.194Z" }, + { url = "https://files.pythonhosted.org/packages/36/2d/8d5355d7fc55bb6e9c581dd74f58b64fa78c994079e3a0ea09b1b5627cde/pyzmq-27.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dfb2bb5e0f7198eaacfb6796fb0330afd28f36d985a770745fba554a5903595a", size = 1657750, upload-time = "2025-08-03T05:03:22.055Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f4/cd032352d5d252dc6f5ee272a34b59718ba3af1639a8a4ef4654f9535cf5/pyzmq-27.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4f6886c59ba93ffde09b957d3e857e7950c8fe818bd5494d9b4287bc6d5bc7f1", size = 2034312, upload-time = "2025-08-03T05:03:23.578Z" }, + { url = "https://files.pythonhosted.org/packages/e4/1a/c050d8b6597200e97a4bd29b93c769d002fa0b03083858227e0376ad59bc/pyzmq-27.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b99ea9d330e86ce1ff7f2456b33f1bf81c43862a5590faf4ef4ed3a63504bdab", size = 1893632, upload-time = "2025-08-03T05:03:25.167Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/173ce21d5097e7fcf284a090e8beb64fc683c6582b1f00fa52b1b7e867ce/pyzmq-27.0.1-cp311-cp311-win32.whl", hash = "sha256:571f762aed89025ba8cdcbe355fea56889715ec06d0264fd8b6a3f3fa38154ed", size = 566587, upload-time = "2025-08-03T05:03:26.769Z" }, + { url = "https://files.pythonhosted.org/packages/53/ab/22bd33e7086f0a2cc03a5adabff4bde414288bb62a21a7820951ef86ec20/pyzmq-27.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee16906c8025fa464bea1e48128c048d02359fb40bebe5333103228528506530", size = 632873, upload-time = "2025-08-03T05:03:28.685Z" }, + { url = "https://files.pythonhosted.org/packages/90/14/3e59b4a28194285ceeff725eba9aa5ba8568d1cb78aed381dec1537c705a/pyzmq-27.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:ba068f28028849da725ff9185c24f832ccf9207a40f9b28ac46ab7c04994bd41", size = 558918, upload-time = "2025-08-03T05:03:30.085Z" }, + { url = "https://files.pythonhosted.org/packages/0e/9b/c0957041067c7724b310f22c398be46399297c12ed834c3bc42200a2756f/pyzmq-27.0.1-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:af7ebce2a1e7caf30c0bb64a845f63a69e76a2fadbc1cac47178f7bb6e657bdd", size = 1305432, upload-time = "2025-08-03T05:03:32.177Z" }, + { url = "https://files.pythonhosted.org/packages/8e/55/bd3a312790858f16b7def3897a0c3eb1804e974711bf7b9dcb5f47e7f82c/pyzmq-27.0.1-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:8f617f60a8b609a13099b313e7e525e67f84ef4524b6acad396d9ff153f6e4cd", size = 895095, upload-time = "2025-08-03T05:03:33.918Z" }, + { url = "https://files.pythonhosted.org/packages/20/50/fc384631d8282809fb1029a4460d2fe90fa0370a0e866a8318ed75c8d3bb/pyzmq-27.0.1-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d59dad4173dc2a111f03e59315c7bd6e73da1a9d20a84a25cf08325b0582b1a", size = 651826, upload-time = "2025-08-03T05:03:35.818Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0a/2356305c423a975000867de56888b79e44ec2192c690ff93c3109fd78081/pyzmq-27.0.1-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f5b6133c8d313bde8bd0d123c169d22525300ff164c2189f849de495e1344577", size = 839751, upload-time = "2025-08-03T05:03:37.265Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1b/81e95ad256ca7e7ccd47f5294c1c6da6e2b64fbace65b84fe8a41470342e/pyzmq-27.0.1-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:58cca552567423f04d06a075f4b473e78ab5bdb906febe56bf4797633f54aa4e", size = 1641359, upload-time = "2025-08-03T05:03:38.799Z" }, + { url = "https://files.pythonhosted.org/packages/50/63/9f50ec965285f4e92c265c8f18344e46b12803666d8b73b65d254d441435/pyzmq-27.0.1-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:4b9d8e26fb600d0d69cc9933e20af08552e97cc868a183d38a5c0d661e40dfbb", size = 2020281, upload-time = "2025-08-03T05:03:40.338Z" }, + { url = "https://files.pythonhosted.org/packages/02/4a/19e3398d0dc66ad2b463e4afa1fc541d697d7bc090305f9dfb948d3dfa29/pyzmq-27.0.1-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2329f0c87f0466dce45bba32b63f47018dda5ca40a0085cc5c8558fea7d9fc55", size = 1877112, upload-time = "2025-08-03T05:03:42.012Z" }, + { url = "https://files.pythonhosted.org/packages/bf/42/c562e9151aa90ed1d70aac381ea22a929d6b3a2ce4e1d6e2e135d34fd9c6/pyzmq-27.0.1-cp312-abi3-win32.whl", hash = "sha256:57bb92abdb48467b89c2d21da1ab01a07d0745e536d62afd2e30d5acbd0092eb", size = 558177, upload-time = "2025-08-03T05:03:43.979Z" }, + { url = "https://files.pythonhosted.org/packages/40/96/5c50a7d2d2b05b19994bf7336b97db254299353dd9b49b565bb71b485f03/pyzmq-27.0.1-cp312-abi3-win_amd64.whl", hash = "sha256:ff3f8757570e45da7a5bedaa140489846510014f7a9d5ee9301c61f3f1b8a686", size = 618923, upload-time = "2025-08-03T05:03:45.438Z" }, + { url = "https://files.pythonhosted.org/packages/13/33/1ec89c8f21c89d21a2eaff7def3676e21d8248d2675705e72554fb5a6f3f/pyzmq-27.0.1-cp312-abi3-win_arm64.whl", hash = "sha256:df2c55c958d3766bdb3e9d858b911288acec09a9aab15883f384fc7180df5bed", size = 552358, upload-time = "2025-08-03T05:03:46.887Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a0/f26e276211ec8090a4d11e4ec70eb8a8b15781e591c1d44ce62f372963a0/pyzmq-27.0.1-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:497bd8af534ae55dc4ef67eebd1c149ff2a0b0f1e146db73c8b5a53d83c1a5f5", size = 1122287, upload-time = "2025-08-03T05:03:48.838Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d8/af4b507e4f7eeea478cc8ee873995a6fd55582bfb99140593ed460e1db3c/pyzmq-27.0.1-cp313-cp313-android_24_x86_64.whl", hash = "sha256:a066ea6ad6218b4c233906adf0ae67830f451ed238419c0db609310dd781fbe7", size = 1155756, upload-time = "2025-08-03T05:03:50.907Z" }, + { url = "https://files.pythonhosted.org/packages/ac/55/37fae0013e11f88681da42698e550b08a316d608242551f65095cc99232a/pyzmq-27.0.1-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:72d235d6365ca73d8ce92f7425065d70f5c1e19baa458eb3f0d570e425b73a96", size = 1340826, upload-time = "2025-08-03T05:03:52.568Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e4/3a87854c64b26fcf63a9d1b6f4382bd727d4797c772ceb334a97b7489be9/pyzmq-27.0.1-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:313a7b374e3dc64848644ca348a51004b41726f768b02e17e689f1322366a4d9", size = 897283, upload-time = "2025-08-03T05:03:54.167Z" }, + { url = "https://files.pythonhosted.org/packages/17/3e/4296c6b0ad2d07be11ae1395dccf9cae48a0a655cf9be1c3733ad2b591d1/pyzmq-27.0.1-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:119ce8590409702394f959c159d048002cbed2f3c0645ec9d6a88087fc70f0f1", size = 660565, upload-time = "2025-08-03T05:03:56.152Z" }, + { url = "https://files.pythonhosted.org/packages/72/41/a33ba3aa48b45b23c4cd4ac49aafde46f3e0f81939f2bfb3b6171a437122/pyzmq-27.0.1-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:45c3e00ce16896ace2cd770ab9057a7cf97d4613ea5f2a13f815141d8b6894b9", size = 847680, upload-time = "2025-08-03T05:03:57.696Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/bf2350bb25b3b58d2e5b5d2290ffab0e923f0cc6d02288d3fbf4baa6e4d1/pyzmq-27.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:678e50ec112bdc6df5a83ac259a55a4ba97a8b314c325ab26b3b5b071151bc61", size = 1650151, upload-time = "2025-08-03T05:03:59.387Z" }, + { url = "https://files.pythonhosted.org/packages/f7/1a/a5a07c54890891344a8ddc3d5ab320dd3c4e39febb6e4472546e456d5157/pyzmq-27.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d0b96c30be9f9387b18b18b6133c75a7b1b0065da64e150fe1feb5ebf31ece1c", size = 2023766, upload-time = "2025-08-03T05:04:01.883Z" }, + { url = "https://files.pythonhosted.org/packages/62/5e/514dcff08f02c6c8a45a6e23621901139cf853be7ac5ccd0b9407c3aa3de/pyzmq-27.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88dc92d9eb5ea4968123e74db146d770b0c8d48f0e2bfb1dbc6c50a8edb12d64", size = 1885195, upload-time = "2025-08-03T05:04:03.923Z" }, + { url = "https://files.pythonhosted.org/packages/c8/91/87f74f98a487fbef0b115f6025e4a295129fd56b2b633a03ba7d5816ecc2/pyzmq-27.0.1-cp313-cp313t-win32.whl", hash = "sha256:6dcbcb34f5c9b0cefdfc71ff745459241b7d3cda5b27c7ad69d45afc0821d1e1", size = 574213, upload-time = "2025-08-03T05:04:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/e6/d7/07f7d0d7f4c81e08be7b60e52ff2591c557377c017f96204d33d5fca1b07/pyzmq-27.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9fd0fda730461f510cfd9a40fafa5355d65f5e3dbdd8d6dfa342b5b3f5d1949", size = 640202, upload-time = "2025-08-03T05:04:07.439Z" }, + { url = "https://files.pythonhosted.org/packages/ab/83/21d66bcef6fb803647a223cbde95111b099e2176277c0cbc8b099c485510/pyzmq-27.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:56a3b1853f3954ec1f0e91085f1350cc57d18f11205e4ab6e83e4b7c414120e0", size = 561514, upload-time = "2025-08-03T05:04:09.071Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0b/d5ea75cf46b52cdce85a85200c963cb498932953df443892238be49b1a01/pyzmq-27.0.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:f98f6b7787bd2beb1f0dde03f23a0621a0c978edf673b7d8f5e7bc039cbe1b60", size = 1340836, upload-time = "2025-08-03T05:04:10.774Z" }, + { url = "https://files.pythonhosted.org/packages/be/4c/0dbce882550e17db6846b29e9dc242aea7590e7594e1ca5043e8e58fff2d/pyzmq-27.0.1-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:351bf5d8ca0788ca85327fda45843b6927593ff4c807faee368cc5aaf9f809c2", size = 897236, upload-time = "2025-08-03T05:04:13.221Z" }, + { url = "https://files.pythonhosted.org/packages/1b/22/461e131cf16b8814f3c356fa1ea0912697dbc4c64cddf01f7756ec704c1e/pyzmq-27.0.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5268a5a9177afff53dc6d70dffe63114ba2a6e7b20d9411cc3adeba09eeda403", size = 660374, upload-time = "2025-08-03T05:04:15.032Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0c/bbd65a814395bf4fc3e57c6c13af27601c07e4009bdfb75ebcf500537bbd/pyzmq-27.0.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a4aca06ba295aa78bec9b33ec028d1ca08744c36294338c41432b7171060c808", size = 847497, upload-time = "2025-08-03T05:04:16.967Z" }, + { url = "https://files.pythonhosted.org/packages/1e/df/3d1f4a03b561d824cbd491394f67591957e2f1acf6dc85d96f970312a76a/pyzmq-27.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1c363c6dc66352331d5ad64bb838765c6692766334a6a02fdb05e76bd408ae18", size = 1650028, upload-time = "2025-08-03T05:04:19.398Z" }, + { url = "https://files.pythonhosted.org/packages/41/c9/a3987540f59a412bdaae3f362f78e00e6769557a598c63b7e32956aade5a/pyzmq-27.0.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:87aebf4acd7249bdff8d3df03aed4f09e67078e6762cfe0aecf8d0748ff94cde", size = 2023808, upload-time = "2025-08-03T05:04:21.145Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a5/c388f4cd80498a8eaef7535f2a8eaca0a35b82b87a0b47fa1856fc135004/pyzmq-27.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e4f22d67756518d71901edf73b38dc0eb4765cce22c8fe122cc81748d425262b", size = 1884970, upload-time = "2025-08-03T05:04:22.908Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ac/b2a89a1ed90526a1b9a260cdc5cd42f055fd44ee8d2a59902b5ac35ddeb1/pyzmq-27.0.1-cp314-cp314t-win32.whl", hash = "sha256:8c62297bc7aea2147b472ca5ca2b4389377ad82898c87cabab2a94aedd75e337", size = 586905, upload-time = "2025-08-03T05:04:24.492Z" }, + { url = "https://files.pythonhosted.org/packages/68/62/7aa5ea04e836f7a788b2a67405f83011cef59ca76d7bac91d1fc9a0476da/pyzmq-27.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bee5248d5ec9223545f8cc4f368c2d571477ae828c99409125c3911511d98245", size = 660503, upload-time = "2025-08-03T05:04:26.382Z" }, + { url = "https://files.pythonhosted.org/packages/89/32/3836ed85947b06f1d67c07ce16c00b0cf8c053ab0b249d234f9f81ff95ff/pyzmq-27.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0fc24bf45e4a454e55ef99d7f5c8b8712539200ce98533af25a5bfa954b6b390", size = 575098, upload-time = "2025-08-03T05:04:27.974Z" }, + { url = "https://files.pythonhosted.org/packages/6f/87/fc96f224dd99070fe55d0afc37ac08d7d4635d434e3f9425b232867e01b9/pyzmq-27.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:544b995a6a1976fad5d7ff01409b4588f7608ccc41be72147700af91fd44875d", size = 835950, upload-time = "2025-08-03T05:05:04.193Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b6/802d96017f176c3a7285603d9ed2982550095c136c6230d3e0b53f52c7e5/pyzmq-27.0.1-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0f772eea55cccce7f45d6ecdd1d5049c12a77ec22404f6b892fae687faa87bee", size = 799876, upload-time = "2025-08-03T05:05:06.263Z" }, + { url = "https://files.pythonhosted.org/packages/4e/52/49045c6528007cce385f218f3a674dc84fc8b3265330d09e57c0a59b41f4/pyzmq-27.0.1-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9d63d66059114a6756d09169c9209ffceabacb65b9cb0f66e6fc344b20b73e6", size = 567402, upload-time = "2025-08-03T05:05:08.028Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fe/c29ac0d5a817543ecf0cb18f17195805bad0da567a1c64644aacf11b2779/pyzmq-27.0.1-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1da8e645c655d86f0305fb4c65a0d848f461cd90ee07d21f254667287b5dbe50", size = 747030, upload-time = "2025-08-03T05:05:10.116Z" }, + { url = "https://files.pythonhosted.org/packages/17/d1/cc1fbfb65b4042016e4e035b2548cdfe0945c817345df83aa2d98490e7fc/pyzmq-27.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1843fd0daebcf843fe6d4da53b8bdd3fc906ad3e97d25f51c3fed44436d82a49", size = 544567, upload-time = "2025-08-03T05:05:11.856Z" }, + { url = "https://files.pythonhosted.org/packages/b4/1a/49f66fe0bc2b2568dd4280f1f520ac8fafd73f8d762140e278d48aeaf7b9/pyzmq-27.0.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7fb0ee35845bef1e8c4a152d766242164e138c239e3182f558ae15cb4a891f94", size = 835949, upload-time = "2025-08-03T05:05:13.798Z" }, + { url = "https://files.pythonhosted.org/packages/49/94/443c1984b397eab59b14dd7ae8bc2ac7e8f32dbc646474453afcaa6508c4/pyzmq-27.0.1-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f379f11e138dfd56c3f24a04164f871a08281194dd9ddf656a278d7d080c8ad0", size = 799875, upload-time = "2025-08-03T05:05:15.632Z" }, + { url = "https://files.pythonhosted.org/packages/30/f1/fd96138a0f152786a2ba517e9c6a8b1b3516719e412a90bb5d8eea6b660c/pyzmq-27.0.1-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b978c0678cffbe8860ec9edc91200e895c29ae1ac8a7085f947f8e8864c489fb", size = 567403, upload-time = "2025-08-03T05:05:17.326Z" }, + { url = "https://files.pythonhosted.org/packages/16/57/34e53ef2b55b1428dac5aabe3a974a16c8bda3bf20549ba500e3ff6cb426/pyzmq-27.0.1-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ebccf0d760bc92a4a7c751aeb2fef6626144aace76ee8f5a63abeb100cae87f", size = 747032, upload-time = "2025-08-03T05:05:19.074Z" }, + { url = "https://files.pythonhosted.org/packages/81/b7/769598c5ae336fdb657946950465569cf18803140fe89ce466d7f0a57c11/pyzmq-27.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:77fed80e30fa65708546c4119840a46691290efc231f6bfb2ac2a39b52e15811", size = 544566, upload-time = "2025-08-03T05:05:20.798Z" }, ] [[package]] name = "qiskit" -version = "1.4.3" +version = "2.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, - { name = "python-dateutil" }, { name = "rustworkx" }, { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "scipy", version = "1.16.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "stevedore" }, - { name = "symengine" }, - { name = "sympy" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/ac/25993f01e39cf04c9dccfd83f9b0817b5b8b1766f4afb8c34e6fba85155f/qiskit-1.4.3.tar.gz", hash = "sha256:e4e311190c159578f253d219dc860241ccb71955ca08725bb092c74cf7fbdac5", size = 3939859, upload-time = "2025-05-12T15:28:05.09Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/97/903041c27db9105f5036a579b2b7ee2a0caa21c6061fa29e0ccbd35aa19a/qiskit-2.1.1.tar.gz", hash = "sha256:148f62d314cd138a1f4da305c6293b19c73115323e77123b13a048cdcbc1fcdd", size = 3600302, upload-time = "2025-07-10T21:30:11.665Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/66/d5/126a6ddc7a9138b436cfee3772c5b082ea8f8216feed729f02c5bda32d66/qiskit-1.4.3-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:65caf291bbe93f136b85281cb4a807c138fc4315fc17bdda9382cb4bfa18abdf", size = 6570998, upload-time = "2025-05-12T15:27:51.659Z" }, - { url = "https://files.pythonhosted.org/packages/67/95/c4bf1fe91c456570c9536e5505ccd878f358f4b8e6b06c8fd8cbc09093a0/qiskit-1.4.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:6e9f41eca2f4d522f59e48a47eb8b81ed3fdd35f56cefb41cc0db47768ccde47", size = 6251292, upload-time = "2025-05-12T15:27:53.929Z" }, - { url = "https://files.pythonhosted.org/packages/23/70/713fae76998831e9cb458e3605a9429915b9f9fbb92244c8699903868be2/qiskit-1.4.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a04c6baca379bae8e6fc626bd06f0dda3f2ee7961205839b5a431b7f8d1e3978", size = 6396599, upload-time = "2025-05-12T18:02:22.029Z" }, - { url = "https://files.pythonhosted.org/packages/d6/93/6cadc22a5184e4e868c28dd6a83beacf6e4641088f106e3cd97e0cd160a8/qiskit-1.4.3-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ca6eeaf29ae2cf3789e7474b062845c59c6e4164276569949f9170cfcaec6b1", size = 6730964, upload-time = "2025-05-12T15:27:55.962Z" }, - { url = "https://files.pythonhosted.org/packages/ef/9c/53a7fd3a18ec3526e56fa68d9af1a164ba4cea2302a03be7b621678b1694/qiskit-1.4.3-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc82934e5b5192a75adca57bfa8194166e6bce1023da3b82e02db6c279a5d0fc", size = 6801019, upload-time = "2025-05-12T18:02:24.857Z" }, - { url = "https://files.pythonhosted.org/packages/40/a2/1355e3a8a00f9310ea80ab5887095bd3122918c8a61d62895e6519e442c0/qiskit-1.4.3-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03355819fb9747a937bfffb0aba59d44c4654536b87c62dcd00d4e4e1550190f", size = 7895620, upload-time = "2025-05-12T18:02:27.104Z" }, - { url = "https://files.pythonhosted.org/packages/85/35/a442b69b1507112f4fba392354d933f1ef65f66dc72bfce0c03be27f70c7/qiskit-1.4.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d90b25ad017839b0bf1b5d05d8bd4066b7f83e3c14839947994f5fd56a5f5e2", size = 6762841, upload-time = "2025-05-12T15:27:58.379Z" }, - { url = "https://files.pythonhosted.org/packages/f1/f8/c9d116275bec7d0942f364ed6461b384e2ccd1c6bb5df8fe5d998d24ae41/qiskit-1.4.3-cp39-abi3-win32.whl", hash = "sha256:74cb30e34189ca9c1263994705a0cf8d97cead5f7375dedab3be4e783173785d", size = 6138538, upload-time = "2025-05-12T15:28:00.754Z" }, - { url = "https://files.pythonhosted.org/packages/ae/a7/7f736138e67f3f89e4a8b42bb480a9dcd582da9a87f4d723a3c4221766b0/qiskit-1.4.3-cp39-abi3-win_amd64.whl", hash = "sha256:554b5ad8c6198881923998fd0124660eec534c985c731d1e3c09c6421377c29e", size = 6517946, upload-time = "2025-05-12T15:28:03.189Z" }, + { url = "https://files.pythonhosted.org/packages/76/3a/26a99184f830be25a14ef7cbc40f19b98721ac018aa0c4db18c5dedc774c/qiskit-2.1.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:00f8fe1980a80e8e79e01352f2502cd3ca4fe89d07872bc9a244ba9cba304a7d", size = 7283884, upload-time = "2025-07-10T21:30:02.576Z" }, + { url = "https://files.pythonhosted.org/packages/60/a1/2a63ab52a5166346599df7bec2e41fd2be9876ccf01637c73603beebdcb5/qiskit-2.1.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e00985d1b348bf8cc60b686a64a150af2043538e81a61b48400ff71064588fdd", size = 6817779, upload-time = "2025-07-10T21:30:04.513Z" }, + { url = "https://files.pythonhosted.org/packages/ba/87/1a184f6dcd614f57362d9b0be1c718ff857c1a3d69ca0f426c84adda6755/qiskit-2.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:10f546148c86fd15cdbc68270e1d3937a021bd718779dff95f912c8b7cfad7bd", size = 7437467, upload-time = "2025-07-10T21:30:06.524Z" }, + { url = "https://files.pythonhosted.org/packages/82/d7/d0fc92d20b266692db8aedc5e259a2d4cff76613ec155178f855144c7a71/qiskit-2.1.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3765cef67ccc8b3d54b86ede2266c282039da045be1b10e64660a4bbf815680", size = 7696275, upload-time = "2025-07-11T13:15:14.672Z" }, + { url = "https://files.pythonhosted.org/packages/ba/30/ba384695bc9c9cb5795ef3ab47f33eb579460dc928115918d4eb0046ae9f/qiskit-2.1.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca95a1ab710eb3e0fc65dd876734b5c6fc6df1bb78249f86913d77ed1984983f", size = 7411176, upload-time = "2025-07-11T13:15:16.62Z" }, + { url = "https://files.pythonhosted.org/packages/75/dc/551c6afe0aa087ebe53988173290904ded5bf93e56b22503d8311d421d82/qiskit-2.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b41c66958c2e0550bc1047524cd754dce2277bea0a1db1085c052cc5bb07ec6", size = 7458353, upload-time = "2025-07-10T21:30:08.223Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/988791f56e6ab2999e1a4c7e60831b0f02c3e29a467400bced501ce6b637/qiskit-2.1.1-cp39-abi3-win_amd64.whl", hash = "sha256:e7225798221ecf0c8a5cf2e96c37d6d9d00674a412e8c397542fe387909b80db", size = 7234838, upload-time = "2025-07-10T21:30:10.121Z" }, ] [package.optional-dependencies] @@ -3073,8 +3115,10 @@ name = "sb3-contrib" version = "2.7.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", ] @@ -3192,9 +3236,11 @@ name = "scipy" version = "1.16.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -3347,9 +3393,11 @@ name = "sphinx" version = "8.2.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -3530,47 +3578,47 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.41" +version = "2.0.42" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/66/45b165c595ec89aa7dcc2c1cd222ab269bc753f1fc7a1e68f8481bd957bf/sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9", size = 9689424, upload-time = "2025-05-14T17:10:32.339Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/12/d7c445b1940276a828efce7331cb0cb09d6e5f049651db22f4ebb0922b77/sqlalchemy-2.0.41-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b", size = 2117967, upload-time = "2025-05-14T17:48:15.841Z" }, - { url = "https://files.pythonhosted.org/packages/6f/b8/cb90f23157e28946b27eb01ef401af80a1fab7553762e87df51507eaed61/sqlalchemy-2.0.41-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5", size = 2107583, upload-time = "2025-05-14T17:48:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c2/eef84283a1c8164a207d898e063edf193d36a24fb6a5bb3ce0634b92a1e8/sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747", size = 3186025, upload-time = "2025-05-14T17:51:51.226Z" }, - { url = "https://files.pythonhosted.org/packages/bd/72/49d52bd3c5e63a1d458fd6d289a1523a8015adedbddf2c07408ff556e772/sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30", size = 3186259, upload-time = "2025-05-14T17:55:22.526Z" }, - { url = "https://files.pythonhosted.org/packages/4f/9e/e3ffc37d29a3679a50b6bbbba94b115f90e565a2b4545abb17924b94c52d/sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29", size = 3126803, upload-time = "2025-05-14T17:51:53.277Z" }, - { url = "https://files.pythonhosted.org/packages/8a/76/56b21e363f6039978ae0b72690237b38383e4657281285a09456f313dd77/sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11", size = 3148566, upload-time = "2025-05-14T17:55:24.398Z" }, - { url = "https://files.pythonhosted.org/packages/3b/92/11b8e1b69bf191bc69e300a99badbbb5f2f1102f2b08b39d9eee2e21f565/sqlalchemy-2.0.41-cp310-cp310-win32.whl", hash = "sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda", size = 2086696, upload-time = "2025-05-14T17:55:59.136Z" }, - { url = "https://files.pythonhosted.org/packages/5c/88/2d706c9cc4502654860f4576cd54f7db70487b66c3b619ba98e0be1a4642/sqlalchemy-2.0.41-cp310-cp310-win_amd64.whl", hash = "sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08", size = 2110200, upload-time = "2025-05-14T17:56:00.757Z" }, - { url = "https://files.pythonhosted.org/packages/37/4e/b00e3ffae32b74b5180e15d2ab4040531ee1bef4c19755fe7926622dc958/sqlalchemy-2.0.41-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f", size = 2121232, upload-time = "2025-05-14T17:48:20.444Z" }, - { url = "https://files.pythonhosted.org/packages/ef/30/6547ebb10875302074a37e1970a5dce7985240665778cfdee2323709f749/sqlalchemy-2.0.41-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560", size = 2110897, upload-time = "2025-05-14T17:48:21.634Z" }, - { url = "https://files.pythonhosted.org/packages/9e/21/59df2b41b0f6c62da55cd64798232d7349a9378befa7f1bb18cf1dfd510a/sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f", size = 3273313, upload-time = "2025-05-14T17:51:56.205Z" }, - { url = "https://files.pythonhosted.org/packages/62/e4/b9a7a0e5c6f79d49bcd6efb6e90d7536dc604dab64582a9dec220dab54b6/sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6", size = 3273807, upload-time = "2025-05-14T17:55:26.928Z" }, - { url = "https://files.pythonhosted.org/packages/39/d8/79f2427251b44ddee18676c04eab038d043cff0e764d2d8bb08261d6135d/sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04", size = 3209632, upload-time = "2025-05-14T17:51:59.384Z" }, - { url = "https://files.pythonhosted.org/packages/d4/16/730a82dda30765f63e0454918c982fb7193f6b398b31d63c7c3bd3652ae5/sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582", size = 3233642, upload-time = "2025-05-14T17:55:29.901Z" }, - { url = "https://files.pythonhosted.org/packages/04/61/c0d4607f7799efa8b8ea3c49b4621e861c8f5c41fd4b5b636c534fcb7d73/sqlalchemy-2.0.41-cp311-cp311-win32.whl", hash = "sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8", size = 2086475, upload-time = "2025-05-14T17:56:02.095Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8e/8344f8ae1cb6a479d0741c02cd4f666925b2bf02e2468ddaf5ce44111f30/sqlalchemy-2.0.41-cp311-cp311-win_amd64.whl", hash = "sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504", size = 2110903, upload-time = "2025-05-14T17:56:03.499Z" }, - { url = "https://files.pythonhosted.org/packages/3e/2a/f1f4e068b371154740dd10fb81afb5240d5af4aa0087b88d8b308b5429c2/sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9", size = 2119645, upload-time = "2025-05-14T17:55:24.854Z" }, - { url = "https://files.pythonhosted.org/packages/9b/e8/c664a7e73d36fbfc4730f8cf2bf930444ea87270f2825efbe17bf808b998/sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1", size = 2107399, upload-time = "2025-05-14T17:55:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/5c/78/8a9cf6c5e7135540cb682128d091d6afa1b9e48bd049b0d691bf54114f70/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70", size = 3293269, upload-time = "2025-05-14T17:50:38.227Z" }, - { url = "https://files.pythonhosted.org/packages/3c/35/f74add3978c20de6323fb11cb5162702670cc7a9420033befb43d8d5b7a4/sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e", size = 3303364, upload-time = "2025-05-14T17:51:49.829Z" }, - { url = "https://files.pythonhosted.org/packages/6a/d4/c990f37f52c3f7748ebe98883e2a0f7d038108c2c5a82468d1ff3eec50b7/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078", size = 3229072, upload-time = "2025-05-14T17:50:39.774Z" }, - { url = "https://files.pythonhosted.org/packages/15/69/cab11fecc7eb64bc561011be2bd03d065b762d87add52a4ca0aca2e12904/sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae", size = 3268074, upload-time = "2025-05-14T17:51:51.736Z" }, - { url = "https://files.pythonhosted.org/packages/5c/ca/0c19ec16858585d37767b167fc9602593f98998a68a798450558239fb04a/sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6", size = 2084514, upload-time = "2025-05-14T17:55:49.915Z" }, - { url = "https://files.pythonhosted.org/packages/7f/23/4c2833d78ff3010a4e17f984c734f52b531a8c9060a50429c9d4b0211be6/sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0", size = 2111557, upload-time = "2025-05-14T17:55:51.349Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ad/2e1c6d4f235a97eeef52d0200d8ddda16f6c4dd70ae5ad88c46963440480/sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443", size = 2115491, upload-time = "2025-05-14T17:55:31.177Z" }, - { url = "https://files.pythonhosted.org/packages/cf/8d/be490e5db8400dacc89056f78a52d44b04fbf75e8439569d5b879623a53b/sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc", size = 2102827, upload-time = "2025-05-14T17:55:34.921Z" }, - { url = "https://files.pythonhosted.org/packages/a0/72/c97ad430f0b0e78efaf2791342e13ffeafcbb3c06242f01a3bb8fe44f65d/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1", size = 3225224, upload-time = "2025-05-14T17:50:41.418Z" }, - { url = "https://files.pythonhosted.org/packages/5e/51/5ba9ea3246ea068630acf35a6ba0d181e99f1af1afd17e159eac7e8bc2b8/sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a", size = 3230045, upload-time = "2025-05-14T17:51:54.722Z" }, - { url = "https://files.pythonhosted.org/packages/78/2f/8c14443b2acea700c62f9b4a8bad9e49fc1b65cfb260edead71fd38e9f19/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d", size = 3159357, upload-time = "2025-05-14T17:50:43.483Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b2/43eacbf6ccc5276d76cea18cb7c3d73e294d6fb21f9ff8b4eef9b42bbfd5/sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23", size = 3197511, upload-time = "2025-05-14T17:51:57.308Z" }, - { url = "https://files.pythonhosted.org/packages/fa/2e/677c17c5d6a004c3c45334ab1dbe7b7deb834430b282b8a0f75ae220c8eb/sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f", size = 2082420, upload-time = "2025-05-14T17:55:52.69Z" }, - { url = "https://files.pythonhosted.org/packages/e9/61/e8c1b9b6307c57157d328dd8b8348ddc4c47ffdf1279365a13b2b98b8049/sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df", size = 2108329, upload-time = "2025-05-14T17:55:54.495Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fc/9ba22f01b5cdacc8f5ed0d22304718d2c758fce3fd49a5372b886a86f37c/sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576", size = 1911224, upload-time = "2025-05-14T17:39:42.154Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/5a/03/a0af991e3a43174d6b83fca4fb399745abceddd1171bdabae48ce877ff47/sqlalchemy-2.0.42.tar.gz", hash = "sha256:160bedd8a5c28765bd5be4dec2d881e109e33b34922e50a3b881a7681773ac5f", size = 9749972, upload-time = "2025-07-29T12:48:09.323Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/12/33ff43214c2c6cc87499b402fe419869d2980a08101c991daae31345e901/sqlalchemy-2.0.42-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:172b244753e034d91a826f80a9a70f4cbac690641207f2217f8404c261473efe", size = 2130469, upload-time = "2025-07-29T13:25:15.215Z" }, + { url = "https://files.pythonhosted.org/packages/63/c4/4d2f2c21ddde9a2c7f7b258b202d6af0bac9fc5abfca5de367461c86d766/sqlalchemy-2.0.42-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be28f88abd74af8519a4542185ee80ca914933ca65cdfa99504d82af0e4210df", size = 2120393, upload-time = "2025-07-29T13:25:16.367Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0d/5ff2f2dfbac10e4a9ade1942f8985ffc4bd8f157926b1f8aed553dfe3b88/sqlalchemy-2.0.42-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98b344859d282fde388047f1710860bb23f4098f705491e06b8ab52a48aafea9", size = 3206173, upload-time = "2025-07-29T13:29:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/1f/59/71493fe74bd76a773ae8fa0c50bfc2ccac1cbf7cfa4f9843ad92897e6dcf/sqlalchemy-2.0.42-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97978d223b11f1d161390a96f28c49a13ce48fdd2fed7683167c39bdb1b8aa09", size = 3206910, upload-time = "2025-07-29T13:24:50.58Z" }, + { url = "https://files.pythonhosted.org/packages/a9/51/01b1d85bbb492a36b25df54a070a0f887052e9b190dff71263a09f48576b/sqlalchemy-2.0.42-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e35b9b000c59fcac2867ab3a79fc368a6caca8706741beab3b799d47005b3407", size = 3145479, upload-time = "2025-07-29T13:29:02.3Z" }, + { url = "https://files.pythonhosted.org/packages/fa/78/10834f010e2a3df689f6d1888ea6ea0074ff10184e6a550b8ed7f9189a89/sqlalchemy-2.0.42-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bc7347ad7a7b1c78b94177f2d57263113bb950e62c59b96ed839b131ea4234e1", size = 3169605, upload-time = "2025-07-29T13:24:52.135Z" }, + { url = "https://files.pythonhosted.org/packages/0c/75/e6fdd66d237582c8488dd1dfa90899f6502822fbd866363ab70e8ac4a2ce/sqlalchemy-2.0.42-cp310-cp310-win32.whl", hash = "sha256:739e58879b20a179156b63aa21f05ccacfd3e28e08e9c2b630ff55cd7177c4f1", size = 2098759, upload-time = "2025-07-29T13:23:55.809Z" }, + { url = "https://files.pythonhosted.org/packages/a5/a8/366db192641c2c2d1ea8977e7c77b65a0d16a7858907bb76ea68b9dd37af/sqlalchemy-2.0.42-cp310-cp310-win_amd64.whl", hash = "sha256:1aef304ada61b81f1955196f584b9e72b798ed525a7c0b46e09e98397393297b", size = 2122423, upload-time = "2025-07-29T13:23:56.968Z" }, + { url = "https://files.pythonhosted.org/packages/ea/3c/7bfd65f3c2046e2fb4475b21fa0b9d7995f8c08bfa0948df7a4d2d0de869/sqlalchemy-2.0.42-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c34100c0b7ea31fbc113c124bcf93a53094f8951c7bf39c45f39d327bad6d1e7", size = 2133779, upload-time = "2025-07-29T13:25:18.446Z" }, + { url = "https://files.pythonhosted.org/packages/66/17/19be542fe9dd64a766090e90e789e86bdaa608affda6b3c1e118a25a2509/sqlalchemy-2.0.42-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ad59dbe4d1252448c19d171dfba14c74e7950b46dc49d015722a4a06bfdab2b0", size = 2123843, upload-time = "2025-07-29T13:25:19.749Z" }, + { url = "https://files.pythonhosted.org/packages/14/fc/83e45fc25f0acf1c26962ebff45b4c77e5570abb7c1a425a54b00bcfa9c7/sqlalchemy-2.0.42-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9187498c2149919753a7fd51766ea9c8eecdec7da47c1b955fa8090bc642eaa", size = 3294824, upload-time = "2025-07-29T13:29:03.879Z" }, + { url = "https://files.pythonhosted.org/packages/b9/81/421efc09837104cd1a267d68b470e5b7b6792c2963b8096ca1e060ba0975/sqlalchemy-2.0.42-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f092cf83ebcafba23a247f5e03f99f5436e3ef026d01c8213b5eca48ad6efa9", size = 3294662, upload-time = "2025-07-29T13:24:53.715Z" }, + { url = "https://files.pythonhosted.org/packages/2f/ba/55406e09d32ed5e5f9e8aaec5ef70c4f20b4ae25b9fa9784f4afaa28e7c3/sqlalchemy-2.0.42-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc6afee7e66fdba4f5a68610b487c1f754fccdc53894a9567785932dbb6a265e", size = 3229413, upload-time = "2025-07-29T13:29:05.638Z" }, + { url = "https://files.pythonhosted.org/packages/d4/c4/df596777fce27bde2d1a4a2f5a7ddea997c0c6d4b5246aafba966b421cc0/sqlalchemy-2.0.42-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:260ca1d2e5910f1f1ad3fe0113f8fab28657cee2542cb48c2f342ed90046e8ec", size = 3255563, upload-time = "2025-07-29T13:24:55.17Z" }, + { url = "https://files.pythonhosted.org/packages/16/ed/b9c4a939b314400f43f972c9eb0091da59d8466ef9c51d0fd5b449edc495/sqlalchemy-2.0.42-cp311-cp311-win32.whl", hash = "sha256:2eb539fd83185a85e5fcd6b19214e1c734ab0351d81505b0f987705ba0a1e231", size = 2098513, upload-time = "2025-07-29T13:23:58.946Z" }, + { url = "https://files.pythonhosted.org/packages/91/72/55b0c34e39feb81991aa3c974d85074c356239ac1170dfb81a474b4c23b3/sqlalchemy-2.0.42-cp311-cp311-win_amd64.whl", hash = "sha256:9193fa484bf00dcc1804aecbb4f528f1123c04bad6a08d7710c909750fa76aeb", size = 2123380, upload-time = "2025-07-29T13:24:00.155Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/ac31a9821fc70a7376321fb2c70fdd7eadbc06dadf66ee216a22a41d6058/sqlalchemy-2.0.42-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:09637a0872689d3eb71c41e249c6f422e3e18bbd05b4cd258193cfc7a9a50da2", size = 2132203, upload-time = "2025-07-29T13:29:19.291Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ba/fd943172e017f955d7a8b3a94695265b7114efe4854feaa01f057e8f5293/sqlalchemy-2.0.42-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3cb3ec67cc08bea54e06b569398ae21623534a7b1b23c258883a7c696ae10df", size = 2120373, upload-time = "2025-07-29T13:29:21.049Z" }, + { url = "https://files.pythonhosted.org/packages/ea/a2/b5f7d233d063ffadf7e9fff3898b42657ba154a5bec95a96f44cba7f818b/sqlalchemy-2.0.42-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e87e6a5ef6f9d8daeb2ce5918bf5fddecc11cae6a7d7a671fcc4616c47635e01", size = 3317685, upload-time = "2025-07-29T13:26:40.837Z" }, + { url = "https://files.pythonhosted.org/packages/86/00/fcd8daab13a9119d41f3e485a101c29f5d2085bda459154ba354c616bf4e/sqlalchemy-2.0.42-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b718011a9d66c0d2f78e1997755cd965f3414563b31867475e9bc6efdc2281d", size = 3326967, upload-time = "2025-07-29T13:22:31.009Z" }, + { url = "https://files.pythonhosted.org/packages/a3/85/e622a273d648d39d6771157961956991a6d760e323e273d15e9704c30ccc/sqlalchemy-2.0.42-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:16d9b544873fe6486dddbb859501a07d89f77c61d29060bb87d0faf7519b6a4d", size = 3255331, upload-time = "2025-07-29T13:26:42.579Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a0/2c2338b592c7b0a61feffd005378c084b4c01fabaf1ed5f655ab7bd446f0/sqlalchemy-2.0.42-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21bfdf57abf72fa89b97dd74d3187caa3172a78c125f2144764a73970810c4ee", size = 3291791, upload-time = "2025-07-29T13:22:32.454Z" }, + { url = "https://files.pythonhosted.org/packages/41/19/b8a2907972a78285fdce4c880ecaab3c5067eb726882ca6347f7a4bf64f6/sqlalchemy-2.0.42-cp312-cp312-win32.whl", hash = "sha256:78b46555b730a24901ceb4cb901c6b45c9407f8875209ed3c5d6bcd0390a6ed1", size = 2096180, upload-time = "2025-07-29T13:16:08.952Z" }, + { url = "https://files.pythonhosted.org/packages/48/1f/67a78f3dfd08a2ed1c7be820fe7775944f5126080b5027cc859084f8e223/sqlalchemy-2.0.42-cp312-cp312-win_amd64.whl", hash = "sha256:4c94447a016f36c4da80072e6c6964713b0af3c8019e9c4daadf21f61b81ab53", size = 2123533, upload-time = "2025-07-29T13:16:11.705Z" }, + { url = "https://files.pythonhosted.org/packages/e9/7e/25d8c28b86730c9fb0e09156f601d7a96d1c634043bf8ba36513eb78887b/sqlalchemy-2.0.42-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:941804f55c7d507334da38133268e3f6e5b0340d584ba0f277dd884197f4ae8c", size = 2127905, upload-time = "2025-07-29T13:29:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/e5/a1/9d8c93434d1d983880d976400fcb7895a79576bd94dca61c3b7b90b1ed0d/sqlalchemy-2.0.42-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d3d06a968a760ce2aa6a5889fefcbdd53ca935735e0768e1db046ec08cbf01", size = 2115726, upload-time = "2025-07-29T13:29:23.496Z" }, + { url = "https://files.pythonhosted.org/packages/a2/cc/d33646fcc24c87cc4e30a03556b611a4e7bcfa69a4c935bffb923e3c89f4/sqlalchemy-2.0.42-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cf10396a8a700a0f38ccd220d940be529c8f64435c5d5b29375acab9267a6c9", size = 3246007, upload-time = "2025-07-29T13:26:44.166Z" }, + { url = "https://files.pythonhosted.org/packages/67/08/4e6c533d4c7f5e7c4cbb6fe8a2c4e813202a40f05700d4009a44ec6e236d/sqlalchemy-2.0.42-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cae6c2b05326d7c2c7c0519f323f90e0fb9e8afa783c6a05bb9ee92a90d0f04", size = 3250919, upload-time = "2025-07-29T13:22:33.74Z" }, + { url = "https://files.pythonhosted.org/packages/5c/82/f680e9a636d217aece1b9a8030d18ad2b59b5e216e0c94e03ad86b344af3/sqlalchemy-2.0.42-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f50f7b20677b23cfb35b6afcd8372b2feb348a38e3033f6447ee0704540be894", size = 3180546, upload-time = "2025-07-29T13:26:45.648Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a2/8c8f6325f153894afa3775584c429cc936353fb1db26eddb60a549d0ff4b/sqlalchemy-2.0.42-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d88a1c0d66d24e229e3938e1ef16ebdbd2bf4ced93af6eff55225f7465cf350", size = 3216683, upload-time = "2025-07-29T13:22:34.977Z" }, + { url = "https://files.pythonhosted.org/packages/39/44/3a451d7fa4482a8ffdf364e803ddc2cfcafc1c4635fb366f169ecc2c3b11/sqlalchemy-2.0.42-cp313-cp313-win32.whl", hash = "sha256:45c842c94c9ad546c72225a0c0d1ae8ef3f7c212484be3d429715a062970e87f", size = 2093990, upload-time = "2025-07-29T13:16:13.036Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9e/9bce34f67aea0251c8ac104f7bdb2229d58fb2e86a4ad8807999c4bee34b/sqlalchemy-2.0.42-cp313-cp313-win_amd64.whl", hash = "sha256:eb9905f7f1e49fd57a7ed6269bc567fcbbdac9feadff20ad6bd7707266a91577", size = 2120473, upload-time = "2025-07-29T13:16:14.502Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/ba2546ab09a6adebc521bf3974440dc1d8c06ed342cceb30ed62a8858835/sqlalchemy-2.0.42-py3-none-any.whl", hash = "sha256:defcdff7e661f0043daa381832af65d616e060ddb54d3fe4476f51df7eaa1835", size = 1922072, upload-time = "2025-07-29T13:09:17.061Z" }, ] [[package]] @@ -3620,8 +3668,10 @@ name = "stable-baselines3" version = "2.7.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", ] @@ -3667,39 +3717,39 @@ wheels = [ [[package]] name = "symengine" -version = "0.13.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/ff/a2041497a482a0ae585672fe12cc8983c7fc46ce792811b55a067e5e5516/symengine-0.13.0.tar.gz", hash = "sha256:ab83a08897ebf12579702c2b71ba73d4732fb706cc4291d810aedf39c690c14c", size = 114237, upload-time = "2024-09-30T22:06:25.16Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/ed/964f75a2dc5b0e2c97b732f44dfb9c40fe7c0f5e21a1ecc2edff89db3d81/symengine-0.13.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:259fd4111c7a70c72bdff5686de1949e8132baeb612eacdaf8837720c6fe449b", size = 25867912, upload-time = "2024-09-30T22:03:05.097Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ce/c74dfbaf487a428984644b3cb5e1131c4808f60eab1456f37a107f20b87a/symengine-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44f2eb28a1e36db0bbd6679435412f79da9743bf9c1cb3eff25e0c343b7ddd48", size = 22711016, upload-time = "2024-09-30T22:03:09.144Z" }, - { url = "https://files.pythonhosted.org/packages/4b/65/df699e2b4c2bbf608394b05d1095d77b3f02569e09960f7840f708c7c5dc/symengine-0.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d141712fa14d9138bd19e64b10392f850c68d88cd7db29f1bda33e32d1095559", size = 61000047, upload-time = "2024-09-30T22:03:13.613Z" }, - { url = "https://files.pythonhosted.org/packages/ff/a9/623d97da0da9615367484127dd3b5d1049675832fb9a6a3572f2e072bb86/symengine-0.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:830226d933bfcdb93546e4062541627d9a3bc7a178a63fb16c002eb5c5221938", size = 90017189, upload-time = "2024-09-30T22:03:20.545Z" }, - { url = "https://files.pythonhosted.org/packages/79/a0/d30329ef1bd2b188cb5bbf6d9394e72fa9f38b33a6caa2128ee187716259/symengine-0.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a08090163819a0bbfa97d64bd2d8dac2c5268147ed9c242799d7f7e8728a6f4e", size = 49698796, upload-time = "2024-09-30T22:03:31.169Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e3/cf99b6353b46b8d9ff05e8d7d24764c8afed7c46b888eece99c6e04cc295/symengine-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1e435dcd8ed25e4c7c21ab1c0376be910efc7f35da76d532367df27b359f0358", size = 17830331, upload-time = "2024-09-30T22:03:35.649Z" }, - { url = "https://files.pythonhosted.org/packages/47/a7/e69cff22c2b169b469faa390f0102fbdefe1dfede893a086454483db0fc3/symengine-0.13.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:da0eba7e106095cdce88eb275c8a9d7c4586ad88f229394c53e1184155c00745", size = 25878286, upload-time = "2024-09-30T22:03:39.216Z" }, - { url = "https://files.pythonhosted.org/packages/60/40/bb3faf5a3d4cc99cf5252cc3f4f5267568abd4aae6439374623841cc0025/symengine-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b0c175f4f895a73a925508af03faf7efd6cad8593256bbdb5346bd996d3ec5c8", size = 22721741, upload-time = "2024-09-30T22:03:42.574Z" }, - { url = "https://files.pythonhosted.org/packages/de/da/d6350f60f11abc7ee56fcb6b996deba7b31584b5942a4c5db7d3d4f324dd/symengine-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e58d1e2abd08381aa0cf24c88c0e8b7f592df92619b51e32d36835fbd2dd6ae8", size = 60999516, upload-time = "2024-09-30T22:03:47.206Z" }, - { url = "https://files.pythonhosted.org/packages/d1/ee/db107db7d0557aa8dbc9485741a60dd4f869d3da32180710506f9ba942b9/symengine-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db745f2c7a3c5e83510cf4decb43201f43552dfb05ad8af9787c89708be9ede", size = 90019965, upload-time = "2024-09-30T22:03:54.128Z" }, - { url = "https://files.pythonhosted.org/packages/8f/f0/0642f5d9681ff26e57c317d0514315cf1b0dfe1bc8f68ee14a13a270d704/symengine-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2572c98b09ac284db6ecff63f6170461194dc94c4209afd34c092ec67873d85", size = 49690621, upload-time = "2024-09-30T22:03:59.467Z" }, - { url = "https://files.pythonhosted.org/packages/54/85/4300eda41959e3839115b2cb0ddb21818804f5eb129cf92eb9cc55c6efe5/symengine-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:12727f02a2919f005aee48e68e0cbb70cf857b19385857b4d985d1c9b075f620", size = 17831939, upload-time = "2024-09-30T22:04:03.649Z" }, - { url = "https://files.pythonhosted.org/packages/a1/b2/786d3efb98ae1c8e0a9869d6901f24a6633bd621f9e4e1427c86bff35abb/symengine-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cf91d24f1bfd6d53228593c7804dd106b71b19674d5afc4fa322d516e1793bdd", size = 25853458, upload-time = "2024-09-30T22:04:06.435Z" }, - { url = "https://files.pythonhosted.org/packages/3f/74/78b9e7f17c9b9b345d8ef0dbdefebbfc2c7f00693949c6b5808f8a9e54d8/symengine-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5615b7eb68890917abd390ebb10434a949165f6064741c1a8cc345fee14e855", size = 22713256, upload-time = "2024-09-30T22:04:10.002Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a8/69f429946e9a9e63a141dcbe519df8a8c3d56aa75fa8440716871efd8b75/symengine-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb92bdf0890de264abaeacbfbdbd4dd7444b94057bd47958d913b662e549ad8a", size = 60847852, upload-time = "2024-09-30T22:04:14.415Z" }, - { url = "https://files.pythonhosted.org/packages/f5/3c/a613d5fa73c1b05eb4f0a4bc2bfa21314d37c89dcdb355da684b5f9bea46/symengine-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3bce486fbc0b87970ed1b10ca9d5cafb1fd6b66382fe631261d83592851d7e", size = 89691094, upload-time = "2024-09-30T22:04:21.012Z" }, - { url = "https://files.pythonhosted.org/packages/90/9f/5a171a9edff23eb0e33e0a2dca295a8b25fd64491ebe8cf765e489bd2bcd/symengine-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7e6bae9cfcdde2775d92fbb0abe3ef04e32f65ebc4c2d164ca33f4da202d4a7", size = 49584342, upload-time = "2024-09-30T22:04:28.117Z" }, - { url = "https://files.pythonhosted.org/packages/07/16/a69dffc665e5007a0b4f1500fc401316aa070d109f83bc6887802dce199d/symengine-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:bced0a1dbdb94737c299384c85ddbad6944ce8dadc334f7bb8dbbd8f6c965807", size = 17787218, upload-time = "2024-09-30T22:04:32.066Z" }, - { url = "https://files.pythonhosted.org/packages/f2/51/36ea8d87b61f34d585d09ff585cdc2ba136c501e0a96e861fe81fd0efa5b/symengine-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d34df77971538e4c29f2d8e5ef7f459c2179465e6cdb7dfd48b79b87ecd8f4d", size = 25838153, upload-time = "2024-09-30T22:04:35.743Z" }, - { url = "https://files.pythonhosted.org/packages/2a/f7/73cd707633c01760df27d340ac2868788fa0a35034aa09f51f6a289d9a07/symengine-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ab2661d9b18867e7c6edbfa7a74b8b0a2a694bd24aa08003dc3214f77cb9d6f2", size = 22706111, upload-time = "2024-09-30T22:04:38.922Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e7/a1ddc4cc3f2604b18965342523cddd6160b6406d1ef21b58a2dea1c46312/symengine-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53f27b9013878ee4419d8e853664d8ae4b68419e3f4b9b5b7f503d32bf904755", size = 60848269, upload-time = "2024-09-30T22:04:43.816Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f5/b127d236a8ccce8b85cec8bcb0221cbb6a4e651d6f5511da925e10714a4c/symengine-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27987f75ce08c64f453e2b9b74fec6ffc5ca418c4deca0b75580979d4a4e242a", size = 89679345, upload-time = "2024-09-30T22:04:50.53Z" }, - { url = "https://files.pythonhosted.org/packages/49/d0/b07c71dfb6f7f47f90495d67cb0b2264f94f2fb9380e528fe4fcec4c5cfa/symengine-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ea9410330ea15ed4137d7a0a3c43caccacb71490e18036ce5182d08c93baf8", size = 49582795, upload-time = "2024-09-30T22:04:56.705Z" }, - { url = "https://files.pythonhosted.org/packages/de/c6/3ce562ec269b033a738b99aa75729d564bfe465a765a5b5810200924f5c9/symengine-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:5031eb7a5c6675d5195bb57f93cc7d9ac5a7a9a826d4ad6f6b2927746ed7e6e6", size = 17786679, upload-time = "2024-09-30T22:05:30.754Z" }, - { url = "https://files.pythonhosted.org/packages/ca/0f/02031b4ed54fb088ade94082e4658160333c2d5c6629ca7e567ea5a23720/symengine-0.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ce0e5dfb19943bcf3e44a4485bcac4c5533ba3705c63083494eed0b3bf246076", size = 25795209, upload-time = "2024-09-30T22:05:05.713Z" }, - { url = "https://files.pythonhosted.org/packages/34/c0/03e9e34a4e2af73dd786fb966ee3ad7ffa57659e79e4ac390be9e9f6aded/symengine-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c3b77dc54bf1181f6bd3b3338c4e6e5973a8b0fa20a189d15563ef5626e57b04", size = 22670484, upload-time = "2024-09-30T22:05:08.721Z" }, - { url = "https://files.pythonhosted.org/packages/9d/13/66c8510403089ee157f0a8930a2e043e6f4de9ee514c8084adb958934058/symengine-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca7c3f6c168f6f5b06b421833c3d3baae56067a94b671bdffbe09b8e4fefd9be", size = 60739889, upload-time = "2024-09-30T22:05:13.331Z" }, - { url = "https://files.pythonhosted.org/packages/70/fe/d0c778204d855257865e713fcbfef11dde34621e07fee439d4d117f43203/symengine-0.13.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:847523de682416811bacb3ad11507e663b3522fbb35cd27184757e9956d0eaf0", size = 89405899, upload-time = "2024-09-30T22:05:20.504Z" }, - { url = "https://files.pythonhosted.org/packages/66/f6/f546e527caf35b7d0f14dbcea278134d4e46d7431821b9ca9f5ec3388a6a/symengine-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2fc1b7d96426463f0c9011e9fb88459d906477c1baa8a996dde6fb2bfa99d4", size = 49474632, upload-time = "2024-09-30T22:05:26.083Z" }, +version = "0.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/ae/051d3e2ffd128f4a8fa67d380bb7be45637d39e206b4c3737c087a3d4b71/symengine-0.14.1.tar.gz", hash = "sha256:4e9e4b4ec56371c2151803ae0403dab07dd1c74ce88e9abca433bebeb6e2f0f0", size = 938282, upload-time = "2025-04-21T04:03:04.916Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/64/7a9c565d804cc1aafdf4941a2fa3985a6b660ac70ac15080e5112113beeb/symengine-0.14.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0f977360c9993dae163951386ea5b865d8310f323cf11234e62b6535f330d3ac", size = 25935332, upload-time = "2025-04-21T04:00:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/08/9d/deba31c5a38cf26244298ebb63fee5d730638d23b6ab055ecf4988bcf485/symengine-0.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:524249b3224617f91e4e0b81c4134fa496024ddf67b383163586d74683f064a3", size = 22999100, upload-time = "2025-04-21T04:00:46.425Z" }, + { url = "https://files.pythonhosted.org/packages/87/77/13b5faf6b7873df3f2365aa2e43c7dac3e5cb7f037d7d0b60c648132fba9/symengine-0.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f2fb2b9ba7038cba436783a5c1bddc40ba84c7812a4b9c50571fd47ff265038", size = 60837233, upload-time = "2025-04-21T04:00:50.435Z" }, + { url = "https://files.pythonhosted.org/packages/46/cb/9bce97ad8135a32b47e90b3f57084bdc0bb844aa866b3ca0bc88987a2ac4/symengine-0.14.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a010412317d93e37fbee3f4bc04886408653e863997993424e7b9e4d8c85c150", size = 90826835, upload-time = "2025-04-21T04:00:55.849Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8f/3c335e44db300f4d91f7b098661a2add403367833cc27d26dc235520661a/symengine-0.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb14724ab6a6844d04adbd48d7aadcadfe4974193e87eedac93963a6e88bf53", size = 50356243, upload-time = "2025-04-21T04:01:00.867Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fd/d9f33b8a08bdfc07fff733c7f869deb5a0e8c93f5cb95ed4cb9d16294dfb/symengine-0.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:4635fa8855fcadae8c60f27f498388699b7ee88c6be7c3e23564eb0907f6b397", size = 18755307, upload-time = "2025-04-21T04:01:04.187Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f8/689900a258a68b121d7c61a6705b5332969dd95517f9be1d66a4937a17e1/symengine-0.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:43a394acef2355bbcbed089c8f83a7dbdac28f4f979e094b549f571fc411dea6", size = 25992552, upload-time = "2025-04-21T04:01:07.102Z" }, + { url = "https://files.pythonhosted.org/packages/6e/10/82291c78d6dbc17b2e4371559a3945920ecc536ec36b6c8dde28165064f9/symengine-0.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7eb37cd5a9eb0c1c5e35c515139fd1221d937b269aef3569b92c7bb4e251be4", size = 23052876, upload-time = "2025-04-21T04:01:09.679Z" }, + { url = "https://files.pythonhosted.org/packages/30/1a/2199515b7d4f3aa74262e3eb31916a593c4daa7da53bb2c9cbd2cc13fad8/symengine-0.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7657663cfb0d87d66848f7cacda0b2447e127584bc9ec65120e75ce68b21b809", size = 60873086, upload-time = "2025-04-21T04:01:14.285Z" }, + { url = "https://files.pythonhosted.org/packages/07/ce/1e7d9abea217cee8a543ff1fb395b4462e9a4df8072e25b42984e8a6938e/symengine-0.14.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94535da1085a4927364fbb4a8705f7f504897ac53da2cc6d6a8edc897e49c4da", size = 90878511, upload-time = "2025-04-21T04:01:21.764Z" }, + { url = "https://files.pythonhosted.org/packages/6e/23/4bcd98c8a79bc0d584786eb765f33dffca1136fe9b506c6e336d61fad844/symengine-0.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32a29b9462446c9e7f3bf464c7faa847ac2a2d75f0f3fd2f7c0606f9b9384cb", size = 50397966, upload-time = "2025-04-21T04:01:27.732Z" }, + { url = "https://files.pythonhosted.org/packages/a2/c2/72612eae87f3d0ca58ae4e2207eaee9f8c1dfddc6862a1dc8e2257d67e14/symengine-0.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:f639a488886a066c4d8f19f2a4fd2213de2ea428153d8e1bf425c14f8bc74d57", size = 18803262, upload-time = "2025-04-21T04:01:31.136Z" }, + { url = "https://files.pythonhosted.org/packages/59/ab/3ef6b6385b277511a2e80f5425629af6566c491200ced6ba4a5b33db6b9c/symengine-0.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4c657fba40960dc143d90b20fe49ae769d5c82b323b9dd459f5e3dea4796df8f", size = 25962842, upload-time = "2025-04-21T04:01:34.359Z" }, + { url = "https://files.pythonhosted.org/packages/58/8d/e47e7e9166b4d53cacb0ad722164a6a2bfbb459d62bee105a05998f7b2aa/symengine-0.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9789c62a8ade18f368241525e910dae745fdde1f3b8bb782e5ac8bbfad505e92", size = 23046175, upload-time = "2025-04-21T04:01:37.275Z" }, + { url = "https://files.pythonhosted.org/packages/be/76/6c2227ca8076c238b65341beb3ce4a5bb29174afce3eb9f124b319242693/symengine-0.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcab68fe738a50df3a1b2415f75395c588aab237cb636818332e6cda7ddcf5fb", size = 60719492, upload-time = "2025-04-21T04:01:40.806Z" }, + { url = "https://files.pythonhosted.org/packages/bb/d8/e2dad8babfbb6c8abdb2c443aefca0ae65078c2a0c1f791117a2e659b005/symengine-0.14.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f58a88571a5f7ceca499d7f7834c00d129a55d4c2104a463ba8e3ec24c252e89", size = 90545323, upload-time = "2025-04-21T04:01:46.143Z" }, + { url = "https://files.pythonhosted.org/packages/64/4f/84948cd8384deb43465c14daea81e53159b1c22a2fd55c4f087c47f180df/symengine-0.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a55b8f78541d57a28beda6971bed0a7ddbd585148bb030221f7ca3a0c8e2517", size = 50278629, upload-time = "2025-04-21T04:01:51.673Z" }, + { url = "https://files.pythonhosted.org/packages/d6/7f/4d6b6998a69af3614cc4cb5953acc23b116b35e0596be4dd991397f0cdce/symengine-0.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:5091ce86728022d2c7e0e864ab23070494c1f24fb430ab3437d46806e854651e", size = 18754027, upload-time = "2025-04-21T04:01:55.355Z" }, + { url = "https://files.pythonhosted.org/packages/db/09/c382abfa3e83f11be0ade2ab063f11cc4a3a906b5194f62956856ba766b6/symengine-0.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9859c0c926475dfed666707afba04639a6d46ab48bc463faf50c79b6513de861", size = 25960338, upload-time = "2025-04-21T04:01:57.962Z" }, + { url = "https://files.pythonhosted.org/packages/13/8d/d4b541515b0fa5c390109572d035d397e28ac6f4bd69bee88806b231a65f/symengine-0.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:431545ef66b20efa24e5de9d754ffb184ad9ed29743740c0e9d815c1a1ec37a8", size = 23040715, upload-time = "2025-04-21T04:02:00.584Z" }, + { url = "https://files.pythonhosted.org/packages/4a/c7/4ca78ac8df7dacf35bfa77411c317d65adc6add07f58a4d210060b678511/symengine-0.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e69fe8be6e1d1f5209abeb7a8308a074d981b9f1f166086f23f6eed20d861e7f", size = 60716721, upload-time = "2025-04-21T04:02:04.19Z" }, + { url = "https://files.pythonhosted.org/packages/04/92/1d1d9084ccf1749af477273ac952ab68970175a62ef093b32d83dd3efc53/symengine-0.14.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b51617f42213ceb49786b474195d17e7d62e492d0592caa4b404f0e1b1acf58", size = 90546321, upload-time = "2025-04-21T04:02:09.873Z" }, + { url = "https://files.pythonhosted.org/packages/8d/23/922e6fd625ef08c4b703790d3accdcc48e6b340538de25a29ee8b5bebe6c/symengine-0.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e91af61b854e82ae5382e5f91e66d83ac007c0b19b3946f747bc4fc6ca25d66", size = 50277827, upload-time = "2025-04-21T04:02:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/7b/05/29090873cc7b3d23b492a192fa51ada148c80de016db2dc29225230f6499/symengine-0.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:d232d03ceb008d6eb24cb3e1f423af44d3d78cfe09aed801d9fc68ef7b41b611", size = 18753449, upload-time = "2025-04-21T04:02:38.332Z" }, + { url = "https://files.pythonhosted.org/packages/d8/23/0a542b0d3af0b017c129852265aa1a208f152855fd9feb0c1480d846b784/symengine-0.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1324f94852cf2541be29de31899d00bdcab547fea9e9534bcc548062c3f33038", size = 25893789, upload-time = "2025-04-21T04:02:19.407Z" }, + { url = "https://files.pythonhosted.org/packages/e3/38/d22630f658238e33138ceb57b368fd99555472f5e4be561bbc27cf4b134d/symengine-0.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e4b61cb16a559f2e098d52285b27fac4e6ee15194368cef5b78727f71a490bb5", size = 22991458, upload-time = "2025-04-21T04:02:22.396Z" }, + { url = "https://files.pythonhosted.org/packages/be/28/9ae2ee8c3a6e5b35b25a42625de4cd8ef432121dd4ff75bca6809b9e61ac/symengine-0.14.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58f8e1756c9f8cdb7f6cdf189b3752f20cb464f82bf1c7a3873156b12c567896", size = 60604042, upload-time = "2025-04-21T04:02:25.915Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c0/233806912e5515505a058d2527a53117e0e6cd8e59525f1c7cb870805a47/symengine-0.14.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a96f1adfed8cfad62a4f58fe2f32b42718e0938afef0bffeb8131d862ca71a9b", size = 90280432, upload-time = "2025-04-21T04:02:31.02Z" }, + { url = "https://files.pythonhosted.org/packages/bd/93/a6f379c6bd9554efc4cd5475e75fc164d6c44e69d98ddf6553f12a2532aa/symengine-0.14.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c4f500fdd09cbd3cde34a027a964e47b4fc7bfcd5ec8b9a4e654a37036d364b", size = 50183106, upload-time = "2025-04-21T04:02:35.537Z" }, ] [[package]] @@ -3833,8 +3883,10 @@ name = "torch" version = "2.7.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", + "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", ] From 5f8473c6f102f1dd5cfd6198ec4382fe3b9d85e0 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Sun, 3 Aug 2025 13:53:59 +0200 Subject: [PATCH 11/98] Fix dependency issues --- pyproject.toml | 3 +-- uv.lock | 58 ++++++++++---------------------------------------- 2 files changed, 12 insertions(+), 49 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e1acedfb7..964435876 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,8 +44,7 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 - "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", - "torch>=2.4.0; python_version >= '3.12' and sys_platform != 'darwin' and 'x86_64' not in platform_machine", + "torch>=2.7.1,<2.8.0; sys_platform == 'darwin' and python_version < '3.13'", "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1", "qiskit-ibm-ai-local-transpiler>=0.3.2" diff --git a/uv.lock b/uv.lock index 4e3e5bdde..812e3df7c 100644 --- a/uv.lock +++ b/uv.lock @@ -1562,8 +1562,7 @@ dependencies = [ { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "scikit-learn" }, { name = "tensorboard" }, - { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "torch", version = "2.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12' and 'x86_64' not in platform_machine and sys_platform != 'darwin'" }, + { name = "torch", marker = "python_full_version < '3.13' and sys_platform == 'darwin'" }, { name = "tqdm" }, { name = "typing-extensions" }, ] @@ -1620,8 +1619,7 @@ requires-dist = [ { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "tensorboard", specifier = ">=2.17.0" }, - { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.2.2,<2.3.0" }, - { name = "torch", marker = "python_full_version >= '3.12' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", specifier = ">=2.4.0" }, + { name = "torch", marker = "python_full_version < '3.13' and sys_platform == 'darwin'", specifier = ">=2.7.1,<2.8.0" }, { name = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, ] @@ -3656,7 +3654,7 @@ dependencies = [ { name = "matplotlib", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "pandas", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fa/3b/13aacfe41697455f559449ad0dc5f51b4f30aed8fb000131225c64cc60f4/stable_baselines3-2.4.1.tar.gz", hash = "sha256:3bbf0e46b9aa4b1fd2696ff4c806ddb8ba719966ef0f71fba61f7a177e563c81", size = 212611, upload-time = "2025-01-07T13:22:42.455Z" } wheels = [ @@ -3682,7 +3680,7 @@ dependencies = [ { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, { name = "pandas", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "torch", version = "2.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "torch", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/cc/9a334071fae143bc7177e17a3191db83c1a4bf9038b09c4c5a34e427ca33/stable_baselines3-2.7.0.tar.gz", hash = "sha256:5258561e5becd15234274262cf09fcb9a082a73c2c67a85322f5652a05195ec4", size = 219012, upload-time = "2025-07-25T09:54:35.113Z" } wheels = [ @@ -3852,49 +3850,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, ] -[[package]] -name = "torch" -version = "2.2.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", -] -dependencies = [ - { name = "filelock", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "fsspec", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "jinja2", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "networkx", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "sympy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "typing-extensions", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/55/7192974ab13e5e5577f45d14ce70d42f5a9a686b4f57bbe8c9ab45c4a61a/torch-2.2.2-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:b2e2200b245bd9f263a0d41b6a2dab69c4aca635a01b30cca78064b0ef5b109e", size = 150788930, upload-time = "2024-03-27T21:08:09.98Z" }, - { url = "https://files.pythonhosted.org/packages/33/6b/21496316c9b8242749ee2a9064406271efdf979e91d440e8a3806b5e84bf/torch-2.2.2-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:877b3e6593b5e00b35bbe111b7057464e76a7dd186a287280d941b564b0563c2", size = 59707286, upload-time = "2024-03-27T21:10:28.154Z" }, - { url = "https://files.pythonhosted.org/packages/3f/14/e105b8ef6d324e789c1589e95cb0ab63f3e07c2216d68b1178b7c21b7d2a/torch-2.2.2-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:95b9b44f3bcebd8b6cd8d37ec802048c872d9c567ba52c894bba90863a439059", size = 150796474, upload-time = "2024-03-27T21:09:29.142Z" }, - { url = "https://files.pythonhosted.org/packages/96/23/18b9c16c18a77755e7f15173821c7100f11e6b3b7717bea8d729bdeb92c0/torch-2.2.2-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:49aa4126ede714c5aeef7ae92969b4b0bbe67f19665106463c39f22e0a1860d1", size = 59714938, upload-time = "2024-03-27T21:09:34.709Z" }, - { url = "https://files.pythonhosted.org/packages/79/78/29dcab24a344ffd9ee9549ec0ab2c7885c13df61cde4c65836ee275efaeb/torch-2.2.2-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:eb4d6e9d3663e26cd27dc3ad266b34445a16b54908e74725adb241aa56987533", size = 150797270, upload-time = "2024-03-27T21:08:29.623Z" }, - { url = "https://files.pythonhosted.org/packages/4a/0e/e4e033371a7cba9da0db5ccb507a9174e41b9c29189a932d01f2f61ecfc0/torch-2.2.2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:bf9558da7d2bf7463390b3b2a61a6a3dbb0b45b161ee1dd5ec640bf579d479fc", size = 59678388, upload-time = "2024-03-27T21:08:35.869Z" }, -] - [[package]] name = "torch" version = "2.7.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", - "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", - "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", -] dependencies = [ - { name = "filelock", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "fsspec", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "jinja2", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "networkx", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, @@ -3909,10 +3873,10 @@ dependencies = [ { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "setuptools", marker = "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, - { name = "sympy", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "setuptools", marker = "python_full_version >= '3.12'" }, + { name = "sympy" }, { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "typing-extensions" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/6a/27/2e06cb52adf89fe6e020963529d17ed51532fc73c1e6d1b18420ef03338c/torch-2.7.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a103b5d782af5bd119b81dbcc7ffc6fa09904c423ff8db397a1e6ea8fd71508f", size = 99089441, upload-time = "2025-06-04T17:38:48.268Z" }, From 7491ec01f5f615335fc7cdb6b070be176ae12067 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Sun, 3 Aug 2025 14:30:54 +0200 Subject: [PATCH 12/98] Add missing zip file --- pyproject.toml | 2 +- .../training_data_compilation.zip | Bin 0 -> 592854 bytes uv.lock | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/mqt/predictor/rl/training_data/training_circuits/training_data_compilation.zip diff --git a/pyproject.toml b/pyproject.toml index 964435876..84b31abd6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 - "torch>=2.7.1,<2.8.0; sys_platform == 'darwin' and python_version < '3.13'", + "torch>=2.7.1,<2.8.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1", "qiskit-ibm-ai-local-transpiler>=0.3.2" diff --git a/src/mqt/predictor/rl/training_data/training_circuits/training_data_compilation.zip b/src/mqt/predictor/rl/training_data/training_circuits/training_data_compilation.zip new file mode 100644 index 0000000000000000000000000000000000000000..2e51e3333fa1b0d741ac129fbe8b994e88abfa9a GIT binary patch literal 592854 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 z zxWON6tuT|^Y?VB|T8lKTF~ZW+Rc&$%c}T#D*rz~jO1mc3Tb92PoOC-XHfV~2R4d(@ z{AJ>&E_QDGl{}2Y9d#4P`E-!D`JP^A_s9EFNCOJNDagkfSpa-w0QgXb{c5211Reqk z1ZJSo1Ri^y{<^+>z9Kx513XjS)cG#~{Dp-7C;)o^1r5Ik@NZKte+%IM^jHsoh9C>T z^$kMUH6IX}Tz6ej_0qcCM7-!<-W!R^BRKZ0{AOfGBbsvAw&T|SSvDq1zNR>$ev z7(&H@Qq1EG!1JvjG{qId6eaXRo`P1uXXwktTuR?7jVYH}F;c}6-E3^<&ANhNL8rfcGY(k@1dEW{=-R=VH$s2MFYzffXU47ua=c^s^eBfS@rwGFdU z^r7|43^`KCs=8fp1$E|KtW7`~ab823LYk*GFS{kfu+NG_Z&fecKE()czxn!6-aEbb)E%VuNR6l|LzY|Os*1thJhtr*w}dNLE2 zRJl^Yx)me|0)EzJaSRtXsqxd|Il4afB9onQ7_HNeVYCcZF%T?$0p|Ncgif7=!*|?w2qX z1uuB^`_61s{&Lp7qLU$Kl~7#O&uD_w>MJydl~C|YbF-bPUfK0A%jwpJVPYfDVfsz0 z8IOZ&yUX5nV++>0LE8xX($xiE6dH;!aTOGx!)h#`DdpzyEP9IYah2x4&dUeBZx>9a z_G&(F0IqLZ{+GD^LhyeSuIYf;wRk|kOC>LgNzlnG44jcXTRJVI#n|&<>B~3!Uu(2^)mh>J-${!J4Vw9!;hCj z{mhZmWA{IpJFBQXvu;b{?oQC)?(XjH?(PJ4cemiK!2$#)I0Oss9)i2O^+)}uM~_n{ zsncWBO)j|M^4oJh@0PXZx~h3K6q%U`CkYOPh8?m)9oUmDRG6g*FnL}nE5|CrSHjJ> ztoaV3@JJS^mlt)k?Jw6mapUIb-L6-7p&?R?Td<)cDvqqa>VRe5S9o1_AX=vPxRwta zn@EA(-+rXuFkkt!>WT^tnXgjYF1$=aWEtE9TqpHDc_U3EqIX-G)~kw#t-)b0|DZ>W z71N{sGW^m36tP}K(K?DEW-9w%q|NJoOaeC*!CU{15kxp9PXmG>nm zG2AI*+eDm_9PIEQy4&pgi4V2$ksMi#5FgbFav3sXQ=Nb zHctMV3A;#L8X(TxP(cx_A>I2`ArZR*N1?W--2q&R!e6xgBh00+hth8uGa ze5>@igR3>qX|-+I`DEMT!!J;jl;N>sHuT+TmziWOG2JQeGBKT3{*fwhu!Qov_7s@m zS|SLOLH18Hn(^}bf@0Qz0nvxT| z1|z^gnO6rHn-g%B+7`@-z8yV*uUMseHYcPyI_a31%gd(xlwm@Yl*#S!3nI`zM&)80 zfp!xzxp5XgD-`>=UtxM=ME4**ST~hmQRpdxBv(>^OR2MfXH;82uxKknB>$Jooo%}R za<~c4`=x4t!{6lpdxuj1jPbud(EQ3Hf0V`H02NRFVDZ0YUjEMFs(#bnS z1tBJ=fB?3{Hy`T-ylwIVv zbgqj|WLVSi7GKEN-S~MV5oirLHzny%)vD{Fy*ZtWIGsZmZZ;-ZXAN|v8hF3LT~@+# z@@1B@Z_VDg5GoQx{+DS_1-WMw@Hkv>dVe^uToz~P4kS> zZ)G3nX3h0I>E?=&V9U&_9#YqhDU&I+uElq$lw5L{THJGBP)h&8sI#duW*lJ!UoBzp4wWYG)3rI zFAosP&%dfwd|u~UU-NnL6<#T*R&T7z)prg3%9(E7R{RO4vqdkP>rz7QmgN=tHLktA z)J{PkqJjK|j#vaHL2wHRybq)xxQx&$yf~`!8x>~%!yTL9Cz=)&&ZMsfkyiHzd!v+F zTc7A)X@jRYO~DI=L^x-5Csa~YT6xmH5Mjz3QiO>%NM%c_i&9lB6kz2>TIx}#eW=DR zq!Z)p*-bu;V=Fx00--8{MNR#f<6vQ<1vrE#;7vfa*=YDx#~LFV;JyRlh}j|2L+NU^ zj{jb85#a`I5R0aWMi?x=64B7{+jx|=)h%kQwS8d;h4 zY^_b=$9g~(=LR<_sS<4Q=oH-N{Au&&t?OqE7f+3PB|Knm-Ss6#Gws z4+ELPCW8)RmI0~IOn^)n1xN{OgQ)tKgO>x(!q$Ub)p7qPN|Fxmdlod{Cicx)|CS!V zu-_j=4^lv|?my7uZ#kI1dEhlwTaI03L-M&*NAhsg(m**aViO2}kXTQ2o$LVji8nP( z9h7P$J?6sPS{IHGj>rIlo!~Ne-*E^{rG>d@+&>s-Jm62#W{q#PFR$fH*i^rGdFd2L zbQ0&-CMx9G+^(h=)Zfji-|cu`{pftMY~{>X#Fdjf;4&AWlapa(F&KrjB7r|}&a{Hw zf9yJPsGKry_kCcOjh|K23omXu+9*-)O9#vI50}$H*bz%P@{2Y2-1fO1?{$515}eGA z&o^!+@=kP4jr{S0DzXF)-<&djoa8$Nne%0}kqO2fv$kFBV!B0MHot1`g3Cn8##X<} zeI!%hiW%c;sXnmE6QM&r@W$3X>=qc<$ z`gF^C9_9JPN%#56+iI}F`f@9l=63z_+EKO7r9d?S_9KC>KE$o#Ls@AY7g8KwU=LO& zXEcZybYY-kuZ2N9!$(DPlqaUrOyAkmdF*i)%KCgA*napg5A1n}^H{=8+EmoVwaJeC z>B*9Cu#7b9q|L#kTkJ{Y!@8<{3Xl4c=HU(tF#j6J3G4I(MO_&S11 zlT!~Gkdet&fo@FB)N3l_$RPxh`CGmcrje)D8Ndoe zqPf%9AMsFxn}BO-(D|bcMHUH0Rfgk5;6R(0DpkWBz*2|~kxZq)4k|KXbK|&C#~YcU zqaaeED>VWBC6#iNNm?96B3~l#I zyr5hle^3^f9|R}#3tU~@u+-LgkvYi&bM40YxA3BjSz0@}8ry_!gJq(i?nY6FMJk#E z+bG=X@^_1kj*kPd2on8ft$mG@xeZvNU^HJu4uP@7&Obtp(4W&GQbiN-Bp3IALlH$2 z=~T{<&KaO}+gw-GfE7aN$-aK5#}+-a!d|C~CUU-x`pnd*Q+&R$xDq*1+{z<9P=2aA zO^<0qu?0*=g*^w@dYJ^?y}ucikBHMed@Vk=f36g+<9}jq6~)f83Hl}tC<2~P!_ zf};Xl&Q=DYVy^&NwwQ;Z&?YD?Fmg=w^XJaee_EQY-DB1y0rYuu=D(%SFYNnA(Z>SN zw*3$E`CHY&Z>|$e0ddy=`T)AckXo84X(D>(mj#=@~!}7VYfbmmIhWR4_Nn)3f8Yvwo&cRt7HXD#lJm1D%Tl1Nz-=b|BzOLKd9@_K!c|M)r#@T4igk_%| zq|Ph%uIXlC`UQJ?`raD49cPleKEwT#fAYhAGEc)lxX(xEyF}}D1j8k!b5!B5!iA5; z5DzoPc2VorJpW933OAd2%9N0)^ll_1K}*A7hj%K>I(nmpxq`Q#sW!{WmPg7LlGlr_7O@69QhE(3kcoB zhz<5oG#*tm{b+)Udh=u7MCb3 zXOWiaZftoT;%90mNE=4`3&69G0xL+Ffk=BEr0W!BAmzMB$$+GS15>Vep)b0i@vj4Z zVmdOEVrmzCSBB!kh&P9L?(gTk4ePU zm*ni=oCyphjZsN-V*LcpYa1lsIc^vGa($p-zaB#pPfe&fdsEJ*=5w0q+wLtyj(Y~D zo}UQGqiIv)9G?B|v_kmn$@2c8{R55GjK)pxRe!B0u;M} z{U6}vakxlh>SPtJBs%4Ot2Xpb zTy94W*9MEF&jTk4H>2@NC$aX=Jl4c=pItmY^?Ny4dY(_+mX2(?dbR6aTIuhoPVYW1 zzh9qU?rm9LHM6mw`Eua3std6uevZ)ceVg`fMyCT_M|o@g+C!wSs*rHWNv#e_>C;PYCg- z!rsYEEC-r!b0QM4X2loQcg_9f({Aa*y7}3u!aMg>SiG0B-=q-&&{AMN}{E@ z(o-$Y4Keg&`n9ta9`-4q5d5^*728kb&(e*(N83+d!4AN2E@i zU@lj{Kb|Gxm%|zH!t;e``rXcWX=&(_2N&a&YJMKxBItUS1vf*`q^ki$;c*vSkBm*) zaTo4bW$YrtjMNo!UtS2Kj>EE2j1HlufFv^&XpMhD{~qdzoF$D+H_ z!bx1~KF7rN4~ZHpmebiB?erK@U34WyEF%MhJrPD<5{H31QIPd`EL=_JSzXw5Cu;}T z-6zwVn{b|<9-2Ggv$Z0;&+XPHruP_l(!-jz1}W{4T=wQu3e1CMoiC3w47p1LPj9s9e1px% zk_+NsTPg#gD1r6ad8CkpLT4szYIeK8*5+$fGVgP_V0%+)>E&bO)Sy?_;j+2-xTbDDQ4^{gg!p_PbvvB!dLs8l zNq&{1(d~8?&$`*>hn;S*#Bz)vYcN-dkbyM_Jr3Uw5e+hg+A1 zhvQp)KE9``fv{ovgXeMrSNhL!y4NQ&?N{0sPp59D>ZP?_<#M?KFX*p+Jh!=BuM4_< zM?yaq#|<2VIW9ONIZ8aJV!2|;V%cKp?oE2PpoUPYbNt3h<|W%U-B|7GQCF-AtB|6D zX4VJp9+Jswzj0LoM;pT6QV>tzLOJCzu7$yp20&9w5yU2164UI$V7U$FaT4v;jWJlK zxQbbTB8(<*raDe-`a4WPQP#u_x4@+eaarRwO>rF+I?=r^R+Z8k%{q^m#7+8Oc^uF+ z!0B!j$oLU#8KtLR71bv5AY*NTvCII0J96~y2s|2$Bgx4O2qpge zXqLe8Tp;YId?w>b8nHHNg#YApO1%G#z0gmR_ymiAfdY=DOkgOiNmS&C%j9qlRw z1IM^p3t-Ft`o(V9@u-ba-$O|M^JcqXsB!aH?zoHhMr)c|_HDob&NSC*!0k&M$?JUY zk`0!m-ri1cr%`wMLSQPedDG(G(Tb^liHcJu32VAE8< zo>L4i^zU6DC%aquf$~Saud4G#>$9r*1d*%j{kviO1+^RvA!tgr!K;G~O{*B4S*<_a z4-N_}JF{DjXW4_K8@SuAE_DxoKIy2>x4PR_%j)x7Ki_+Hu6DGyr#uR)o@90$>Bny8 zui?`_pSTX(V0ex_Xt~Y5Kk+$-DW>Qjy_?YKM64wn>8uzjvw3JeET8qMMJb*kt(*hb zDsPSA8dO4R_pr%4G`Rm@WnFL*n>yOU-OdL2RUX0b(noQcYGhLFSz28@sdz2ZURJx| z(L|}3tYo^yK6aFUb4j#q2qrBuQtH{& zd-l__#TD}N{*ER7SjY?{1~Sdy&(~-~m5eC6%asf#j!c3p(_lTtkY@o!n zHoF3^KHdpj1x$gX2Qt9aCr)vQdXo&97ELHwgNt!E^hu5m6*PLPvpe1x)2&-00R|GTBJ;e7J~RB7ziDTaayADBjkK(B!JYPoX%Hjy8(5M znl`L8>pk83)-r;zQH(kl)IOmg5Tu|I2%T?&sVef+Zgyqv+U1AZF8JK=;74sHK%QPO znJP=!L)sspo`F@ng(QyPY>v=`CPCP1&x&9$)Dw0xeo`Hgtx!-_mr%D#N@tsN*I8m{ z$QPI_vNV#~4J41oLwY%>6*d_T5d|79K9O96u$Z9AKtZ(O%LfJ8_~K-Qb^g;t)u*#lMi$TpTKt4s}|K57V_bqH(x(8e(&WtORVVn{Q%HjSXmw`RAB9WmSXuxCy z!VdyxNz~q_!h>LBWtYZ1=pcq9(^%y59YyKFsVjbmQCed3s>O*060F-q^x+#F6e%K+ zq0+_O7?j3lxNga`HoqL2R4A-hz z?+}ZsEVKPL@S|0k9A!R2^OeL^QGDXFMY5sA`0UgQ4VH_u)UK$6@Jd;}uHC3oO%%c^ zFz+2nrd-d&@4Go9<^=F<<%b!qnI%K+!&TD~9~-B*M#1U$x>-AL9IAEYD@vy%TEEFB zY@SVWd5^}NM~#+l2ve%R2ZX9HePU8pRZ=ZEC_0c~m1Iq~O0r^}C7m@bmoFcmiJysA z59kN3u%n{?j94QuNDW4VeDMxA3O9H0^=<3?`V-=PJOJWvfcv)){{;pAD2Q7FYBk^e z&!UXq<$C>M->j-IBGt!$wt7oV_eII_vW(#e8d!)UaUp^$d$Yt;1w5M%iDiYK{gh&4 zMb-fC?gwGY72^sk;v@3!JppwTJZglU8xAz%WX`l(G@WA$Y$Nt4QXBbS47j55mT$-2 zZMa||*Wo;8Nafora0E+oALrk6xN%GEdXSZ)h*-)$SxAJ;!0CMhiN+3y^>ln2E7i!>*2e|k9Vqv7>}w((yBVD@!kf)rhbd$Og4ces2_1JoA12or%Wh# zIn*pjCq^!~3M6xf)fT4Vz3OLrzjo(4z+t%I-Eq%UXFare+=f#D)S|6L+`(U!t{yn0 z`&U3fKySa`?^QzjkMH`w`H@fyTtS)#G}lV+H1RHTk#R4e#bnVFeQ&6ZIsj=0agg`Cq<3#?;nGD8M8$#timdENe><>HjG{qvWt=)be7>EPy3nmRHH(lI?%0!S( zas2s`Ndm$Q54~ zRt^rhY9ZL*Lj~Z2IVGhrceS$xlTQmi4Fd70IG`s@&7Ki|0QnrS7lCK;3HcCEF=jFr zu)3#wK$zU<)Wm>|S(Szm~lCt8k&{d(1&MXmh>`|m)opOmp z37A$AR|}}Rp13AaG4)n=CKs^p2sdg&fu1s2h&ziEZA~@fB?6v1)Js&pcy1C*ntUhaH5t zu;N?~>-1O6o#nMOSEV=XSdPU-3cf(>s@%gfokCU}^0s{GRRN1J9>t7Ocv9jNP82x# z`NFoRf89F@95Rh+0(AJcO#e!UzgWvZN{4}f%hlhp?Qgrj-xRvJC{4=s077)u)mP4n zAX*!7DB{yB0_h=A264{wm&;k0*ji)v*O%))Du(;CH0|a%*?BE91dDgb&T}TMPt?FD z4W<9YCh26*r&%UK)6Pp11Lb));fNG^rXn#2J0xhs51Yw9@btK z9N3^_$_m|EVyTe9m<$u5l3f@bb}vUNhWzfZ`Y>li>QT->9!YEgEp_~hX&9=A*gHhM zbu;>?uv<=r;L?DFl1#46iRJSc38<;ZH5Mq>L_a~z2=x23#>`c#vgw(k{rAtDGqq!L zt$ReZ2}^)xY#c|~>MKeM9zM;&OeG!d3g1IxcdW^Lea11>-eKV{zPsU**aifzgX)(N~c_alg#gQ`nMLV-|*5!Symp9nb8i&N95?Hapa3qp`5@#tW$+HPVHi=8_%j0P+&aN@i7Sm1U?OJrUBU*RW3g)uXp4*-XXvoK& zLHMoLjSbUP^86*xQXahto9b!M-&S!#$jM(K8^a?aB1 z99h_)_ZHtbJ~FTg658En{R!P>Ej5vvk6W;r;w-t!WpGsr2g_r?Lik6 zx;m8RUR}0G!#`%n@6M?hO`B*HbN(a39RsDtM+84xtUMiysv>+c|La*HzvQA^K$GtH zR7b^J2j4(we*>O=G*cW?@Q1h$!Qb#>kTcv_1T78}=gkE;oVJRX*{GV0VHj2tnMEKg$0%Eto|JZ0YG<-Amzn1;+2@FDUW3u04jP^K zQ6-aE_$iCXWv=!>@?hs`^E9&^n7X@e-3j0B9~&AC%+A8 zEBA1FIaK4R+aU?3)jh0ByC*6C{Pf8AbvK=LQ|0&w|E{;0I(H^q!kvWAcOMfz489NM zZ1G;p=p!6}0H?c0x%SJssG<3DCK+`TF>2{SVobem%Y^T4fu|zbbd~oF>df1hWVf24=~K zdvPH}pbdy!eK_|IqXskOkx^{cOqtM<#Dj>Gv88)zGDCglv5azvzYgINCvJyvjA2&QEW>0dplscYEEnZ0NCM8E&s|6zmU`)We0OW z+tBaq@QZ$+UtHg~sQlFc*M3P|$!kk(bVmMv-OyIC(|7!|DRR~m2R>S zDUMt9RHm&~A)ViI^lhZA_;{^wW*HE%o;yVss~SVWFyYLEwIar28tC@4+a$BwB-GE7E0c3mCdByO-K^ z4g~Fww^9@kncvr^mJGl?!S33aDs*wD(Hzw_KwDzpyr<_DRX{oG)1t3y#)FE-SZuS~ z75T^}oB!^yeyHB?^(M>v3neG7_xf0=65^a*+a zR!5K1A?niTy0Mn0hZ+4~+px`)(F>79?FO*C{PotXSi6){epBi%4H&>GNc0ka0mH6_x%KToryhU(+f z{jS1<@A0KXeX{9d6%E~yKALh=PfuoD_KIq;Y?-TA<}aK{d`A`J@7l%7L3mJ@t?k%) zS4xMF2U&+sHfXRZK!~6)9}UNSMaXy_a7OpFle|PP3aY`usyY^oTY;yuNAm-zgiKdN zk1&u7?~IatM11o*DeNMq5Apeq)dG1vLk2rW1PXCLn+G8aFpFRrm%5PENiJJ z;m)@YP^lw9FS-OaO1mfcaaPOXDRHa$`B7?eYD+1WjvCS2&5Y7BeRs>Lfp$K#;9gix zRC>6Cs?|#LS1>E~zd9vW?{zqxsqh*!K!tWgRNA%k%B;>1hhF z@h}KF*Z3f^Ol58Xu6sUi3X|tQfg0a4QnMe~-7F_k4?AeltE+tVX-FGIkiE`4T7HOl z)`{jvkdMAO-9FQcJ@wPa?p9(P(G5v=9+Z;&ET?yuA|&65GMv)LgQ^hBVes*YQnhL5K(BYe_MaRX1rtnM-Eb zfrOZGPBeZBRN+5BA5;>$`yW}SVO zbju3fBNi+9V`=M=)y0alto)o$=c(PrlQWm;Z29-{lJSR4GVR&>oeBD|aBm4b&D_IA zClC8U<`E0Au>P>|CPZX&>}iBtpJ&&{?U&wL?jGjWG}h&V{pRwa*?eECk2Fr}>QReF z6LXz|9oG1Zas79W?k2rntY6hPA9FDg57y@FI5l=?Z`ItX+f~=B>|yO=n%K6mQPjk5 zzCowzpocnIh7F*d-i&IG^Abcr@@F^}rcJGla>DF!P#nr_zla|380Mu@l^N(LzUB$! zBx9jX4jNa5z7Q$)p|D%$=SDwqCANtR@uPbPvVE^0{v1dxN~0?zzhzNS2o*rg8WPLK z^#N_L=K+g@$(^II28sjGJuSy^H46_64$N_KJ<`eFJ47-#oFSJ_Nt_N`82bJ)ewP^Vh>j>tUiM+w$>nyPa3YV8<&GIL4yTuua%Ho!U-}1agmkrDhx`i z5!5?@FAPU#86eV%c_5=>DfQO{@|>}5V1CHWZ?Y&-(B7)QBZ?1E-cWLkF8JzhvK4Xw zM+1sJ&hwto%$?1Y5eO@?LnEW2%}Q1%Abgd~{wJn=LrF7fqQFCMi&WS$1#? zQi$W@q^~a@~Jl#6Tg0cnlHXD879gJDvldES1asve3(wB z8zw?H;PS;EaQWg769?lj6({9S6-VW76=&s-flmu$#bX6z#cO4Vp5L6h_WW1iX_D;p z-2wmvZ#MaNAozus{wNTv0s1R`3xdDBQ2ql5-iB=Ls#kIVOC4ul`!)j7mqNUMQ+qd z%Ub>gY?A`3cEO-{PL6`>a58Da>7*iUk{nlL8)23N& zd80Mvy$g4uN|0h7t<1EIJ_HB9?@i=$mt~;x$s5>E{m*e|krEY<{-{846c_omPVYcX zc6nTu&aN4q!ppOJx0x;$E@wd(Z^#`x-dVg?k&;GyMqgtLQVL;~EWkrCr8v@d%GwL< zi$;sAS;x%ykr2)s*q6i3^flljOnI};DWDG=i-NDELkY2ch7<+GO*kGoIRz9xrj{rW zCTN4~Jmn%quB)pLX(7D*TeHYVtlHGO`bP3laT;1nG;3ze(fMZd5~NNtA^8zglJ0~O ziB?iwR!318iTP=ErI1XFhvpkwd}uJa2ts>YLliILp>)D(Q)7E)?_*UNDd4n0AfREG zHpr|qp&L#i8B{=a*(2NyG^5(*1;}KmI>bBb+iwZVl36LnuQCRxe4Lmoz*Fcgpj)fQ zd!Ld~Z#0fTiHhjUA*Y675puE;PaT+Lh+d}ThCu_lx!A0Pa(jgo#GM3z;=c$s?AL-| zp7lgCbR#>^n%awz=-!=0djM4vDxAkNSwUc-tIK)MJ%F&B#t$1db07*ueXXvjCr%s5Mc|?#iUcXLs;O6c`q!c0AtJ974e&tmX0d+>jiw$_bnbEFk){7u(f_Eb$I`gU=nHP&OU^rpTPi`Fh>?`~FD+ImNg9J#U+ zjZ(-(XGumKvnz-DJ=bZL@uDz12OqTNAj7ErWx zcbXGzG<~sB{)($k+P0KRKZ}BLdpmn<)A)Hr-^Q&h=f{BU?Z6AP(ydPYxajTE?$^M! zQge1Zv9rQ6;{)-1@$G@{aZ7RE;@Ey%`2!Vm1ARXSfTs*aJq$@s$`ylw=9C3mb?i(p$pDHWYZuH=9fT z?io3UW3yk0Fz^e;<`BL-qyREdul9LQonXqNWOSj}R}qHc5h0SYN*d4moW>sND*-V1 zG{M$L%+?RzV2^7Q5@RgWPT4ZnqFCr)C2W?)C3u3|;OcDI{3*Zo8_-~JriDhHD~KWN ze~IctgXop~88>oT4+24!(Is}o94&1Uf$SAAGTZ(Ezm|nWu~HTlHo}T=u0*KX!5}y* zbVMSMR5HQY>Av4G>!Ul<3kmv5olZ-e6E6x>7K-4SMi0r&xA+Xg>SAO2Isr1=0$xh+ zJYrBF3hE<#haT8PbLiS=j!e0Q(pvd&Mx*i+CaNizK&4^?(CtWEh?iXXk;ER-9r>&@ zE+mB8Y0)U~Vo@519#~DdEr^=>`t9HWvj^w7jhS|nygZqj0D-bJMUN3mNLsTX&2Q|F z;C^7dDt%@C+eQ2Wc9cJL*q8=?v;`kvlB8gx=VnYH;+pr;{QPL9ltqxkpll9NpF z#^*Snmj{M+lQ2xO=6JW273j_-n+5u?*keT9-lfz|gw>9dK0mugFGPP*o^2}OhWFsFV=r^>A4o;) z^!1c*E$f22nLX9#d%n3Y<>zBoJbzSutn=dIXFKY(zFe`(fA`|otY4+qwqx(g)3E+y z{BeK$kX@noboI`Q{rTngpgT-ozW0zr2ul>p6iXG$1xpso7E2e)=Q}fbH1_+FV8-1O zxOMofW%uJI-YjH7rjBx1~=0mxyP!4Dl(ZDYM`*YJI9C>Wl*r zM187c>Up(8#B}$R11fZ2Bwu1&k&hk2WKLI)2ptI{rC;>MfDgn-v59};!zGZ-PI1g^ zWGVQ^yYG9IqQC_?nF6uOg+^_K35Q>SprA-kneD-kNn1pKv=6gyX$+jf6%&Viu)8U_ zgGlW`x&Wo0bJj6Mrw$!m4Ry zOq6zqoF-@qlnD(aplEpQkE$cVC-0A4P^l9?Zj_B=6g*>f?EDQKEJO+&A`+bv?kT%! zd#H!>XN8gx4)DO~Vf3)(p=dSuAP8qRgy+qKB~T!qET}_Z4xL{E10n)!tVO!puAow- zGd>u2)GjcTmiiG&0}C=f=r@rIh~1LGE1O~>SWnLgqtY_bgn%n}5ntu9qqE)iWQ7i| zcsYq#c<2Bd((-Cb)+=Or8w7g_lKuDOk)oBU=pZ`jR_3q~-fKh2FcL~5=&%zsR6xz| z0upZfqtHl)bZ7|LM35OUb*9$|-w(aZe_8>74u{??@dYmJn@kR%cLcGzW59?o-b)Cj z!w?meL`nJ)5=$1GXAKjP;zZ23uHWb~-yqA*o-!?1gK+#YV{XdRu5I2h>;cH0*P2jB zzBRU~_SqqU2XTIsk-6>BvANoi8jPB-0!l5Ql1YQKuG~O%usleWxB^-&sFF>CwyxE{ zW$++q))*rJ7s-{G_d6nyU>DqbrLSYduWt{H#llg{^8gOMQR3fm@E0igqd2GqILqSy z=cUBb?tdQy^qW1JYJ$Fe5CdBO`aK%EmtfK)NT&1(3aadt?X>86G-B~eOlB3h)Z!Cr zXB&8^u_WpVZ>N`>WP(J=Bk{wXkFmX4boJAgpEKA%x0?m-n@%Xs@lkEp}b!DG!B- zI3}P?q)^iS@ow<-`s;4$!0f||3-pNsY+U`yJY`Q=A1^7g)3e1!3Ph7ahd4oLU0Io} z$@F03cU;8P+bQxiMGE{(AH#X!I%7 z06coXt<>+eNclfr5dMFc^N*5a@Bbplznyn}6W*_ysQnh+AF_UrUf5Bi9RN>KHKU?s zscyBtWINNL`e^W-1)G)4fZLEB5dS)A`W_`Q{q#Ghv6uq_zrsj6$_^fvq2N0-1Zs-c zuHG9{r2IJrlYXkv>gk_kKXFg2LCe{oiq@?PgNfIPh9CCK)ImmpLqs_eNFlv;-?eRg zJ>(*z?k3^fiH%epR6QL2@#DQ`j;D~Z&k2Ma=ZFSIAMK)B?zR3sW)rU@-aF!-@O{|S zb2M?NX=njvKRmkYz)Q2q4pRoSHUmGF%i<{KmSuQ{_?fMD%~gEC)@m;77HrjXEwwKS z`B+$QbQq$-9*g#T?8d&QZjPxUbRubdkZQrQzlxSSK%jVa`8K5D`5yR5d{wMydqd;B zPQ7~`lX*u+bBtCHw}pO`{-(9@KI?4=T*%S=+To%*#J<})TDVO|B^}Ps!_UN0OA)2` zn6S9fji|D@taHj|EBNjo_^QypA!RJ4%1o!cIzEYcflt}LH14txSW4W3y|Ggk)5z?t z0`F}p|FvF!vEF}_Ug-cIiGRZ9-?qWOdG`X01^R!3RRH<=N5z(HfX8MfFX<&!uP9H3 zZ;N=Qwr_(~C|=vy7Bm$|iwtwz%+_l2DSjl){LE|i2uwgEjNVdXQ+N$+TaD8URs*G8 zB%`!)3K2W*10v87@?s`POh%0DkE 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

Hea*`xh?&%5sCU-Hga>cQj(WV3MuM=#%2&#Bm7J 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 literal 0 HcmV?d00001 diff --git a/uv.lock b/uv.lock index 812e3df7c..8db53de16 100644 --- a/uv.lock +++ b/uv.lock @@ -1562,7 +1562,7 @@ dependencies = [ { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "scikit-learn" }, { name = "tensorboard" }, - { name = "torch", marker = "python_full_version < '3.13' and sys_platform == 'darwin'" }, + { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "tqdm" }, { name = "typing-extensions" }, ] @@ -1619,7 +1619,7 @@ requires-dist = [ { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "tensorboard", specifier = ">=2.17.0" }, - { name = "torch", marker = "python_full_version < '3.13' and sys_platform == 'darwin'", specifier = ">=2.7.1,<2.8.0" }, + { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.7.1,<2.8.0" }, { name = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, ] From 3346842d2b437739dbcec32532d5bb2c6fe1d9ae Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Sun, 3 Aug 2025 19:11:03 +0200 Subject: [PATCH 13/98] Fix issue with Python 3.13 --- pyproject.toml | 2 +- uv.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 84b31abd6..7224218bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "torch>=2.7.1,<2.8.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1", - "qiskit-ibm-ai-local-transpiler>=0.3.2" + "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'" ] classifiers = [ diff --git a/uv.lock b/uv.lock index 8db53de16..25bf474e6 100644 --- a/uv.lock +++ b/uv.lock @@ -1555,7 +1555,7 @@ dependencies = [ { name = "pytket" }, { name = "pytket-qiskit" }, { name = "qiskit" }, - { name = "qiskit-ibm-ai-local-transpiler" }, + { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'" }, { name = "qiskit-ibm-transpiler" }, { name = "rich" }, { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, @@ -1613,7 +1613,7 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = "!=1.3.2" }, - { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.3.2" }, + { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = ">=0.3.2" }, { name = "qiskit-ibm-transpiler", specifier = ">=0.11.1" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, @@ -2796,10 +2796,10 @@ name = "qiskit-ibm-ai-local-transpiler" version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jsonschema" }, - { name = "networkx" }, - { name = "qiskit" }, - { name = "qiskit-ibm-runtime" }, + { name = "jsonschema", marker = "python_full_version < '3.13'" }, + { name = "networkx", marker = "python_full_version < '3.13'" }, + { name = "qiskit", marker = "python_full_version < '3.13'" }, + { name = "qiskit-ibm-runtime", marker = "python_full_version < '3.13'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/a2/2b/d4a31925f23a4614587bd256f1a5b46d53f667971243df2bff62ceb1286e/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6b13b0978b0bb906c1175a63b1c2c00070ed7f3ff9c302d9b8a8e104f5a8ec39", size = 97513406, upload-time = "2025-07-02T15:25:39.934Z" }, From 6c67349fb0dab8d99f0c4257982e435cc261f6a7 Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Sun, 3 Aug 2025 21:08:34 +0200 Subject: [PATCH 14/98] Remove Python 3.13 from noxfile.py due to compatibility issue --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 9e13b37f9..9fe9986e4 100644 --- a/noxfile.py +++ b/noxfile.py @@ -29,7 +29,7 @@ # TODO(denialhaag): Add 3.14 when all dependencies support it # https://github.com/munich-quantum-toolkit/predictor/issues/420 -PYTHON_ALL_VERSIONS = ["3.10", "3.11", "3.12", "3.13"] +PYTHON_ALL_VERSIONS = ["3.10", "3.11", "3.12"] if os.environ.get("CI", None): nox.options.error_on_missing_interpreters = True From 2692b96c191e6a4e03e5cfb25d3101c9f414702d Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Mon, 4 Aug 2025 16:52:26 +0200 Subject: [PATCH 15/98] Skip minimums session on Windows due to CI slowness --- noxfile.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/noxfile.py b/noxfile.py index 9fe9986e4..8a7e78ddc 100644 --- a/noxfile.py +++ b/noxfile.py @@ -12,6 +12,7 @@ import argparse import os +import platform import shutil from typing import TYPE_CHECKING @@ -82,6 +83,9 @@ def tests(session: nox.Session) -> None: @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) def minimums(session: nox.Session) -> None: """Test the minimum versions of dependencies.""" + if platform.system() == "Windows": + session.skip("Too slow on Windows — skipping minimums session.") + return _run_tests( session, install_args=["--resolution=lowest-direct"], From f4874e60c77bccce33181451f9603b8df0e1c74b Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Tue, 5 Aug 2025 15:25:40 +0200 Subject: [PATCH 16/98] Fix bugs Fix bugs Fix bugs Fix bugs --- src/mqt/predictor/rl/actions.py | 74 ++++---------------------- src/mqt/predictor/rl/predictorenv.py | 11 ++-- tests/compilation/test_predictor_rl.py | 6 +-- 3 files changed, 19 insertions(+), 72 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 58609b4e5..dc2e13717 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -50,7 +50,6 @@ from qiskit.transpiler import CouplingMap from qiskit.transpiler.passes import ( ApplyLayout, - BasicSwap, BasisTranslator, Collect2qBlocks, CollectCliffords, @@ -125,6 +124,7 @@ class Action: pass_type: PassType transpile_pass: ( list[qiskit_BasePass | tket_BasePass] + | Callable[..., list[Any]] | Callable[..., list[qiskit_BasePass | tket_BasePass]] | Callable[ ..., @@ -144,7 +144,8 @@ class DeviceDependentAction(Action): """Action that represents a device-specific compilation pass that can be applied to a specific device.""" transpile_pass: ( - Callable[..., list[qiskit_BasePass | tket_BasePass]] + Callable[..., list[Any]] + | Callable[..., list[qiskit_BasePass | tket_BasePass]] | Callable[ ..., Callable[..., tuple[Any, ...] | Circuit], @@ -466,7 +467,7 @@ def get_openqasm_gates() -> list[str]: register_action( DeviceDependentAction( - "SabreLayout+BasicSwap", + "SabreLayout+AIRouting", CompilationOrigin.QISKIT, PassType.MAPPING, stochastic=True, @@ -482,26 +483,19 @@ def get_openqasm_gates() -> list[str]: FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), EnlargeWithAncilla(), ApplyLayout(), - BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="improve"), ], ) ) register_action( DeviceDependentAction( - "SabreLayout+AIRouting", + "AIRouting", CompilationOrigin.QISKIT, PassType.MAPPING, stochastic=True, - transpile_pass=lambda device, max_iteration=(20, 20): [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=True, - layout_trials=max_iteration[0], - swap_trials=max_iteration[1], - max_iterations=4, - seed=None, - ), + transpile_pass=lambda device: [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), EnlargeWithAncilla(), ApplyLayout(), @@ -532,20 +526,6 @@ def get_openqasm_gates() -> list[str]: ) ) -register_action( - DeviceDependentAction( - name="DenseLayout+BasicSwap", - origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, - transpile_pass=lambda device: [ - DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), - ], - ) -) register_action( DeviceDependentAction( @@ -579,45 +559,11 @@ def get_openqasm_gates() -> list[str]: FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), EnlargeWithAncilla(), ApplyLayout(), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="improve"), ], ) ) -register_action( - DeviceDependentAction( - name="VF2Layout+BasicSwap", - origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, - transpile_pass=lambda device: [ - VF2Layout( - coupling_map=CouplingMap(device.build_coupling_map()), - target=device, - ), - ConditionalController( - [ - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - == VF2LayoutStopReason.SOLUTION_FOUND, - ), - ConditionalController( - [ - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - # Run if VF2Layout did not find a solution - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - != VF2LayoutStopReason.SOLUTION_FOUND, - ), - BasicSwap(coupling_map=CouplingMap(device.build_coupling_map())), - ], - ) -) register_action( DeviceDependentAction( @@ -691,7 +637,7 @@ def get_openqasm_gates() -> list[str]: condition=lambda property_set: property_set["VF2Layout_stop_reason"] != VF2LayoutStopReason.SOLUTION_FOUND, ), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="improve"), ], ) ) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 5f1d4603e..14983a0a1 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -188,6 +188,7 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any RuntimeError: If no valid actions are left. """ self.used_actions.append(str(self.action_set[action].name)) + logger.info(f"Applying: {self.action_set[action].name!s}") altered_qc = self.apply_action(action) if not altered_qc: return ( @@ -377,9 +378,9 @@ def metric_fn(circ: QuantumCircuit) -> float: pm = PassManager(transpile_pass) altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} - if action_index in (self.actions_mapping_indices + self.actions_final_optimization_indices): - pm_property_set = dict(pm.property_set) - altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) + if action_index in (self.actions_mapping_indices + self.actions_final_optimization_indices): + pm_property_set = dict(pm.property_set) + altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) return altered_qc @@ -466,7 +467,7 @@ def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCirc def determine_valid_actions_for_state(self) -> list[int]: """Determines and returns the valid actions for the current state.""" - check_nat_gates = GatesInBasis(target=self.device) + check_nat_gates = GatesInBasis(basis_gates=self.device.operation_names) check_nat_gates(self.state) only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] @@ -477,7 +478,7 @@ def determine_valid_actions_for_state(self) -> list[int]: if not only_nat_gates: # not native gates yet return self.actions_synthesis_indices + self.actions_opt_indices - if mapped and self.layout is not None: # The circuit is correctly mapped. + if mapped and self.layout is not None: # The circuit is correctly mapped return [self.action_terminate_index, *self.actions_opt_indices, *self.actions_final_optimization_indices] # The circuit is not mapped yet # Or the circuit was mapped but some optimization actions change its structure and the circuit is again unmapped diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index b7001d65b..ac62c2fae 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -37,7 +37,7 @@ def test_predictor_env_reset_from_string() -> None: device = get_device("ibm_eagle_127") predictor = Predictor(figure_of_merit="expected_fidelity", device=device) qasm_path = Path("test.qasm") - qc = get_benchmark("dj", BenchmarkLevel.ALG, 3) + qc = get_benchmark("dj", BenchmarkLevel.INDEP, 3) with qasm_path.open("w", encoding="utf-8") as f: dump(qc, f) assert predictor.env.reset(qc=qasm_path)[0] == create_feature_dict(qc) @@ -69,7 +69,7 @@ def test_qcompile_with_newly_trained_models() -> None: """ figure_of_merit = "expected_fidelity" device = get_device("ibm_falcon_127") - qc = get_benchmark("ghz", BenchmarkLevel.ALG, 3) + qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 3) predictor = Predictor(figure_of_merit=figure_of_merit, device=device) model_name = "model_" + figure_of_merit + "_" + device.description @@ -95,7 +95,7 @@ def test_qcompile_with_newly_trained_models() -> None: def test_qcompile_with_false_input() -> None: """Test the qcompile function with false input.""" - qc = get_benchmark("dj", BenchmarkLevel.ALG, 5) + qc = get_benchmark("dj", BenchmarkLevel.INDEP, 5) with pytest.raises(ValueError, match=re.escape("figure_of_merit must not be None if predictor_singleton is None.")): rl_compile(qc, device=get_device("quantinuum_h2_56"), figure_of_merit=None) with pytest.raises(ValueError, match=re.escape("device must not be None if predictor_singleton is None.")): From 54eec91444622a0d23097c08e7dcf3f14e21ea2e Mon Sep 17 00:00:00 2001 From: Liu Keyu Date: Tue, 5 Aug 2025 17:22:14 +0200 Subject: [PATCH 17/98] Fix bugs --- noxfile.py | 4 + pyproject.toml | 2 +- src/mqt/predictor/ml/predictor.py | 8 +- src/mqt/predictor/rl/actions.py | 1 + src/mqt/predictor/rl/predictorenv.py | 7 +- uv.lock | 448 +++++++++++---------------- 6 files changed, 190 insertions(+), 280 deletions(-) diff --git a/noxfile.py b/noxfile.py index 8a7e78ddc..ee7980b69 100644 --- a/noxfile.py +++ b/noxfile.py @@ -67,7 +67,9 @@ def _run_tests( "test", *install_args, "pytest", + "-v", *pytest_run_args, + "--disable-warnings", *session.posargs, "--cov-config=pyproject.toml", env=env, @@ -137,5 +139,7 @@ def docs(session: nox.Session) -> None: "--frozen", "sphinx-autobuild" if serve else "sphinx-build", *shared_args, + "-v", + "--disable-warnings", env=env, ) diff --git a/pyproject.toml b/pyproject.toml index 742cba154..e161979cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 - "torch>=2.7.1,<2.8.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. + "torch>=2.7.1,<2.8.0", "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1", "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'" diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 3f0ec5497..3b844caf2 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -205,8 +205,7 @@ def compile_training_circuits( self, path_uncompiled_circuits: Path | None = None, path_compiled_circuits: Path | None = None, - timeout: int = 600, - num_workers: int = -1, + timeout: int = 6000, ) -> None: """Compiles all circuits in the given directory with the given timeout and saves them in the given directory. @@ -227,7 +226,7 @@ def compile_training_circuits( with zipfile.ZipFile(str(path_zip), "r") as zip_ref: zip_ref.extractall(path_uncompiled_circuits) - Parallel(n_jobs=num_workers, verbose=100)( + Parallel(n_jobs=1, verbose=100)( delayed(self._compile_all_circuits_devicewise)( device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level ) @@ -239,7 +238,6 @@ def generate_training_data( path_uncompiled_circuits: Path | None = None, path_compiled_circuits: Path | None = None, path_training_data: Path | None = None, - num_workers: int = -1, ) -> None: """Creates and saves training data from all generated training samples. @@ -267,7 +265,7 @@ def generate_training_data( names_list = [] scores_list = [] - results = Parallel(n_jobs=num_workers, verbose=100)( + results = Parallel(n_jobs=1, verbose=100)( delayed(self._generate_training_sample)( filename.name, path_uncompiled_circuits, diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index dc2e13717..7d0b856d3 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -495,6 +495,7 @@ def get_openqasm_gates() -> list[str]: PassType.MAPPING, stochastic=True, transpile_pass=lambda device: [ + ### Requires a initial layout, but "optimize" mode overwrites it TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), EnlargeWithAncilla(), diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 14983a0a1..a3cbae20b 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -341,7 +341,6 @@ def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCirc def metric_fn(circ: QuantumCircuit) -> float: return float(circ.count_ops().get("swap", 0)) - # for stochastic actions, pass the layout/routing trials parameter max_iteration = self.max_iter if "Sabre" in action.name and "AIRouting" not in action.name: # Internal trials for Sabre @@ -359,6 +358,10 @@ def metric_fn(circ: QuantumCircuit) -> float: max_iteration=max_iteration, metric_fn=metric_fn, ) + else: + msg = f"Unknown stochastic action: {action.name}" + raise ValueError(msg) + else: if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): passes = action.transpile_pass( @@ -378,8 +381,8 @@ def metric_fn(circ: QuantumCircuit) -> float: pm = PassManager(transpile_pass) altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + if action_index in (self.actions_mapping_indices + self.actions_final_optimization_indices): - pm_property_set = dict(pm.property_set) altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) return altered_qc diff --git a/uv.lock b/uv.lock index 25bf474e6..d9e9e8d01 100644 --- a/uv.lock +++ b/uv.lock @@ -2,11 +2,9 @@ version = 1 revision = 3 requires-python = ">=3.10" resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version >= '3.13'", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", @@ -406,11 +404,9 @@ name = "contourpy" version = "1.3.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version >= '3.13'", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -495,87 +491,87 @@ wheels = [ [[package]] name = "coverage" -version = "7.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/0e/66dbd4c6a7f0758a8d18044c048779ba21fb94856e1edcf764bd5403e710/coverage-7.10.1.tar.gz", hash = "sha256:ae2b4856f29ddfe827106794f3589949a57da6f0d38ab01e24ec35107979ba57", size = 819938, upload-time = "2025-07-27T14:13:39.045Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/e7/0f4e35a15361337529df88151bddcac8e8f6d6fd01da94a4b7588901c2fe/coverage-7.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1c86eb388bbd609d15560e7cc0eb936c102b6f43f31cf3e58b4fd9afe28e1372", size = 214627, upload-time = "2025-07-27T14:11:01.211Z" }, - { url = "https://files.pythonhosted.org/packages/e0/fd/17872e762c408362072c936dbf3ca28c67c609a1f5af434b1355edcb7e12/coverage-7.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b4ba0f488c1bdb6bd9ba81da50715a372119785458831c73428a8566253b86b", size = 215015, upload-time = "2025-07-27T14:11:03.988Z" }, - { url = "https://files.pythonhosted.org/packages/54/50/c9d445ba38ee5f685f03876c0f8223469e2e46c5d3599594dca972b470c8/coverage-7.10.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083442ecf97d434f0cb3b3e3676584443182653da08b42e965326ba12d6b5f2a", size = 241995, upload-time = "2025-07-27T14:11:05.983Z" }, - { url = "https://files.pythonhosted.org/packages/cc/83/4ae6e0f60376af33de543368394d21b9ac370dc86434039062ef171eebf8/coverage-7.10.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c1a40c486041006b135759f59189385da7c66d239bad897c994e18fd1d0c128f", size = 243253, upload-time = "2025-07-27T14:11:07.424Z" }, - { url = "https://files.pythonhosted.org/packages/49/90/17a4d9ac7171be364ce8c0bb2b6da05e618ebfe1f11238ad4f26c99f5467/coverage-7.10.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3beb76e20b28046989300c4ea81bf690df84ee98ade4dc0bbbf774a28eb98440", size = 245110, upload-time = "2025-07-27T14:11:09.152Z" }, - { url = "https://files.pythonhosted.org/packages/e1/f7/edc3f485d536ed417f3af2b4969582bcb5fab456241721825fa09354161e/coverage-7.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc265a7945e8d08da28999ad02b544963f813a00f3ed0a7a0ce4165fd77629f8", size = 243056, upload-time = "2025-07-27T14:11:10.586Z" }, - { url = "https://files.pythonhosted.org/packages/58/2c/c4c316a57718556b8d0cc8304437741c31b54a62934e7c8c551a7915c2f4/coverage-7.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:47c91f32ba4ac46f1e224a7ebf3f98b4b24335bad16137737fe71a5961a0665c", size = 241731, upload-time = "2025-07-27T14:11:12.145Z" }, - { url = "https://files.pythonhosted.org/packages/f7/93/c78e144c6f086043d0d7d9237c5b880e71ac672ed2712c6f8cca5544481f/coverage-7.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1a108dd78ed185020f66f131c60078f3fae3f61646c28c8bb4edd3fa121fc7fc", size = 242023, upload-time = "2025-07-27T14:11:13.573Z" }, - { url = "https://files.pythonhosted.org/packages/8f/e1/34e8505ca81fc144a612e1cc79fadd4a78f42e96723875f4e9f1f470437e/coverage-7.10.1-cp310-cp310-win32.whl", hash = "sha256:7092cc82382e634075cc0255b0b69cb7cada7c1f249070ace6a95cb0f13548ef", size = 217130, upload-time = "2025-07-27T14:11:15.11Z" }, - { url = "https://files.pythonhosted.org/packages/75/2b/82adfce6edffc13d804aee414e64c0469044234af9296e75f6d13f92f6a2/coverage-7.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:ac0c5bba938879c2fc0bc6c1b47311b5ad1212a9dcb8b40fe2c8110239b7faed", size = 218015, upload-time = "2025-07-27T14:11:16.836Z" }, - { url = "https://files.pythonhosted.org/packages/20/8e/ef088112bd1b26e2aa931ee186992b3e42c222c64f33e381432c8ee52aae/coverage-7.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b45e2f9d5b0b5c1977cb4feb5f594be60eb121106f8900348e29331f553a726f", size = 214747, upload-time = "2025-07-27T14:11:18.217Z" }, - { url = "https://files.pythonhosted.org/packages/2d/76/a1e46f3c6e0897758eb43af88bb3c763cb005f4950769f7b553e22aa5f89/coverage-7.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a7a4d74cb0f5e3334f9aa26af7016ddb94fb4bfa11b4a573d8e98ecba8c34f1", size = 215128, upload-time = "2025-07-27T14:11:19.706Z" }, - { url = "https://files.pythonhosted.org/packages/78/4d/903bafb371a8c887826ecc30d3977b65dfad0e1e66aa61b7e173de0828b0/coverage-7.10.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d4b0aab55ad60ead26159ff12b538c85fbab731a5e3411c642b46c3525863437", size = 245140, upload-time = "2025-07-27T14:11:21.261Z" }, - { url = "https://files.pythonhosted.org/packages/55/f1/1f8f09536f38394a8698dd08a0e9608a512eacee1d3b771e2d06397f77bf/coverage-7.10.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dcc93488c9ebd229be6ee1f0d9aad90da97b33ad7e2912f5495804d78a3cd6b7", size = 246977, upload-time = "2025-07-27T14:11:23.15Z" }, - { url = "https://files.pythonhosted.org/packages/57/cc/ed6bbc5a3bdb36ae1bca900bbbfdcb23b260ef2767a7b2dab38b92f61adf/coverage-7.10.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa309df995d020f3438407081b51ff527171cca6772b33cf8f85344b8b4b8770", size = 249140, upload-time = "2025-07-27T14:11:24.743Z" }, - { url = "https://files.pythonhosted.org/packages/10/f5/e881ade2d8e291b60fa1d93d6d736107e940144d80d21a0d4999cff3642f/coverage-7.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cfb8b9d8855c8608f9747602a48ab525b1d320ecf0113994f6df23160af68262", size = 246869, upload-time = "2025-07-27T14:11:26.156Z" }, - { url = "https://files.pythonhosted.org/packages/53/b9/6a5665cb8996e3cd341d184bb11e2a8edf01d8dadcf44eb1e742186cf243/coverage-7.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:320d86da829b012982b414c7cdda65f5d358d63f764e0e4e54b33097646f39a3", size = 244899, upload-time = "2025-07-27T14:11:27.622Z" }, - { url = "https://files.pythonhosted.org/packages/27/11/24156776709c4e25bf8a33d6bb2ece9a9067186ddac19990f6560a7f8130/coverage-7.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dc60ddd483c556590da1d9482a4518292eec36dd0e1e8496966759a1f282bcd0", size = 245507, upload-time = "2025-07-27T14:11:29.544Z" }, - { url = "https://files.pythonhosted.org/packages/43/db/a6f0340b7d6802a79928659c9a32bc778ea420e87a61b568d68ac36d45a8/coverage-7.10.1-cp311-cp311-win32.whl", hash = "sha256:4fcfe294f95b44e4754da5b58be750396f2b1caca8f9a0e78588e3ef85f8b8be", size = 217167, upload-time = "2025-07-27T14:11:31.349Z" }, - { url = "https://files.pythonhosted.org/packages/f5/6f/1990eb4fd05cea4cfabdf1d587a997ac5f9a8bee883443a1d519a2a848c9/coverage-7.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:efa23166da3fe2915f8ab452dde40319ac84dc357f635737174a08dbd912980c", size = 218054, upload-time = "2025-07-27T14:11:33.202Z" }, - { url = "https://files.pythonhosted.org/packages/b4/4d/5e061d6020251b20e9b4303bb0b7900083a1a384ec4e5db326336c1c4abd/coverage-7.10.1-cp311-cp311-win_arm64.whl", hash = "sha256:d12b15a8c3759e2bb580ffa423ae54be4f184cf23beffcbd641f4fe6e1584293", size = 216483, upload-time = "2025-07-27T14:11:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/a5/3f/b051feeb292400bd22d071fdf933b3ad389a8cef5c80c7866ed0c7414b9e/coverage-7.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6b7dc7f0a75a7eaa4584e5843c873c561b12602439d2351ee28c7478186c4da4", size = 214934, upload-time = "2025-07-27T14:11:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e4/a61b27d5c4c2d185bdfb0bfe9d15ab4ac4f0073032665544507429ae60eb/coverage-7.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:607f82389f0ecafc565813aa201a5cade04f897603750028dd660fb01797265e", size = 215173, upload-time = "2025-07-27T14:11:38.005Z" }, - { url = "https://files.pythonhosted.org/packages/8a/01/40a6ee05b60d02d0bc53742ad4966e39dccd450aafb48c535a64390a3552/coverage-7.10.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f7da31a1ba31f1c1d4d5044b7c5813878adae1f3af8f4052d679cc493c7328f4", size = 246190, upload-time = "2025-07-27T14:11:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/11/ef/a28d64d702eb583c377255047281305dc5a5cfbfb0ee36e721f78255adb6/coverage-7.10.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51fe93f3fe4f5d8483d51072fddc65e717a175490804e1942c975a68e04bf97a", size = 248618, upload-time = "2025-07-27T14:11:41.841Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ad/73d018bb0c8317725370c79d69b5c6e0257df84a3b9b781bda27a438a3be/coverage-7.10.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e59d00830da411a1feef6ac828b90bbf74c9b6a8e87b8ca37964925bba76dbe", size = 250081, upload-time = "2025-07-27T14:11:43.705Z" }, - { url = "https://files.pythonhosted.org/packages/2d/dd/496adfbbb4503ebca5d5b2de8bed5ec00c0a76558ffc5b834fd404166bc9/coverage-7.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:924563481c27941229cb4e16eefacc35da28563e80791b3ddc5597b062a5c386", size = 247990, upload-time = "2025-07-27T14:11:45.244Z" }, - { url = "https://files.pythonhosted.org/packages/18/3c/a9331a7982facfac0d98a4a87b36ae666fe4257d0f00961a3a9ef73e015d/coverage-7.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ca79146ee421b259f8131f153102220b84d1a5e6fb9c8aed13b3badfd1796de6", size = 246191, upload-time = "2025-07-27T14:11:47.093Z" }, - { url = "https://files.pythonhosted.org/packages/62/0c/75345895013b83f7afe92ec595e15a9a525ede17491677ceebb2ba5c3d85/coverage-7.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b225a06d227f23f386fdc0eab471506d9e644be699424814acc7d114595495f", size = 247400, upload-time = "2025-07-27T14:11:48.643Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a9/98b268cfc5619ef9df1d5d34fee408ecb1542d9fd43d467e5c2f28668cd4/coverage-7.10.1-cp312-cp312-win32.whl", hash = "sha256:5ba9a8770effec5baaaab1567be916c87d8eea0c9ad11253722d86874d885eca", size = 217338, upload-time = "2025-07-27T14:11:50.258Z" }, - { url = "https://files.pythonhosted.org/packages/fe/31/22a5440e4d1451f253c5cd69fdcead65e92ef08cd4ec237b8756dc0b20a7/coverage-7.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:9eb245a8d8dd0ad73b4062135a251ec55086fbc2c42e0eb9725a9b553fba18a3", size = 218125, upload-time = "2025-07-27T14:11:52.034Z" }, - { url = "https://files.pythonhosted.org/packages/d6/2b/40d9f0ce7ee839f08a43c5bfc9d05cec28aaa7c9785837247f96cbe490b9/coverage-7.10.1-cp312-cp312-win_arm64.whl", hash = "sha256:7718060dd4434cc719803a5e526838a5d66e4efa5dc46d2b25c21965a9c6fcc4", size = 216523, upload-time = "2025-07-27T14:11:53.965Z" }, - { url = "https://files.pythonhosted.org/packages/ef/72/135ff5fef09b1ffe78dbe6fcf1e16b2e564cd35faeacf3d63d60d887f12d/coverage-7.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebb08d0867c5a25dffa4823377292a0ffd7aaafb218b5d4e2e106378b1061e39", size = 214960, upload-time = "2025-07-27T14:11:55.959Z" }, - { url = "https://files.pythonhosted.org/packages/b1/aa/73a5d1a6fc08ca709a8177825616aa95ee6bf34d522517c2595484a3e6c9/coverage-7.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f32a95a83c2e17422f67af922a89422cd24c6fa94041f083dd0bb4f6057d0bc7", size = 215220, upload-time = "2025-07-27T14:11:57.899Z" }, - { url = "https://files.pythonhosted.org/packages/8d/40/3124fdd45ed3772a42fc73ca41c091699b38a2c3bd4f9cb564162378e8b6/coverage-7.10.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c4c746d11c8aba4b9f58ca8bfc6fbfd0da4efe7960ae5540d1a1b13655ee8892", size = 245772, upload-time = "2025-07-27T14:12:00.422Z" }, - { url = "https://files.pythonhosted.org/packages/42/62/a77b254822efa8c12ad59e8039f2bc3df56dc162ebda55e1943e35ba31a5/coverage-7.10.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7f39edd52c23e5c7ed94e0e4bf088928029edf86ef10b95413e5ea670c5e92d7", size = 248116, upload-time = "2025-07-27T14:12:03.099Z" }, - { url = "https://files.pythonhosted.org/packages/1d/01/8101f062f472a3a6205b458d18ef0444a63ae5d36a8a5ed5dd0f6167f4db/coverage-7.10.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab6e19b684981d0cd968906e293d5628e89faacb27977c92f3600b201926b994", size = 249554, upload-time = "2025-07-27T14:12:04.668Z" }, - { url = "https://files.pythonhosted.org/packages/8f/7b/e51bc61573e71ff7275a4f167aecbd16cb010aefdf54bcd8b0a133391263/coverage-7.10.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5121d8cf0eacb16133501455d216bb5f99899ae2f52d394fe45d59229e6611d0", size = 247766, upload-time = "2025-07-27T14:12:06.234Z" }, - { url = "https://files.pythonhosted.org/packages/4b/71/1c96d66a51d4204a9d6d12df53c4071d87e110941a2a1fe94693192262f5/coverage-7.10.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:df1c742ca6f46a6f6cbcaef9ac694dc2cb1260d30a6a2f5c68c5f5bcfee1cfd7", size = 245735, upload-time = "2025-07-27T14:12:08.305Z" }, - { url = "https://files.pythonhosted.org/packages/13/d5/efbc2ac4d35ae2f22ef6df2ca084c60e13bd9378be68655e3268c80349ab/coverage-7.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:40f9a38676f9c073bf4b9194707aa1eb97dca0e22cc3766d83879d72500132c7", size = 247118, upload-time = "2025-07-27T14:12:09.903Z" }, - { url = "https://files.pythonhosted.org/packages/d1/22/073848352bec28ca65f2b6816b892fcf9a31abbef07b868487ad15dd55f1/coverage-7.10.1-cp313-cp313-win32.whl", hash = "sha256:2348631f049e884839553b9974f0821d39241c6ffb01a418efce434f7eba0fe7", size = 217381, upload-time = "2025-07-27T14:12:11.535Z" }, - { url = "https://files.pythonhosted.org/packages/b7/df/df6a0ff33b042f000089bd11b6bb034bab073e2ab64a56e78ed882cba55d/coverage-7.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:4072b31361b0d6d23f750c524f694e1a417c1220a30d3ef02741eed28520c48e", size = 218152, upload-time = "2025-07-27T14:12:13.182Z" }, - { url = "https://files.pythonhosted.org/packages/30/e3/5085ca849a40ed6b47cdb8f65471c2f754e19390b5a12fa8abd25cbfaa8f/coverage-7.10.1-cp313-cp313-win_arm64.whl", hash = "sha256:3e31dfb8271937cab9425f19259b1b1d1f556790e98eb266009e7a61d337b6d4", size = 216559, upload-time = "2025-07-27T14:12:14.807Z" }, - { url = "https://files.pythonhosted.org/packages/cc/93/58714efbfdeb547909feaabe1d67b2bdd59f0597060271b9c548d5efb529/coverage-7.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1c4f679c6b573a5257af6012f167a45be4c749c9925fd44d5178fd641ad8bf72", size = 215677, upload-time = "2025-07-27T14:12:16.68Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0c/18eaa5897e7e8cb3f8c45e563e23e8a85686b4585e29d53cacb6bc9cb340/coverage-7.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:871ebe8143da284bd77b84a9136200bd638be253618765d21a1fce71006d94af", size = 215899, upload-time = "2025-07-27T14:12:18.758Z" }, - { url = "https://files.pythonhosted.org/packages/84/c1/9d1affacc3c75b5a184c140377701bbf14fc94619367f07a269cd9e4fed6/coverage-7.10.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:998c4751dabf7d29b30594af416e4bf5091f11f92a8d88eb1512c7ba136d1ed7", size = 257140, upload-time = "2025-07-27T14:12:20.357Z" }, - { url = "https://files.pythonhosted.org/packages/3d/0f/339bc6b8fa968c346df346068cca1f24bdea2ddfa93bb3dc2e7749730962/coverage-7.10.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:780f750a25e7749d0af6b3631759c2c14f45de209f3faaa2398312d1c7a22759", size = 259005, upload-time = "2025-07-27T14:12:22.007Z" }, - { url = "https://files.pythonhosted.org/packages/c8/22/89390864b92ea7c909079939b71baba7e5b42a76bf327c1d615bd829ba57/coverage-7.10.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:590bdba9445df4763bdbebc928d8182f094c1f3947a8dc0fc82ef014dbdd8324", size = 261143, upload-time = "2025-07-27T14:12:23.746Z" }, - { url = "https://files.pythonhosted.org/packages/2c/56/3d04d89017c0c41c7a71bd69b29699d919b6bbf2649b8b2091240b97dd6a/coverage-7.10.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b2df80cb6a2af86d300e70acb82e9b79dab2c1e6971e44b78dbfc1a1e736b53", size = 258735, upload-time = "2025-07-27T14:12:25.73Z" }, - { url = "https://files.pythonhosted.org/packages/cb/40/312252c8afa5ca781063a09d931f4b9409dc91526cd0b5a2b84143ffafa2/coverage-7.10.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d6a558c2725bfb6337bf57c1cd366c13798bfd3bfc9e3dd1f4a6f6fc95a4605f", size = 256871, upload-time = "2025-07-27T14:12:27.767Z" }, - { url = "https://files.pythonhosted.org/packages/1f/2b/564947d5dede068215aaddb9e05638aeac079685101462218229ddea9113/coverage-7.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e6150d167f32f2a54690e572e0a4c90296fb000a18e9b26ab81a6489e24e78dd", size = 257692, upload-time = "2025-07-27T14:12:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/93/1b/c8a867ade85cb26d802aea2209b9c2c80613b9c122baa8c8ecea6799648f/coverage-7.10.1-cp313-cp313t-win32.whl", hash = "sha256:d946a0c067aa88be4a593aad1236493313bafaa27e2a2080bfe88db827972f3c", size = 218059, upload-time = "2025-07-27T14:12:31.076Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fe/cd4ab40570ae83a516bf5e754ea4388aeedd48e660e40c50b7713ed4f930/coverage-7.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e37c72eaccdd5ed1130c67a92ad38f5b2af66eeff7b0abe29534225db2ef7b18", size = 219150, upload-time = "2025-07-27T14:12:32.746Z" }, - { url = "https://files.pythonhosted.org/packages/8d/16/6e5ed5854be6d70d0c39e9cb9dd2449f2c8c34455534c32c1a508c7dbdb5/coverage-7.10.1-cp313-cp313t-win_arm64.whl", hash = "sha256:89ec0ffc215c590c732918c95cd02b55c7d0f569d76b90bb1a5e78aa340618e4", size = 217014, upload-time = "2025-07-27T14:12:34.406Z" }, - { url = "https://files.pythonhosted.org/packages/54/8e/6d0bfe9c3d7121cf936c5f8b03e8c3da1484fb801703127dba20fb8bd3c7/coverage-7.10.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:166d89c57e877e93d8827dac32cedae6b0277ca684c6511497311249f35a280c", size = 214951, upload-time = "2025-07-27T14:12:36.069Z" }, - { url = "https://files.pythonhosted.org/packages/f2/29/e3e51a8c653cf2174c60532aafeb5065cea0911403fa144c9abe39790308/coverage-7.10.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bed4a2341b33cd1a7d9ffc47df4a78ee61d3416d43b4adc9e18b7d266650b83e", size = 215229, upload-time = "2025-07-27T14:12:37.759Z" }, - { url = "https://files.pythonhosted.org/packages/e0/59/3c972080b2fa18b6c4510201f6d4dc87159d450627d062cd9ad051134062/coverage-7.10.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ddca1e4f5f4c67980533df01430184c19b5359900e080248bbf4ed6789584d8b", size = 245738, upload-time = "2025-07-27T14:12:39.453Z" }, - { url = "https://files.pythonhosted.org/packages/2e/04/fc0d99d3f809452654e958e1788454f6e27b34e43f8f8598191c8ad13537/coverage-7.10.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:37b69226001d8b7de7126cad7366b0778d36777e4d788c66991455ba817c5b41", size = 248045, upload-time = "2025-07-27T14:12:41.387Z" }, - { url = "https://files.pythonhosted.org/packages/5e/2e/afcbf599e77e0dfbf4c97197747250d13d397d27e185b93987d9eaac053d/coverage-7.10.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2f22102197bcb1722691296f9e589f02b616f874e54a209284dd7b9294b0b7f", size = 249666, upload-time = "2025-07-27T14:12:43.056Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ae/bc47f7f8ecb7a06cbae2bf86a6fa20f479dd902bc80f57cff7730438059d/coverage-7.10.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1e0c768b0f9ac5839dac5cf88992a4bb459e488ee8a1f8489af4cb33b1af00f1", size = 247692, upload-time = "2025-07-27T14:12:44.83Z" }, - { url = "https://files.pythonhosted.org/packages/b6/26/cbfa3092d31ccba8ba7647e4d25753263e818b4547eba446b113d7d1efdf/coverage-7.10.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:991196702d5e0b120a8fef2664e1b9c333a81d36d5f6bcf6b225c0cf8b0451a2", size = 245536, upload-time = "2025-07-27T14:12:46.527Z" }, - { url = "https://files.pythonhosted.org/packages/56/77/9c68e92500e6a1c83d024a70eadcc9a173f21aadd73c4675fe64c9c43fdf/coverage-7.10.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae8e59e5f4fd85d6ad34c2bb9d74037b5b11be072b8b7e9986beb11f957573d4", size = 246954, upload-time = "2025-07-27T14:12:49.279Z" }, - { url = "https://files.pythonhosted.org/packages/7f/a5/ba96671c5a669672aacd9877a5987c8551501b602827b4e84256da2a30a7/coverage-7.10.1-cp314-cp314-win32.whl", hash = "sha256:042125c89cf74a074984002e165d61fe0e31c7bd40ebb4bbebf07939b5924613", size = 217616, upload-time = "2025-07-27T14:12:51.214Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3c/e1e1eb95fc1585f15a410208c4795db24a948e04d9bde818fe4eb893bc85/coverage-7.10.1-cp314-cp314-win_amd64.whl", hash = "sha256:a22c3bfe09f7a530e2c94c87ff7af867259c91bef87ed2089cd69b783af7b84e", size = 218412, upload-time = "2025-07-27T14:12:53.429Z" }, - { url = "https://files.pythonhosted.org/packages/b0/85/7e1e5be2cb966cba95566ba702b13a572ca744fbb3779df9888213762d67/coverage-7.10.1-cp314-cp314-win_arm64.whl", hash = "sha256:ee6be07af68d9c4fca4027c70cea0c31a0f1bc9cb464ff3c84a1f916bf82e652", size = 216776, upload-time = "2025-07-27T14:12:55.482Z" }, - { url = "https://files.pythonhosted.org/packages/62/0f/5bb8f29923141cca8560fe2217679caf4e0db643872c1945ac7d8748c2a7/coverage-7.10.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d24fb3c0c8ff0d517c5ca5de7cf3994a4cd559cde0315201511dbfa7ab528894", size = 215698, upload-time = "2025-07-27T14:12:57.225Z" }, - { url = "https://files.pythonhosted.org/packages/80/29/547038ffa4e8e4d9e82f7dfc6d152f75fcdc0af146913f0ba03875211f03/coverage-7.10.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1217a54cfd79be20512a67ca81c7da3f2163f51bbfd188aab91054df012154f5", size = 215902, upload-time = "2025-07-27T14:12:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/e1/8a/7aaa8fbfaed900147987a424e112af2e7790e1ac9cd92601e5bd4e1ba60a/coverage-7.10.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:51f30da7a52c009667e02f125737229d7d8044ad84b79db454308033a7808ab2", size = 257230, upload-time = "2025-07-27T14:13:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/e5/1d/c252b5ffac44294e23a0d79dd5acf51749b39795ccc898faeabf7bee903f/coverage-7.10.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ed3718c757c82d920f1c94089066225ca2ad7f00bb904cb72b1c39ebdd906ccb", size = 259194, upload-time = "2025-07-27T14:13:03.247Z" }, - { url = "https://files.pythonhosted.org/packages/16/ad/6c8d9f83d08f3bac2e7507534d0c48d1a4f52c18e6f94919d364edbdfa8f/coverage-7.10.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc452481e124a819ced0c25412ea2e144269ef2f2534b862d9f6a9dae4bda17b", size = 261316, upload-time = "2025-07-27T14:13:04.957Z" }, - { url = "https://files.pythonhosted.org/packages/d6/4e/f9bbf3a36c061e2e0e0f78369c006d66416561a33d2bee63345aee8ee65e/coverage-7.10.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9d6f494c307e5cb9b1e052ec1a471060f1dea092c8116e642e7a23e79d9388ea", size = 258794, upload-time = "2025-07-27T14:13:06.715Z" }, - { url = "https://files.pythonhosted.org/packages/87/82/e600bbe78eb2cb0541751d03cef9314bcd0897e8eea156219c39b685f869/coverage-7.10.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fc0e46d86905ddd16b85991f1f4919028092b4e511689bbdaff0876bd8aab3dd", size = 256869, upload-time = "2025-07-27T14:13:08.933Z" }, - { url = "https://files.pythonhosted.org/packages/ce/5d/2fc9a9236c5268f68ac011d97cd3a5ad16cc420535369bedbda659fdd9b7/coverage-7.10.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80b9ccd82e30038b61fc9a692a8dc4801504689651b281ed9109f10cc9fe8b4d", size = 257765, upload-time = "2025-07-27T14:13:10.778Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/b4e00b2bd48a2dc8e1c7d2aea7455f40af2e36484ab2ef06deb85883e9fe/coverage-7.10.1-cp314-cp314t-win32.whl", hash = "sha256:e58991a2b213417285ec866d3cd32db17a6a88061a985dbb7e8e8f13af429c47", size = 218420, upload-time = "2025-07-27T14:13:12.882Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/d21d05f33ea27ece327422240e69654b5932b0b29e7fbc40fbab3cf199bf/coverage-7.10.1-cp314-cp314t-win_amd64.whl", hash = "sha256:e88dd71e4ecbc49d9d57d064117462c43f40a21a1383507811cf834a4a620651", size = 219536, upload-time = "2025-07-27T14:13:14.718Z" }, - { url = "https://files.pythonhosted.org/packages/a6/68/7fea94b141281ed8be3d1d5c4319a97f2befc3e487ce33657fc64db2c45e/coverage-7.10.1-cp314-cp314t-win_arm64.whl", hash = "sha256:1aadfb06a30c62c2eb82322171fe1f7c288c80ca4156d46af0ca039052814bab", size = 217190, upload-time = "2025-07-27T14:13:16.85Z" }, - { url = "https://files.pythonhosted.org/packages/0f/64/922899cff2c0fd3496be83fa8b81230f5a8d82a2ad30f98370b133c2c83b/coverage-7.10.1-py3-none-any.whl", hash = "sha256:fa2a258aa6bf188eb9a8948f7102a83da7c430a0dce918dbd8b60ef8fcb772d7", size = 206597, upload-time = "2025-07-27T14:13:37.221Z" }, +version = "7.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/76/17780846fc7aade1e66712e1e27dd28faa0a5d987a1f433610974959eaa8/coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055", size = 820754, upload-time = "2025-08-04T00:35:17.511Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/5f/5ce748ab3f142593698aff5f8a0cf020775aa4e24b9d8748b5a56b64d3f8/coverage-7.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:79f0283ab5e6499fd5fe382ca3d62afa40fb50ff227676a3125d18af70eabf65", size = 215003, upload-time = "2025-08-04T00:33:02.977Z" }, + { url = "https://files.pythonhosted.org/packages/f4/ed/507088561217b000109552139802fa99c33c16ad19999c687b601b3790d0/coverage-7.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4545e906f595ee8ab8e03e21be20d899bfc06647925bc5b224ad7e8c40e08b8", size = 215391, upload-time = "2025-08-04T00:33:05.645Z" }, + { url = "https://files.pythonhosted.org/packages/79/1b/0f496259fe137c4c5e1e8eaff496fb95af88b71700f5e57725a4ddbe742b/coverage-7.10.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ae385e1d58fbc6a9b1c315e5510ac52281e271478b45f92ca9b5ad42cf39643f", size = 242367, upload-time = "2025-08-04T00:33:07.189Z" }, + { url = "https://files.pythonhosted.org/packages/b9/8e/5a8835fb0122a2e2a108bf3527931693c4625fdc4d953950a480b9625852/coverage-7.10.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f0cbe5f7dd19f3a32bac2251b95d51c3b89621ac88a2648096ce40f9a5aa1e7", size = 243627, upload-time = "2025-08-04T00:33:08.809Z" }, + { url = "https://files.pythonhosted.org/packages/c3/96/6a528429c2e0e8d85261764d0cd42e51a429510509bcc14676ee5d1bb212/coverage-7.10.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd17f427f041f6b116dc90b4049c6f3e1230524407d00daa2d8c7915037b5947", size = 245485, upload-time = "2025-08-04T00:33:10.29Z" }, + { url = "https://files.pythonhosted.org/packages/bf/82/1fba935c4d02c33275aca319deabf1f22c0f95f2c0000bf7c5f276d6f7b4/coverage-7.10.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7f10ca4cde7b466405cce0a0e9971a13eb22e57a5ecc8b5f93a81090cc9c7eb9", size = 243429, upload-time = "2025-08-04T00:33:11.909Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a8/c8dc0a57a729fc93be33ab78f187a8f52d455fa8f79bfb379fe23b45868d/coverage-7.10.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b990df23dd51dccce26d18fb09fd85a77ebe46368f387b0ffba7a74e470b31b", size = 242104, upload-time = "2025-08-04T00:33:13.467Z" }, + { url = "https://files.pythonhosted.org/packages/b9/6f/0b7da1682e2557caeed299a00897b42afde99a241a01eba0197eb982b90f/coverage-7.10.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc3902584d25c7eef57fb38f440aa849a26a3a9f761a029a72b69acfca4e31f8", size = 242397, upload-time = "2025-08-04T00:33:14.682Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e4/54dc833dadccd519c04a28852f39a37e522bad35d70cfe038817cdb8f168/coverage-7.10.2-cp310-cp310-win32.whl", hash = "sha256:9dd37e9ac00d5eb72f38ed93e3cdf2280b1dbda3bb9b48c6941805f265ad8d87", size = 217502, upload-time = "2025-08-04T00:33:16.254Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e7/2f78159c4c127549172f427dff15b02176329327bf6a6a1fcf1f603b5456/coverage-7.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:99d16f15cb5baf0729354c5bd3080ae53847a4072b9ba1e10957522fb290417f", size = 218388, upload-time = "2025-08-04T00:33:17.4Z" }, + { url = "https://files.pythonhosted.org/packages/6e/53/0125a6fc0af4f2687b4e08b0fb332cd0d5e60f3ca849e7456f995d022656/coverage-7.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c3b210d79925a476dfc8d74c7d53224888421edebf3a611f3adae923e212b27", size = 215119, upload-time = "2025-08-04T00:33:19.101Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2e/960d9871de9152dbc9ff950913c6a6e9cf2eb4cc80d5bc8f93029f9f2f9f/coverage-7.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf67d1787cd317c3f8b2e4c6ed1ae93497be7e30605a0d32237ac37a37a8a322", size = 215511, upload-time = "2025-08-04T00:33:20.32Z" }, + { url = "https://files.pythonhosted.org/packages/3f/34/68509e44995b9cad806d81b76c22bc5181f3535bca7cd9c15791bfd8951e/coverage-7.10.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:069b779d03d458602bc0e27189876e7d8bdf6b24ac0f12900de22dd2154e6ad7", size = 245513, upload-time = "2025-08-04T00:33:21.896Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d4/9b12f357413248ce40804b0f58030b55a25b28a5c02db95fb0aa50c5d62c/coverage-7.10.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c2de4cb80b9990e71c62c2d3e9f3ec71b804b1f9ca4784ec7e74127e0f42468", size = 247350, upload-time = "2025-08-04T00:33:23.917Z" }, + { url = "https://files.pythonhosted.org/packages/b6/40/257945eda1f72098e4a3c350b1d68fdc5d7d032684a0aeb6c2391153ecf4/coverage-7.10.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75bf7ab2374a7eb107602f1e07310cda164016cd60968abf817b7a0b5703e288", size = 249516, upload-time = "2025-08-04T00:33:25.5Z" }, + { url = "https://files.pythonhosted.org/packages/ff/55/8987f852ece378cecbf39a367f3f7ec53351e39a9151b130af3a3045b83f/coverage-7.10.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3f37516458ec1550815134937f73d6d15b434059cd10f64678a2068f65c62406", size = 247241, upload-time = "2025-08-04T00:33:26.767Z" }, + { url = "https://files.pythonhosted.org/packages/df/ae/da397de7a42a18cea6062ed9c3b72c50b39e0b9e7b2893d7172d3333a9a1/coverage-7.10.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:de3c6271c482c250d3303fb5c6bdb8ca025fff20a67245e1425df04dc990ece9", size = 245274, upload-time = "2025-08-04T00:33:28.494Z" }, + { url = "https://files.pythonhosted.org/packages/4e/64/7baa895eb55ec0e1ec35b988687ecd5d4475ababb0d7ae5ca3874dd90ee7/coverage-7.10.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:98a838101321ac3089c9bb1d4bfa967e8afed58021fda72d7880dc1997f20ae1", size = 245882, upload-time = "2025-08-04T00:33:30.048Z" }, + { url = "https://files.pythonhosted.org/packages/24/6c/1fd76a0bd09ae75220ae9775a8290416d726f0e5ba26ea72346747161240/coverage-7.10.2-cp311-cp311-win32.whl", hash = "sha256:f2a79145a531a0e42df32d37be5af069b4a914845b6f686590739b786f2f7bce", size = 217541, upload-time = "2025-08-04T00:33:31.376Z" }, + { url = "https://files.pythonhosted.org/packages/5f/2d/8c18fb7a6e74c79fd4661e82535bc8c68aee12f46c204eabf910b097ccc9/coverage-7.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:e4f5f1320f8ee0d7cfa421ceb257bef9d39fd614dd3ddcfcacd284d4824ed2c2", size = 218426, upload-time = "2025-08-04T00:33:32.976Z" }, + { url = "https://files.pythonhosted.org/packages/da/40/425bb35e4ff7c7af177edf5dffd4154bc2a677b27696afe6526d75c77fec/coverage-7.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:d8f2d83118f25328552c728b8e91babf93217db259ca5c2cd4dd4220b8926293", size = 217116, upload-time = "2025-08-04T00:33:34.302Z" }, + { url = "https://files.pythonhosted.org/packages/4e/1e/2c752bdbbf6f1199c59b1a10557fbb6fb3dc96b3c0077b30bd41a5922c1f/coverage-7.10.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:890ad3a26da9ec7bf69255b9371800e2a8da9bc223ae5d86daeb940b42247c83", size = 215311, upload-time = "2025-08-04T00:33:35.524Z" }, + { url = "https://files.pythonhosted.org/packages/68/6a/84277d73a2cafb96e24be81b7169372ba7ff28768ebbf98e55c85a491b0f/coverage-7.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38fd1ccfca7838c031d7a7874d4353e2f1b98eb5d2a80a2fe5732d542ae25e9c", size = 215550, upload-time = "2025-08-04T00:33:37.109Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e7/5358b73b46ac76f56cc2de921eeabd44fabd0b7ff82ea4f6b8c159c4d5dc/coverage-7.10.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76c1ffaaf4f6f0f6e8e9ca06f24bb6454a7a5d4ced97a1bc466f0d6baf4bd518", size = 246564, upload-time = "2025-08-04T00:33:38.33Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0e/b0c901dd411cb7fc0cfcb28ef0dc6f3049030f616bfe9fc4143aecd95901/coverage-7.10.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86da8a3a84b79ead5c7d0e960c34f580bc3b231bb546627773a3f53c532c2f21", size = 248993, upload-time = "2025-08-04T00:33:39.555Z" }, + { url = "https://files.pythonhosted.org/packages/0e/4e/a876db272072a9e0df93f311e187ccdd5f39a190c6d1c1f0b6e255a0d08e/coverage-7.10.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cef9731c8a39801830a604cc53c93c9e57ea8b44953d26589499eded9576e0", size = 250454, upload-time = "2025-08-04T00:33:41.023Z" }, + { url = "https://files.pythonhosted.org/packages/64/d6/1222dc69f8dd1be208d55708a9f4a450ad582bf4fa05320617fea1eaa6d8/coverage-7.10.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea58b112f2966a8b91eb13f5d3b1f8bb43c180d624cd3283fb33b1cedcc2dd75", size = 248365, upload-time = "2025-08-04T00:33:42.376Z" }, + { url = "https://files.pythonhosted.org/packages/62/e3/40fd71151064fc315c922dd9a35e15b30616f00146db1d6a0b590553a75a/coverage-7.10.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:20f405188d28da9522b7232e51154e1b884fc18d0b3a10f382d54784715bbe01", size = 246562, upload-time = "2025-08-04T00:33:43.663Z" }, + { url = "https://files.pythonhosted.org/packages/fc/14/8aa93ddcd6623ddaef5d8966268ac9545b145bce4fe7b1738fd1c3f0d957/coverage-7.10.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:64586ce42bbe0da4d9f76f97235c545d1abb9b25985a8791857690f96e23dc3b", size = 247772, upload-time = "2025-08-04T00:33:45.068Z" }, + { url = "https://files.pythonhosted.org/packages/07/4e/dcb1c01490623c61e2f2ea85cb185fa6a524265bb70eeb897d3c193efeb9/coverage-7.10.2-cp312-cp312-win32.whl", hash = "sha256:bc2e69b795d97ee6d126e7e22e78a509438b46be6ff44f4dccbb5230f550d340", size = 217710, upload-time = "2025-08-04T00:33:46.378Z" }, + { url = "https://files.pythonhosted.org/packages/79/16/e8aab4162b5f80ad2e5e1f54b1826e2053aa2f4db508b864af647f00c239/coverage-7.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:adda2268b8cf0d11f160fad3743b4dfe9813cd6ecf02c1d6397eceaa5b45b388", size = 218499, upload-time = "2025-08-04T00:33:48.048Z" }, + { url = "https://files.pythonhosted.org/packages/06/7f/c112ec766e8f1131ce8ce26254be028772757b2d1e63e4f6a4b0ad9a526c/coverage-7.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:164429decd0d6b39a0582eaa30c67bf482612c0330572343042d0ed9e7f15c20", size = 217154, upload-time = "2025-08-04T00:33:49.299Z" }, + { url = "https://files.pythonhosted.org/packages/8d/04/9b7a741557f93c0ed791b854d27aa8d9fe0b0ce7bb7c52ca1b0f2619cb74/coverage-7.10.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aca7b5645afa688de6d4f8e89d30c577f62956fefb1bad021490d63173874186", size = 215337, upload-time = "2025-08-04T00:33:50.61Z" }, + { url = "https://files.pythonhosted.org/packages/02/a4/8d1088cd644750c94bc305d3cf56082b4cdf7fb854a25abb23359e74892f/coverage-7.10.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96e5921342574a14303dfdb73de0019e1ac041c863743c8fe1aa6c2b4a257226", size = 215596, upload-time = "2025-08-04T00:33:52.33Z" }, + { url = "https://files.pythonhosted.org/packages/01/2f/643a8d73343f70e162d8177a3972b76e306b96239026bc0c12cfde4f7c7a/coverage-7.10.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11333094c1bff621aa811b67ed794865cbcaa99984dedea4bd9cf780ad64ecba", size = 246145, upload-time = "2025-08-04T00:33:53.641Z" }, + { url = "https://files.pythonhosted.org/packages/1f/4a/722098d1848db4072cda71b69ede1e55730d9063bf868375264d0d302bc9/coverage-7.10.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6eb586fa7d2aee8d65d5ae1dd71414020b2f447435c57ee8de8abea0a77d5074", size = 248492, upload-time = "2025-08-04T00:33:55.366Z" }, + { url = "https://files.pythonhosted.org/packages/3f/b0/8a6d7f326f6e3e6ed398cde27f9055e860a1e858317001835c521673fb60/coverage-7.10.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d358f259d8019d4ef25d8c5b78aca4c7af25e28bd4231312911c22a0e824a57", size = 249927, upload-time = "2025-08-04T00:33:57.042Z" }, + { url = "https://files.pythonhosted.org/packages/bb/21/1aaadd3197b54d1e61794475379ecd0f68d8fc5c2ebd352964dc6f698a3d/coverage-7.10.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5250bda76e30382e0a2dcd68d961afcab92c3a7613606e6269855c6979a1b0bb", size = 248138, upload-time = "2025-08-04T00:33:58.329Z" }, + { url = "https://files.pythonhosted.org/packages/48/65/be75bafb2bdd22fd8bf9bf63cd5873b91bb26ec0d68f02d4b8b09c02decb/coverage-7.10.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a91e027d66eff214d88d9afbe528e21c9ef1ecdf4956c46e366c50f3094696d0", size = 246111, upload-time = "2025-08-04T00:33:59.899Z" }, + { url = "https://files.pythonhosted.org/packages/5e/30/a4f0c5e249c3cc60e6c6f30d8368e372f2d380eda40e0434c192ac27ccf5/coverage-7.10.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:228946da741558904e2c03ce870ba5efd9cd6e48cbc004d9a27abee08100a15a", size = 247493, upload-time = "2025-08-04T00:34:01.619Z" }, + { url = "https://files.pythonhosted.org/packages/85/99/f09b9493e44a75cf99ca834394c12f8cb70da6c1711ee296534f97b52729/coverage-7.10.2-cp313-cp313-win32.whl", hash = "sha256:95e23987b52d02e7c413bf2d6dc6288bd5721beb518052109a13bfdc62c8033b", size = 217756, upload-time = "2025-08-04T00:34:03.277Z" }, + { url = "https://files.pythonhosted.org/packages/2d/bb/cbcb09103be330c7d26ff0ab05c4a8861dd2e254656fdbd3eb7600af4336/coverage-7.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:f35481d42c6d146d48ec92d4e239c23f97b53a3f1fbd2302e7c64336f28641fe", size = 218526, upload-time = "2025-08-04T00:34:04.635Z" }, + { url = "https://files.pythonhosted.org/packages/37/8f/8bfb4e0bca52c00ab680767c0dd8cfd928a2a72d69897d9b2d5d8b5f63f5/coverage-7.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:65b451949cb789c346f9f9002441fc934d8ccedcc9ec09daabc2139ad13853f7", size = 217176, upload-time = "2025-08-04T00:34:05.973Z" }, + { url = "https://files.pythonhosted.org/packages/1e/25/d458ba0bf16a8204a88d74dbb7ec5520f29937ffcbbc12371f931c11efd2/coverage-7.10.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8415918856a3e7d57a4e0ad94651b761317de459eb74d34cc1bb51aad80f07e", size = 216058, upload-time = "2025-08-04T00:34:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1c/af4dfd2d7244dc7610fed6d59d57a23ea165681cd764445dc58d71ed01a6/coverage-7.10.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f287a25a8ca53901c613498e4a40885b19361a2fe8fbfdbb7f8ef2cad2a23f03", size = 216273, upload-time = "2025-08-04T00:34:09.073Z" }, + { url = "https://files.pythonhosted.org/packages/8e/67/ec5095d4035c6e16368226fa9cb15f77f891194c7e3725aeefd08e7a3e5a/coverage-7.10.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:75cc1a3f8c88c69bf16a871dab1fe5a7303fdb1e9f285f204b60f1ee539b8fc0", size = 257513, upload-time = "2025-08-04T00:34:10.403Z" }, + { url = "https://files.pythonhosted.org/packages/1c/47/be5550b57a3a8ba797de4236b0fd31031f88397b2afc84ab3c2d4cf265f6/coverage-7.10.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca07fa78cc9d26bc8c4740de1abd3489cf9c47cc06d9a8ab3d552ff5101af4c0", size = 259377, upload-time = "2025-08-04T00:34:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/37/50/b12a4da1382e672305c2d17cd3029dc16b8a0470de2191dbf26b91431378/coverage-7.10.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2e117e64c26300032755d4520cd769f2623cde1a1d1c3515b05a3b8add0ade1", size = 261516, upload-time = "2025-08-04T00:34:13.608Z" }, + { url = "https://files.pythonhosted.org/packages/db/41/4d3296dbd33dd8da178171540ca3391af7c0184c0870fd4d4574ac290290/coverage-7.10.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:daaf98009977f577b71f8800208f4d40d4dcf5c2db53d4d822787cdc198d76e1", size = 259110, upload-time = "2025-08-04T00:34:15.089Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f1/b409959ecbc0cec0e61e65683b22bacaa4a3b11512f834e16dd8ffbc37db/coverage-7.10.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ea8d8fe546c528535c761ba424410bbeb36ba8a0f24be653e94b70c93fd8a8ca", size = 257248, upload-time = "2025-08-04T00:34:16.501Z" }, + { url = "https://files.pythonhosted.org/packages/48/ab/7076dc1c240412e9267d36ec93e9e299d7659f6a5c1e958f87e998b0fb6d/coverage-7.10.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fe024d40ac31eb8d5aae70215b41dafa264676caa4404ae155f77d2fa95c37bb", size = 258063, upload-time = "2025-08-04T00:34:18.338Z" }, + { url = "https://files.pythonhosted.org/packages/1e/77/f6b51a0288f8f5f7dcc7c89abdd22cf514f3bc5151284f5cd628917f8e10/coverage-7.10.2-cp313-cp313t-win32.whl", hash = "sha256:8f34b09f68bdadec122ffad312154eda965ade433559cc1eadd96cca3de5c824", size = 218433, upload-time = "2025-08-04T00:34:19.71Z" }, + { url = "https://files.pythonhosted.org/packages/7b/6d/547a86493e25270ce8481543e77f3a0aa3aa872c1374246b7b76273d66eb/coverage-7.10.2-cp313-cp313t-win_amd64.whl", hash = "sha256:71d40b3ac0f26fa9ffa6ee16219a714fed5c6ec197cdcd2018904ab5e75bcfa3", size = 219523, upload-time = "2025-08-04T00:34:21.171Z" }, + { url = "https://files.pythonhosted.org/packages/ff/d5/3c711e38eaf9ab587edc9bed232c0298aed84e751a9f54aaa556ceaf7da6/coverage-7.10.2-cp313-cp313t-win_arm64.whl", hash = "sha256:abb57fdd38bf6f7dcc66b38dafb7af7c5fdc31ac6029ce373a6f7f5331d6f60f", size = 217739, upload-time = "2025-08-04T00:34:22.514Z" }, + { url = "https://files.pythonhosted.org/packages/71/53/83bafa669bb9d06d4c8c6a055d8d05677216f9480c4698fb183ba7ec5e47/coverage-7.10.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a3e853cc04987c85ec410905667eed4bf08b1d84d80dfab2684bb250ac8da4f6", size = 215328, upload-time = "2025-08-04T00:34:23.991Z" }, + { url = "https://files.pythonhosted.org/packages/1d/6c/30827a9c5a48a813e865fbaf91e2db25cce990bd223a022650ef2293fe11/coverage-7.10.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0100b19f230df72c90fdb36db59d3f39232391e8d89616a7de30f677da4f532b", size = 215608, upload-time = "2025-08-04T00:34:25.437Z" }, + { url = "https://files.pythonhosted.org/packages/bb/a0/c92d85948056ddc397b72a3d79d36d9579c53cb25393ed3c40db7d33b193/coverage-7.10.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9c1cd71483ea78331bdfadb8dcec4f4edfb73c7002c1206d8e0af6797853f5be", size = 246111, upload-time = "2025-08-04T00:34:26.857Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/d695cf86b2559aadd072c91720a7844be4fb82cb4a3b642a2c6ce075692d/coverage-7.10.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f75dbf4899e29a37d74f48342f29279391668ef625fdac6d2f67363518056a1", size = 248419, upload-time = "2025-08-04T00:34:28.726Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0a/03206aec4a05986e039418c038470d874045f6e00426b0c3879adc1f9251/coverage-7.10.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7df481e7508de1c38b9b8043da48d94931aefa3e32b47dd20277e4978ed5b95", size = 250038, upload-time = "2025-08-04T00:34:30.061Z" }, + { url = "https://files.pythonhosted.org/packages/ab/9b/b3bd6bd52118c12bc4cf319f5baba65009c9beea84e665b6b9f03fa3f180/coverage-7.10.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:835f39e618099325e7612b3406f57af30ab0a0af350490eff6421e2e5f608e46", size = 248066, upload-time = "2025-08-04T00:34:31.53Z" }, + { url = "https://files.pythonhosted.org/packages/80/cc/bfa92e261d3e055c851a073e87ba6a3bff12a1f7134233e48a8f7d855875/coverage-7.10.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:12e52b5aa00aa720097d6947d2eb9e404e7c1101ad775f9661ba165ed0a28303", size = 245909, upload-time = "2025-08-04T00:34:32.943Z" }, + { url = "https://files.pythonhosted.org/packages/12/80/c8df15db4847710c72084164f615ae900af1ec380dce7f74a5678ccdf5e1/coverage-7.10.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:718044729bf1fe3e9eb9f31b52e44ddae07e434ec050c8c628bf5adc56fe4bdd", size = 247329, upload-time = "2025-08-04T00:34:34.388Z" }, + { url = "https://files.pythonhosted.org/packages/04/6f/cb66e1f7124d5dd9ced69f889f02931419cb448125e44a89a13f4e036124/coverage-7.10.2-cp314-cp314-win32.whl", hash = "sha256:f256173b48cc68486299d510a3e729a96e62c889703807482dbf56946befb5c8", size = 218007, upload-time = "2025-08-04T00:34:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e1/3d4be307278ce32c1b9d95cc02ee60d54ddab784036101d053ec9e4fe7f5/coverage-7.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:2e980e4179f33d9b65ac4acb86c9c0dde904098853f27f289766657ed16e07b3", size = 218802, upload-time = "2025-08-04T00:34:37.35Z" }, + { url = "https://files.pythonhosted.org/packages/ec/66/1e43bbeb66c55a5a5efec70f1c153cf90cfc7f1662ab4ebe2d844de9122c/coverage-7.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:14fb5b6641ab5b3c4161572579f0f2ea8834f9d3af2f7dd8fbaecd58ef9175cc", size = 217397, upload-time = "2025-08-04T00:34:39.15Z" }, + { url = "https://files.pythonhosted.org/packages/81/01/ae29c129217f6110dc694a217475b8aecbb1b075d8073401f868c825fa99/coverage-7.10.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e96649ac34a3d0e6491e82a2af71098e43be2874b619547c3282fc11d3840a4b", size = 216068, upload-time = "2025-08-04T00:34:40.648Z" }, + { url = "https://files.pythonhosted.org/packages/a2/50/6e9221d4139f357258f36dfa1d8cac4ec56d9d5acf5fdcc909bb016954d7/coverage-7.10.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a2e934e9da26341d342d30bfe91422bbfdb3f1f069ec87f19b2909d10d8dcc4", size = 216285, upload-time = "2025-08-04T00:34:42.441Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ec/89d1d0c0ece0d296b4588e0ef4df185200456d42a47f1141335f482c2fc5/coverage-7.10.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:651015dcd5fd9b5a51ca79ece60d353cacc5beaf304db750407b29c89f72fe2b", size = 257603, upload-time = "2025-08-04T00:34:43.899Z" }, + { url = "https://files.pythonhosted.org/packages/82/06/c830af66734671c778fc49d35b58339e8f0687fbd2ae285c3f96c94da092/coverage-7.10.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81bf6a32212f9f66da03d63ecb9cd9bd48e662050a937db7199dbf47d19831de", size = 259568, upload-time = "2025-08-04T00:34:45.519Z" }, + { url = "https://files.pythonhosted.org/packages/60/57/f280dd6f1c556ecc744fbf39e835c33d3ae987d040d64d61c6f821e87829/coverage-7.10.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d800705f6951f75a905ea6feb03fff8f3ea3468b81e7563373ddc29aa3e5d1ca", size = 261691, upload-time = "2025-08-04T00:34:47.019Z" }, + { url = "https://files.pythonhosted.org/packages/54/2b/c63a0acbd19d99ec32326164c23df3a4e18984fb86e902afdd66ff7b3d83/coverage-7.10.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:248b5394718e10d067354448dc406d651709c6765669679311170da18e0e9af8", size = 259166, upload-time = "2025-08-04T00:34:48.792Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c5/cd2997dcfcbf0683634da9df52d3967bc1f1741c1475dd0e4722012ba9ef/coverage-7.10.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5c61675a922b569137cf943770d7ad3edd0202d992ce53ac328c5ff68213ccf4", size = 257241, upload-time = "2025-08-04T00:34:51.038Z" }, + { url = "https://files.pythonhosted.org/packages/16/26/c9e30f82fdad8d47aee90af4978b18c88fa74369ae0f0ba0dbf08cee3a80/coverage-7.10.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:52d708b5fd65589461381fa442d9905f5903d76c086c6a4108e8e9efdca7a7ed", size = 258139, upload-time = "2025-08-04T00:34:52.533Z" }, + { url = "https://files.pythonhosted.org/packages/c9/99/bdb7bd00bebcd3dedfb895fa9af8e46b91422993e4a37ac634a5f1113790/coverage-7.10.2-cp314-cp314t-win32.whl", hash = "sha256:916369b3b914186b2c5e5ad2f7264b02cff5df96cdd7cdad65dccd39aa5fd9f0", size = 218809, upload-time = "2025-08-04T00:34:54.075Z" }, + { url = "https://files.pythonhosted.org/packages/eb/5e/56a7852e38a04d1520dda4dfbfbf74a3d6dec932c20526968f7444763567/coverage-7.10.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5b9d538e8e04916a5df63052d698b30c74eb0174f2ca9cd942c981f274a18eaf", size = 219926, upload-time = "2025-08-04T00:34:55.643Z" }, + { url = "https://files.pythonhosted.org/packages/e0/12/7fbe6b9c52bb9d627e9556f9f2edfdbe88b315e084cdecc9afead0c3b36a/coverage-7.10.2-cp314-cp314t-win_arm64.whl", hash = "sha256:04c74f9ef1f925456a9fd23a7eef1103126186d0500ef9a0acb0bd2514bdc7cc", size = 217925, upload-time = "2025-08-04T00:34:57.564Z" }, + { url = "https://files.pythonhosted.org/packages/18/d8/9b768ac73a8ac2d10c080af23937212434a958c8d2a1c84e89b450237942/coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f", size = 206973, upload-time = "2025-08-04T00:35:15.918Z" }, ] [package.optional-dependencies] @@ -585,49 +581,49 @@ toml = [ [[package]] name = "cryptography" -version = "45.0.5" +version = "45.0.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/1e/49527ac611af559665f71cbb8f92b332b5ec9c6fbc4e88b0f8e92f5e85df/cryptography-45.0.5.tar.gz", hash = "sha256:72e76caa004ab63accdf26023fccd1d087f6d90ec6048ff33ad0445abf7f605a", size = 744903, upload-time = "2025-07-02T13:06:25.941Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/fb/09e28bc0c46d2c547085e60897fea96310574c70fb21cd58a730a45f3403/cryptography-45.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:101ee65078f6dd3e5a028d4f19c07ffa4dd22cce6a20eaa160f8b5219911e7d8", size = 7043092, upload-time = "2025-07-02T13:05:01.514Z" }, - { url = "https://files.pythonhosted.org/packages/b1/05/2194432935e29b91fb649f6149c1a4f9e6d3d9fc880919f4ad1bcc22641e/cryptography-45.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3a264aae5f7fbb089dbc01e0242d3b67dffe3e6292e1f5182122bdf58e65215d", size = 4205926, upload-time = "2025-07-02T13:05:04.741Z" }, - { url = "https://files.pythonhosted.org/packages/07/8b/9ef5da82350175e32de245646b1884fc01124f53eb31164c77f95a08d682/cryptography-45.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e74d30ec9c7cb2f404af331d5b4099a9b322a8a6b25c4632755c8757345baac5", size = 4429235, upload-time = "2025-07-02T13:05:07.084Z" }, - { url = "https://files.pythonhosted.org/packages/7c/e1/c809f398adde1994ee53438912192d92a1d0fc0f2d7582659d9ef4c28b0c/cryptography-45.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3af26738f2db354aafe492fb3869e955b12b2ef2e16908c8b9cb928128d42c57", size = 4209785, upload-time = "2025-07-02T13:05:09.321Z" }, - { url = "https://files.pythonhosted.org/packages/d0/8b/07eb6bd5acff58406c5e806eff34a124936f41a4fb52909ffa4d00815f8c/cryptography-45.0.5-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e6c00130ed423201c5bc5544c23359141660b07999ad82e34e7bb8f882bb78e0", size = 3893050, upload-time = "2025-07-02T13:05:11.069Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ef/3333295ed58d900a13c92806b67e62f27876845a9a908c939f040887cca9/cryptography-45.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:dd420e577921c8c2d31289536c386aaa30140b473835e97f83bc71ea9d2baf2d", size = 4457379, upload-time = "2025-07-02T13:05:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9d/44080674dee514dbb82b21d6fa5d1055368f208304e2ab1828d85c9de8f4/cryptography-45.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d05a38884db2ba215218745f0781775806bde4f32e07b135348355fe8e4991d9", size = 4209355, upload-time = "2025-07-02T13:05:15.017Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d8/0749f7d39f53f8258e5c18a93131919ac465ee1f9dccaf1b3f420235e0b5/cryptography-45.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ad0caded895a00261a5b4aa9af828baede54638754b51955a0ac75576b831b27", size = 4456087, upload-time = "2025-07-02T13:05:16.945Z" }, - { url = "https://files.pythonhosted.org/packages/09/d7/92acac187387bf08902b0bf0699816f08553927bdd6ba3654da0010289b4/cryptography-45.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9024beb59aca9d31d36fcdc1604dd9bbeed0a55bface9f1908df19178e2f116e", size = 4332873, upload-time = "2025-07-02T13:05:18.743Z" }, - { url = "https://files.pythonhosted.org/packages/03/c2/840e0710da5106a7c3d4153c7215b2736151bba60bf4491bdb421df5056d/cryptography-45.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:91098f02ca81579c85f66df8a588c78f331ca19089763d733e34ad359f474174", size = 4564651, upload-time = "2025-07-02T13:05:21.382Z" }, - { url = "https://files.pythonhosted.org/packages/2e/92/cc723dd6d71e9747a887b94eb3827825c6c24b9e6ce2bb33b847d31d5eaa/cryptography-45.0.5-cp311-abi3-win32.whl", hash = "sha256:926c3ea71a6043921050eaa639137e13dbe7b4ab25800932a8498364fc1abec9", size = 2929050, upload-time = "2025-07-02T13:05:23.39Z" }, - { url = "https://files.pythonhosted.org/packages/1f/10/197da38a5911a48dd5389c043de4aec4b3c94cb836299b01253940788d78/cryptography-45.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:b85980d1e345fe769cfc57c57db2b59cff5464ee0c045d52c0df087e926fbe63", size = 3403224, upload-time = "2025-07-02T13:05:25.202Z" }, - { url = "https://files.pythonhosted.org/packages/fe/2b/160ce8c2765e7a481ce57d55eba1546148583e7b6f85514472b1d151711d/cryptography-45.0.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3562c2f23c612f2e4a6964a61d942f891d29ee320edb62ff48ffb99f3de9ae8", size = 7017143, upload-time = "2025-07-02T13:05:27.229Z" }, - { url = "https://files.pythonhosted.org/packages/c2/e7/2187be2f871c0221a81f55ee3105d3cf3e273c0a0853651d7011eada0d7e/cryptography-45.0.5-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3fcfbefc4a7f332dece7272a88e410f611e79458fab97b5efe14e54fe476f4fd", size = 4197780, upload-time = "2025-07-02T13:05:29.299Z" }, - { url = "https://files.pythonhosted.org/packages/b9/cf/84210c447c06104e6be9122661159ad4ce7a8190011669afceeaea150524/cryptography-45.0.5-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:460f8c39ba66af7db0545a8c6f2eabcbc5a5528fc1cf6c3fa9a1e44cec33385e", size = 4420091, upload-time = "2025-07-02T13:05:31.221Z" }, - { url = "https://files.pythonhosted.org/packages/3e/6a/cb8b5c8bb82fafffa23aeff8d3a39822593cee6e2f16c5ca5c2ecca344f7/cryptography-45.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9b4cf6318915dccfe218e69bbec417fdd7c7185aa7aab139a2c0beb7468c89f0", size = 4198711, upload-time = "2025-07-02T13:05:33.062Z" }, - { url = "https://files.pythonhosted.org/packages/04/f7/36d2d69df69c94cbb2473871926daf0f01ad8e00fe3986ac3c1e8c4ca4b3/cryptography-45.0.5-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2089cc8f70a6e454601525e5bf2779e665d7865af002a5dec8d14e561002e135", size = 3883299, upload-time = "2025-07-02T13:05:34.94Z" }, - { url = "https://files.pythonhosted.org/packages/82/c7/f0ea40f016de72f81288e9fe8d1f6748036cb5ba6118774317a3ffc6022d/cryptography-45.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0027d566d65a38497bc37e0dd7c2f8ceda73597d2ac9ba93810204f56f52ebc7", size = 4450558, upload-time = "2025-07-02T13:05:37.288Z" }, - { url = "https://files.pythonhosted.org/packages/06/ae/94b504dc1a3cdf642d710407c62e86296f7da9e66f27ab12a1ee6fdf005b/cryptography-45.0.5-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:be97d3a19c16a9be00edf79dca949c8fa7eff621763666a145f9f9535a5d7f42", size = 4198020, upload-time = "2025-07-02T13:05:39.102Z" }, - { url = "https://files.pythonhosted.org/packages/05/2b/aaf0adb845d5dabb43480f18f7ca72e94f92c280aa983ddbd0bcd6ecd037/cryptography-45.0.5-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:7760c1c2e1a7084153a0f68fab76e754083b126a47d0117c9ed15e69e2103492", size = 4449759, upload-time = "2025-07-02T13:05:41.398Z" }, - { url = "https://files.pythonhosted.org/packages/91/e4/f17e02066de63e0100a3a01b56f8f1016973a1d67551beaf585157a86b3f/cryptography-45.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6ff8728d8d890b3dda5765276d1bc6fb099252915a2cd3aff960c4c195745dd0", size = 4319991, upload-time = "2025-07-02T13:05:43.64Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2e/e2dbd629481b499b14516eed933f3276eb3239f7cee2dcfa4ee6b44d4711/cryptography-45.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7259038202a47fdecee7e62e0fd0b0738b6daa335354396c6ddebdbe1206af2a", size = 4554189, upload-time = "2025-07-02T13:05:46.045Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ea/a78a0c38f4c8736287b71c2ea3799d173d5ce778c7d6e3c163a95a05ad2a/cryptography-45.0.5-cp37-abi3-win32.whl", hash = "sha256:1e1da5accc0c750056c556a93c3e9cb828970206c68867712ca5805e46dc806f", size = 2911769, upload-time = "2025-07-02T13:05:48.329Z" }, - { url = "https://files.pythonhosted.org/packages/79/b3/28ac139109d9005ad3f6b6f8976ffede6706a6478e21c889ce36c840918e/cryptography-45.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:90cb0a7bb35959f37e23303b7eed0a32280510030daba3f7fdfbb65defde6a97", size = 3390016, upload-time = "2025-07-02T13:05:50.811Z" }, - { url = "https://files.pythonhosted.org/packages/f8/8b/34394337abe4566848a2bd49b26bcd4b07fd466afd3e8cce4cb79a390869/cryptography-45.0.5-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:206210d03c1193f4e1ff681d22885181d47efa1ab3018766a7b32a7b3d6e6afd", size = 3575762, upload-time = "2025-07-02T13:05:53.166Z" }, - { url = "https://files.pythonhosted.org/packages/8b/5d/a19441c1e89afb0f173ac13178606ca6fab0d3bd3ebc29e9ed1318b507fc/cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c648025b6840fe62e57107e0a25f604db740e728bd67da4f6f060f03017d5097", size = 4140906, upload-time = "2025-07-02T13:05:55.914Z" }, - { url = "https://files.pythonhosted.org/packages/4b/db/daceb259982a3c2da4e619f45b5bfdec0e922a23de213b2636e78ef0919b/cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b8fa8b0a35a9982a3c60ec79905ba5bb090fc0b9addcfd3dc2dd04267e45f25e", size = 4374411, upload-time = "2025-07-02T13:05:57.814Z" }, - { url = "https://files.pythonhosted.org/packages/6a/35/5d06ad06402fc522c8bf7eab73422d05e789b4e38fe3206a85e3d6966c11/cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:14d96584701a887763384f3c47f0ca7c1cce322aa1c31172680eb596b890ec30", size = 4140942, upload-time = "2025-07-02T13:06:00.137Z" }, - { url = "https://files.pythonhosted.org/packages/65/79/020a5413347e44c382ef1f7f7e7a66817cd6273e3e6b5a72d18177b08b2f/cryptography-45.0.5-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57c816dfbd1659a367831baca4b775b2a5b43c003daf52e9d57e1d30bc2e1b0e", size = 4374079, upload-time = "2025-07-02T13:06:02.043Z" }, - { url = "https://files.pythonhosted.org/packages/9b/c5/c0e07d84a9a2a8a0ed4f865e58f37c71af3eab7d5e094ff1b21f3f3af3bc/cryptography-45.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b9e38e0a83cd51e07f5a48ff9691cae95a79bea28fe4ded168a8e5c6c77e819d", size = 3321362, upload-time = "2025-07-02T13:06:04.463Z" }, - { url = "https://files.pythonhosted.org/packages/c0/71/9bdbcfd58d6ff5084687fe722c58ac718ebedbc98b9f8f93781354e6d286/cryptography-45.0.5-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8c4a6ff8a30e9e3d38ac0539e9a9e02540ab3f827a3394f8852432f6b0ea152e", size = 3587878, upload-time = "2025-07-02T13:06:06.339Z" }, - { url = "https://files.pythonhosted.org/packages/f0/63/83516cfb87f4a8756eaa4203f93b283fda23d210fc14e1e594bd5f20edb6/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bd4c45986472694e5121084c6ebbd112aa919a25e783b87eb95953c9573906d6", size = 4152447, upload-time = "2025-07-02T13:06:08.345Z" }, - { url = "https://files.pythonhosted.org/packages/22/11/d2823d2a5a0bd5802b3565437add16f5c8ce1f0778bf3822f89ad2740a38/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:982518cd64c54fcada9d7e5cf28eabd3ee76bd03ab18e08a48cad7e8b6f31b18", size = 4386778, upload-time = "2025-07-02T13:06:10.263Z" }, - { url = "https://files.pythonhosted.org/packages/5f/38/6bf177ca6bce4fe14704ab3e93627c5b0ca05242261a2e43ef3168472540/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:12e55281d993a793b0e883066f590c1ae1e802e3acb67f8b442e721e475e6463", size = 4151627, upload-time = "2025-07-02T13:06:13.097Z" }, - { url = "https://files.pythonhosted.org/packages/38/6a/69fc67e5266bff68a91bcb81dff8fb0aba4d79a78521a08812048913e16f/cryptography-45.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:5aa1e32983d4443e310f726ee4b071ab7569f58eedfdd65e9675484a4eb67bd1", size = 4385593, upload-time = "2025-07-02T13:06:15.689Z" }, - { url = "https://files.pythonhosted.org/packages/f6/34/31a1604c9a9ade0fdab61eb48570e09a796f4d9836121266447b0eaf7feb/cryptography-45.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e357286c1b76403dd384d938f93c46b2b058ed4dfcdce64a770f0537ed3feb6f", size = 3331106, upload-time = "2025-07-02T13:06:18.058Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/d6/0d/d13399c94234ee8f3df384819dc67e0c5ce215fb751d567a55a1f4b028c7/cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719", size = 744949, upload-time = "2025-08-05T23:59:27.93Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/29/2793d178d0eda1ca4a09a7c4e09a5185e75738cc6d526433e8663b460ea6/cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74", size = 7042702, upload-time = "2025-08-05T23:58:23.464Z" }, + { url = "https://files.pythonhosted.org/packages/b3/b6/cabd07410f222f32c8d55486c464f432808abaa1f12af9afcbe8f2f19030/cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f", size = 4206483, upload-time = "2025-08-05T23:58:27.132Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9e/f9c7d36a38b1cfeb1cc74849aabe9bf817990f7603ff6eb485e0d70e0b27/cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf", size = 4429679, upload-time = "2025-08-05T23:58:29.152Z" }, + { url = "https://files.pythonhosted.org/packages/9c/2a/4434c17eb32ef30b254b9e8b9830cee4e516f08b47fdd291c5b1255b8101/cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5", size = 4210553, upload-time = "2025-08-05T23:58:30.596Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1d/09a5df8e0c4b7970f5d1f3aff1b640df6d4be28a64cae970d56c6cf1c772/cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2", size = 3894499, upload-time = "2025-08-05T23:58:32.03Z" }, + { url = "https://files.pythonhosted.org/packages/79/62/120842ab20d9150a9d3a6bdc07fe2870384e82f5266d41c53b08a3a96b34/cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08", size = 4458484, upload-time = "2025-08-05T23:58:33.526Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/1bc3634d45ddfed0871bfba52cf8f1ad724761662a0c792b97a951fb1b30/cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402", size = 4210281, upload-time = "2025-08-05T23:58:35.445Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fe/ffb12c2d83d0ee625f124880a1f023b5878f79da92e64c37962bbbe35f3f/cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42", size = 4456890, upload-time = "2025-08-05T23:58:36.923Z" }, + { url = "https://files.pythonhosted.org/packages/8c/8e/b3f3fe0dc82c77a0deb5f493b23311e09193f2268b77196ec0f7a36e3f3e/cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05", size = 4333247, upload-time = "2025-08-05T23:58:38.781Z" }, + { url = "https://files.pythonhosted.org/packages/b3/a6/c3ef2ab9e334da27a1d7b56af4a2417d77e7806b2e0f90d6267ce120d2e4/cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453", size = 4565045, upload-time = "2025-08-05T23:58:40.415Z" }, + { url = "https://files.pythonhosted.org/packages/31/c3/77722446b13fa71dddd820a5faab4ce6db49e7e0bf8312ef4192a3f78e2f/cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159", size = 2928923, upload-time = "2025-08-05T23:58:41.919Z" }, + { url = "https://files.pythonhosted.org/packages/38/63/a025c3225188a811b82932a4dcc8457a26c3729d81578ccecbcce2cb784e/cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec", size = 3403805, upload-time = "2025-08-05T23:58:43.792Z" }, + { url = "https://files.pythonhosted.org/packages/5b/af/bcfbea93a30809f126d51c074ee0fac5bd9d57d068edf56c2a73abedbea4/cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0", size = 7020111, upload-time = "2025-08-05T23:58:45.316Z" }, + { url = "https://files.pythonhosted.org/packages/98/c6/ea5173689e014f1a8470899cd5beeb358e22bb3cf5a876060f9d1ca78af4/cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394", size = 4198169, upload-time = "2025-08-05T23:58:47.121Z" }, + { url = "https://files.pythonhosted.org/packages/ba/73/b12995edc0c7e2311ffb57ebd3b351f6b268fed37d93bfc6f9856e01c473/cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9", size = 4421273, upload-time = "2025-08-05T23:58:48.557Z" }, + { url = "https://files.pythonhosted.org/packages/f7/6e/286894f6f71926bc0da67408c853dd9ba953f662dcb70993a59fd499f111/cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3", size = 4199211, upload-time = "2025-08-05T23:58:50.139Z" }, + { url = "https://files.pythonhosted.org/packages/de/34/a7f55e39b9623c5cb571d77a6a90387fe557908ffc44f6872f26ca8ae270/cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3", size = 3883732, upload-time = "2025-08-05T23:58:52.253Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b9/c6d32edbcba0cd9f5df90f29ed46a65c4631c4fbe11187feb9169c6ff506/cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301", size = 4450655, upload-time = "2025-08-05T23:58:53.848Z" }, + { url = "https://files.pythonhosted.org/packages/77/2d/09b097adfdee0227cfd4c699b3375a842080f065bab9014248933497c3f9/cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5", size = 4198956, upload-time = "2025-08-05T23:58:55.209Z" }, + { url = "https://files.pythonhosted.org/packages/55/66/061ec6689207d54effdff535bbdf85cc380d32dd5377173085812565cf38/cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016", size = 4449859, upload-time = "2025-08-05T23:58:56.639Z" }, + { url = "https://files.pythonhosted.org/packages/41/ff/e7d5a2ad2d035e5a2af116e1a3adb4d8fcd0be92a18032917a089c6e5028/cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3", size = 4320254, upload-time = "2025-08-05T23:58:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/82/27/092d311af22095d288f4db89fcaebadfb2f28944f3d790a4cf51fe5ddaeb/cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9", size = 4554815, upload-time = "2025-08-05T23:59:00.283Z" }, + { url = "https://files.pythonhosted.org/packages/7e/01/aa2f4940262d588a8fdf4edabe4cda45854d00ebc6eaac12568b3a491a16/cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02", size = 2912147, upload-time = "2025-08-05T23:59:01.716Z" }, + { url = "https://files.pythonhosted.org/packages/0a/bc/16e0276078c2de3ceef6b5a34b965f4436215efac45313df90d55f0ba2d2/cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b", size = 3390459, upload-time = "2025-08-05T23:59:03.358Z" }, + { url = "https://files.pythonhosted.org/packages/56/d2/4482d97c948c029be08cb29854a91bd2ae8da7eb9c4152461f1244dcea70/cryptography-45.0.6-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012", size = 3576812, upload-time = "2025-08-05T23:59:04.833Z" }, + { url = "https://files.pythonhosted.org/packages/ec/24/55fc238fcaa122855442604b8badb2d442367dfbd5a7ca4bb0bd346e263a/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d", size = 4141694, upload-time = "2025-08-05T23:59:06.66Z" }, + { url = "https://files.pythonhosted.org/packages/f9/7e/3ea4fa6fbe51baf3903806a0241c666b04c73d2358a3ecce09ebee8b9622/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d", size = 4375010, upload-time = "2025-08-05T23:59:08.14Z" }, + { url = "https://files.pythonhosted.org/packages/50/42/ec5a892d82d2a2c29f80fc19ced4ba669bca29f032faf6989609cff1f8dc/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da", size = 4141377, upload-time = "2025-08-05T23:59:09.584Z" }, + { url = "https://files.pythonhosted.org/packages/e7/d7/246c4c973a22b9c2931999da953a2c19cae7c66b9154c2d62ffed811225e/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db", size = 4374609, upload-time = "2025-08-05T23:59:11.923Z" }, + { url = "https://files.pythonhosted.org/packages/78/6d/c49ccf243f0a1b0781c2a8de8123ee552f0c8a417c6367a24d2ecb7c11b3/cryptography-45.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18", size = 3322156, upload-time = "2025-08-05T23:59:13.597Z" }, + { url = "https://files.pythonhosted.org/packages/61/69/c252de4ec047ba2f567ecb53149410219577d408c2aea9c989acae7eafce/cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983", size = 3584669, upload-time = "2025-08-05T23:59:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/e3/fe/deea71e9f310a31fe0a6bfee670955152128d309ea2d1c79e2a5ae0f0401/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427", size = 4153022, upload-time = "2025-08-05T23:59:16.954Z" }, + { url = "https://files.pythonhosted.org/packages/60/45/a77452f5e49cb580feedba6606d66ae7b82c128947aa754533b3d1bd44b0/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b", size = 4386802, upload-time = "2025-08-05T23:59:18.55Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b9/a2f747d2acd5e3075fdf5c145c7c3568895daaa38b3b0c960ef830db6cdc/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c", size = 4152706, upload-time = "2025-08-05T23:59:20.044Z" }, + { url = "https://files.pythonhosted.org/packages/81/ec/381b3e8d0685a3f3f304a382aa3dfce36af2d76467da0fd4bb21ddccc7b2/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385", size = 4386740, upload-time = "2025-08-05T23:59:21.525Z" }, + { url = "https://files.pythonhosted.org/packages/0a/76/cf8d69da8d0b5ecb0db406f24a63a3f69ba5e791a11b782aeeefef27ccbb/cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043", size = 3331874, upload-time = "2025-08-05T23:59:23.017Z" }, ] [[package]] @@ -641,27 +637,27 @@ wheels = [ [[package]] name = "debugpy" -version = "1.8.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/3a9a28ddb750a76eaec445c7f4d3147ea2c579a97dbd9e25d39001b92b21/debugpy-1.8.15.tar.gz", hash = "sha256:58d7a20b7773ab5ee6bdfb2e6cf622fdf1e40c9d5aef2857d85391526719ac00", size = 1643279, upload-time = "2025-07-15T16:43:29.135Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/51/0b4315169f0d945271db037ae6b98c0548a2d48cc036335cd1b2f5516c1b/debugpy-1.8.15-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:e9a8125c85172e3ec30985012e7a81ea5e70bbb836637f8a4104f454f9b06c97", size = 2084890, upload-time = "2025-07-15T16:43:31.239Z" }, - { url = "https://files.pythonhosted.org/packages/36/cc/a5391dedb079280d7b72418022e00ba8227ae0b5bc8b2e3d1ecffc5d6b01/debugpy-1.8.15-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fd0b6b5eccaa745c214fd240ea82f46049d99ef74b185a3517dad3ea1ec55d9", size = 3561470, upload-time = "2025-07-15T16:43:32.515Z" }, - { url = "https://files.pythonhosted.org/packages/e8/92/acf64b92010c66b33c077dee3862c733798a2c90e7d14b25c01d771e2a0d/debugpy-1.8.15-cp310-cp310-win32.whl", hash = "sha256:8181cce4d344010f6bfe94a531c351a46a96b0f7987750932b2908e7a1e14a55", size = 5229194, upload-time = "2025-07-15T16:43:33.997Z" }, - { url = "https://files.pythonhosted.org/packages/3f/f5/c58c015c9ff78de35901bea3ab4dbf7946d7a4aa867ee73875df06ba6468/debugpy-1.8.15-cp310-cp310-win_amd64.whl", hash = "sha256:af2dcae4e4cd6e8b35f982ccab29fe65f7e8766e10720a717bc80c464584ee21", size = 5260900, upload-time = "2025-07-15T16:43:35.413Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b3/1c44a2ed311199ab11c2299c9474a6c7cd80d19278defd333aeb7c287995/debugpy-1.8.15-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:babc4fb1962dd6a37e94d611280e3d0d11a1f5e6c72ac9b3d87a08212c4b6dd3", size = 2183442, upload-time = "2025-07-15T16:43:36.733Z" }, - { url = "https://files.pythonhosted.org/packages/f6/69/e2dcb721491e1c294d348681227c9b44fb95218f379aa88e12a19d85528d/debugpy-1.8.15-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f778e68f2986a58479d0ac4f643e0b8c82fdd97c2e200d4d61e7c2d13838eb53", size = 3134215, upload-time = "2025-07-15T16:43:38.116Z" }, - { url = "https://files.pythonhosted.org/packages/17/76/4ce63b95d8294dcf2fd1820860b300a420d077df4e93afcaa25a984c2ca7/debugpy-1.8.15-cp311-cp311-win32.whl", hash = "sha256:f9d1b5abd75cd965e2deabb1a06b0e93a1546f31f9f621d2705e78104377c702", size = 5154037, upload-time = "2025-07-15T16:43:39.471Z" }, - { url = "https://files.pythonhosted.org/packages/c2/a7/e5a7c784465eb9c976d84408873d597dc7ce74a0fc69ed009548a1a94813/debugpy-1.8.15-cp311-cp311-win_amd64.whl", hash = "sha256:62954fb904bec463e2b5a415777f6d1926c97febb08ef1694da0e5d1463c5c3b", size = 5178133, upload-time = "2025-07-15T16:43:40.969Z" }, - { url = "https://files.pythonhosted.org/packages/ab/4a/4508d256e52897f5cdfee6a6d7580974811e911c6d01321df3264508a5ac/debugpy-1.8.15-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:3dcc7225cb317469721ab5136cda9ff9c8b6e6fb43e87c9e15d5b108b99d01ba", size = 2511197, upload-time = "2025-07-15T16:43:42.343Z" }, - { url = "https://files.pythonhosted.org/packages/99/8d/7f6ef1097e7fecf26b4ef72338d08e41644a41b7ee958a19f494ffcffc29/debugpy-1.8.15-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:047a493ca93c85ccede1dbbaf4e66816794bdc214213dde41a9a61e42d27f8fc", size = 4229517, upload-time = "2025-07-15T16:43:44.14Z" }, - { url = "https://files.pythonhosted.org/packages/3f/e8/e8c6a9aa33a9c9c6dacbf31747384f6ed2adde4de2e9693c766bdf323aa3/debugpy-1.8.15-cp312-cp312-win32.whl", hash = "sha256:b08e9b0bc260cf324c890626961dad4ffd973f7568fbf57feb3c3a65ab6b6327", size = 5276132, upload-time = "2025-07-15T16:43:45.529Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ad/231050c6177b3476b85fcea01e565dac83607b5233d003ff067e2ee44d8f/debugpy-1.8.15-cp312-cp312-win_amd64.whl", hash = "sha256:e2a4fe357c92334272eb2845fcfcdbec3ef9f22c16cf613c388ac0887aed15fa", size = 5317645, upload-time = "2025-07-15T16:43:46.968Z" }, - { url = "https://files.pythonhosted.org/packages/28/70/2928aad2310726d5920b18ed9f54b9f06df5aa4c10cf9b45fa18ff0ab7e8/debugpy-1.8.15-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:f5e01291ad7d6649aed5773256c5bba7a1a556196300232de1474c3c372592bf", size = 2495538, upload-time = "2025-07-15T16:43:48.927Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c6/9b8ffb4ca91fac8b2877eef63c9cc0e87dd2570b1120054c272815ec4cd0/debugpy-1.8.15-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dc0f0d00e528d915e0ce1c78e771475b2335b376c49afcc7382ee0b146bab6", size = 4221874, upload-time = "2025-07-15T16:43:50.282Z" }, - { url = "https://files.pythonhosted.org/packages/55/8a/9b8d59674b4bf489318c7c46a1aab58e606e583651438084b7e029bf3c43/debugpy-1.8.15-cp313-cp313-win32.whl", hash = "sha256:fcf0748d4f6e25f89dc5e013d1129ca6f26ad4da405e0723a4f704583896a709", size = 5275949, upload-time = "2025-07-15T16:43:52.079Z" }, - { url = "https://files.pythonhosted.org/packages/72/83/9e58e6fdfa8710a5e6ec06c2401241b9ad48b71c0a7eb99570a1f1edb1d3/debugpy-1.8.15-cp313-cp313-win_amd64.whl", hash = "sha256:73c943776cb83e36baf95e8f7f8da765896fd94b05991e7bc162456d25500683", size = 5317720, upload-time = "2025-07-15T16:43:53.703Z" }, - { url = "https://files.pythonhosted.org/packages/07/d5/98748d9860e767a1248b5e31ffa7ce8cb7006e97bf8abbf3d891d0a8ba4e/debugpy-1.8.15-py2.py3-none-any.whl", hash = "sha256:bce2e6c5ff4f2e00b98d45e7e01a49c7b489ff6df5f12d881c67d2f1ac635f3d", size = 5282697, upload-time = "2025-07-15T16:44:07.996Z" }, +version = "1.8.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/d4/722d0bcc7986172ac2ef3c979ad56a1030e3afd44ced136d45f8142b1f4a/debugpy-1.8.16.tar.gz", hash = "sha256:31e69a1feb1cf6b51efbed3f6c9b0ef03bc46ff050679c4be7ea6d2e23540870", size = 1643809, upload-time = "2025-08-06T18:00:02.647Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/fd/f1b75ebc61d90882595b81d808efd3573c082e1c3407850d9dccac4ae904/debugpy-1.8.16-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:2a3958fb9c2f40ed8ea48a0d34895b461de57a1f9862e7478716c35d76f56c65", size = 2085511, upload-time = "2025-08-06T18:00:05.067Z" }, + { url = "https://files.pythonhosted.org/packages/df/5e/c5c1934352871128b30a1a144a58b5baa546e1b57bd47dbed788bad4431c/debugpy-1.8.16-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5ca7314042e8a614cc2574cd71f6ccd7e13a9708ce3c6d8436959eae56f2378", size = 3562094, upload-time = "2025-08-06T18:00:06.66Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d5/2ebe42377e5a78dc786afc25e61ee83c5628d63f32dfa41092597d52fe83/debugpy-1.8.16-cp310-cp310-win32.whl", hash = "sha256:8624a6111dc312ed8c363347a0b59c5acc6210d897e41a7c069de3c53235c9a6", size = 5234277, upload-time = "2025-08-06T18:00:08.429Z" }, + { url = "https://files.pythonhosted.org/packages/54/f8/e774ad16a60b9913213dbabb7472074c5a7b0d84f07c1f383040a9690057/debugpy-1.8.16-cp310-cp310-win_amd64.whl", hash = "sha256:fee6db83ea5c978baf042440cfe29695e1a5d48a30147abf4c3be87513609817", size = 5266011, upload-time = "2025-08-06T18:00:10.162Z" }, + { url = "https://files.pythonhosted.org/packages/63/d6/ad70ba8b49b23fa286fb21081cf732232cc19374af362051da9c7537ae52/debugpy-1.8.16-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:67371b28b79a6a12bcc027d94a06158f2fde223e35b5c4e0783b6f9d3b39274a", size = 2184063, upload-time = "2025-08-06T18:00:11.885Z" }, + { url = "https://files.pythonhosted.org/packages/aa/49/7b03e88dea9759a4c7910143f87f92beb494daaae25560184ff4ae883f9e/debugpy-1.8.16-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2abae6dd02523bec2dee16bd6b0781cccb53fd4995e5c71cc659b5f45581898", size = 3134837, upload-time = "2025-08-06T18:00:13.782Z" }, + { url = "https://files.pythonhosted.org/packages/5d/52/b348930316921de7565fbe37a487d15409041713004f3d74d03eb077dbd4/debugpy-1.8.16-cp311-cp311-win32.whl", hash = "sha256:f8340a3ac2ed4f5da59e064aa92e39edd52729a88fbde7bbaa54e08249a04493", size = 5159142, upload-time = "2025-08-06T18:00:15.391Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ef/9aa9549ce1e10cea696d980292e71672a91ee4a6a691ce5f8629e8f48c49/debugpy-1.8.16-cp311-cp311-win_amd64.whl", hash = "sha256:70f5fcd6d4d0c150a878d2aa37391c52de788c3dc680b97bdb5e529cb80df87a", size = 5183117, upload-time = "2025-08-06T18:00:17.251Z" }, + { url = "https://files.pythonhosted.org/packages/61/fb/0387c0e108d842c902801bc65ccc53e5b91d8c169702a9bbf4f7efcedf0c/debugpy-1.8.16-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:b202e2843e32e80b3b584bcebfe0e65e0392920dc70df11b2bfe1afcb7a085e4", size = 2511822, upload-time = "2025-08-06T18:00:18.526Z" }, + { url = "https://files.pythonhosted.org/packages/37/44/19e02745cae22bf96440141f94e15a69a1afaa3a64ddfc38004668fcdebf/debugpy-1.8.16-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64473c4a306ba11a99fe0bb14622ba4fbd943eb004847d9b69b107bde45aa9ea", size = 4230135, upload-time = "2025-08-06T18:00:19.997Z" }, + { url = "https://files.pythonhosted.org/packages/f3/0b/19b1ba5ee4412f303475a2c7ad5858efb99c90eae5ec627aa6275c439957/debugpy-1.8.16-cp312-cp312-win32.whl", hash = "sha256:833a61ed446426e38b0dd8be3e9d45ae285d424f5bf6cd5b2b559c8f12305508", size = 5281271, upload-time = "2025-08-06T18:00:21.281Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e0/bc62e2dc141de53bd03e2c7cb9d7011de2e65e8bdcdaa26703e4d28656ba/debugpy-1.8.16-cp312-cp312-win_amd64.whl", hash = "sha256:75f204684581e9ef3dc2f67687c3c8c183fde2d6675ab131d94084baf8084121", size = 5323149, upload-time = "2025-08-06T18:00:23.033Z" }, + { url = "https://files.pythonhosted.org/packages/62/66/607ab45cc79e60624df386e233ab64a6d8d39ea02e7f80e19c1d451345bb/debugpy-1.8.16-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:85df3adb1de5258dca910ae0bb185e48c98801ec15018a263a92bb06be1c8787", size = 2496157, upload-time = "2025-08-06T18:00:24.361Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a0/c95baae08a75bceabb79868d663a0736655e427ab9c81fb848da29edaeac/debugpy-1.8.16-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee89e948bc236a5c43c4214ac62d28b29388453f5fd328d739035e205365f0b", size = 4222491, upload-time = "2025-08-06T18:00:25.806Z" }, + { url = "https://files.pythonhosted.org/packages/5b/2f/1c8db6ddd8a257c3cd2c46413b267f1d5fa3df910401c899513ce30392d6/debugpy-1.8.16-cp313-cp313-win32.whl", hash = "sha256:cf358066650439847ec5ff3dae1da98b5461ea5da0173d93d5e10f477c94609a", size = 5281126, upload-time = "2025-08-06T18:00:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ba/c3e154ab307366d6c5a9c1b68de04914e2ce7fa2f50d578311d8cc5074b2/debugpy-1.8.16-cp313-cp313-win_amd64.whl", hash = "sha256:b5aea1083f6f50023e8509399d7dc6535a351cc9f2e8827d1e093175e4d9fa4c", size = 5323094, upload-time = "2025-08-06T18:00:29.03Z" }, + { url = "https://files.pythonhosted.org/packages/52/57/ecc9ae29fa5b2d90107cd1d9bf8ed19aacb74b2264d986ae9d44fe9bdf87/debugpy-1.8.16-py2.py3-none-any.whl", hash = "sha256:19c9521962475b87da6f673514f7fd610328757ec993bf7ec0d8c96f9a325f9e", size = 5287700, upload-time = "2025-08-06T18:00:42.333Z" }, ] [[package]] @@ -914,44 +910,16 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/34/80/de3eb55eb581815342d097214bed4c59e806b05f1b3110df03b2280d6dfd/grpcio-1.74.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd3c71aeee838299c5887230b8a1822795325ddfea635edd82954c1eaa831e24", size = 4489214, upload-time = "2025-07-24T18:53:59.771Z" }, ] -[[package]] -name = "gymnasium" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", -] -dependencies = [ - { name = "cloudpickle", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "farama-notifications", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "typing-extensions", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4e/12/1047b8fdbfcdce74022048d916e844ad7e6e1114d81d26a7aed657e3a76d/gymnasium-1.0.0.tar.gz", hash = "sha256:9d2b66f30c1b34fe3c2ce7fae65ecf365d0e9982d2b3d860235e773328a3b403", size = 821389, upload-time = "2024-10-08T10:01:02.49Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/85/f5039ce2df5f0789ff1240f08a59f3e8c92e4c5f99543b7aad7388532f7c/gymnasium-1.0.0-py3-none-any.whl", hash = "sha256:b6f40e1e24c5bd419361e1a5b86a9117d2499baecc3a660d44dfff4c465393ad", size = 958120, upload-time = "2024-10-08T10:01:00.337Z" }, -] - [[package]] name = "gymnasium" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", - "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", - "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", -] dependencies = [ - { name = "cloudpickle", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "farama-notifications", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')" }, + { name = "cloudpickle" }, + { name = "farama-notifications" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, - { name = "typing-extensions", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/17/c2a0e15c2cd5a8e788389b280996db927b923410de676ec5c7b2695e9261/gymnasium-1.2.0.tar.gz", hash = "sha256:344e87561012558f603880baf264ebc97f8a5c997a957b0c9f910281145534b0", size = 821142, upload-time = "2025-06-27T08:21:20.262Z" } wheels = [ @@ -1026,7 +994,7 @@ wheels = [ [[package]] name = "ipykernel" -version = "6.30.0" +version = "6.30.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "appnope", marker = "sys_platform == 'darwin'" }, @@ -1044,9 +1012,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/27/9e6e30ed92f2ac53d29f70b09da8b2dc456e256148e289678fa0e825f46a/ipykernel-6.30.0.tar.gz", hash = "sha256:b7b808ddb2d261aae2df3a26ff3ff810046e6de3dfbc6f7de8c98ea0a6cb632c", size = 165125, upload-time = "2025-07-21T10:36:09.259Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/76/11082e338e0daadc89c8ff866185de11daf67d181901038f9e139d109761/ipykernel-6.30.1.tar.gz", hash = "sha256:6abb270161896402e76b91394fcdce5d1be5d45f456671e5080572f8505be39b", size = 166260, upload-time = "2025-08-04T15:47:35.018Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/3d/00813c3d9b46e3dcd88bd4530e0a3c63c0509e5d8c9eff34723ea243ab04/ipykernel-6.30.0-py3-none-any.whl", hash = "sha256:fd2936e55c4a1c2ee8b1e5fa6a372b8eecc0ab1338750dee76f48fa5cca1301e", size = 117264, upload-time = "2025-07-21T10:36:06.854Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c7/b445faca8deb954fe536abebff4ece5b097b923de482b26e78448c89d1dd/ipykernel-6.30.1-py3-none-any.whl", hash = "sha256:aa6b9fb93dca949069d8b85b6c79b2518e32ac583ae9c7d37c51d119e18b3fb4", size = 117484, upload-time = "2025-08-04T15:47:32.622Z" }, ] [[package]] @@ -1080,11 +1048,9 @@ name = "ipython" version = "9.4.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version >= '3.13'", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -1558,11 +1524,10 @@ dependencies = [ { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'" }, { name = "qiskit-ibm-transpiler" }, { name = "rich" }, - { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "sb3-contrib" }, { name = "scikit-learn" }, { name = "tensorboard" }, - { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "torch" }, { name = "tqdm" }, { name = "typing-extensions" }, ] @@ -1619,7 +1584,7 @@ requires-dist = [ { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "tensorboard", specifier = ">=2.17.0" }, - { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.7.1,<2.8.0" }, + { name = "torch", specifier = ">=2.7.1,<2.8.0" }, { name = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, ] @@ -1792,10 +1757,8 @@ name = "numpy" version = "2.3.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", + "python_full_version >= '3.13'", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] sdist = { url = "https://files.pythonhosted.org/packages/37/7d/3fec4199c5ffb892bed55cff901e4f39a58c81df9c44c280499e92cad264/numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48", size = 20489306, upload-time = "2025-07-24T21:32:07.553Z" } @@ -2818,7 +2781,7 @@ wheels = [ [[package]] name = "qiskit-ibm-runtime" -version = "0.40.1" +version = "0.41.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ibm-platform-services" }, @@ -2832,9 +2795,9 @@ dependencies = [ { name = "requests-ntlm" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b0/90/c16c0a83400b29aa9f76f463ebeb3b5a4abc711eebd6ddd27509fa0a02b4/qiskit_ibm_runtime-0.40.1.tar.gz", hash = "sha256:83fd172357a28d69b3289009a724ec14d70c4367dbb5aa140ffd63aa101c3ae1", size = 3198615, upload-time = "2025-06-05T15:59:51.692Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/0f/8dce46911ad83dde9b593ee56136b9ba05950551bf8242a83e4108e9a5df/qiskit_ibm_runtime-0.41.0.tar.gz", hash = "sha256:c4a1b79026419a911b32da802c5b6a694c23a1bbf63854205e13a6c4bbd65cd2", size = 1472034, upload-time = "2025-08-05T18:23:56.891Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/2e/7ef9afa14f94affb7afd472edd70358c1a0c66e5cbeac1b2a29ce84b8a5d/qiskit_ibm_runtime-0.40.1-py3-none-any.whl", hash = "sha256:5a67e4c55b6e0a2bc9041c1ec7b8c5adc43a50f7dfb8a2521a0c2f3ed4aaa712", size = 3196409, upload-time = "2025-06-05T15:59:49.117Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/cc8edf7f4500cb3e99c187c214977880396ea2462c2c28ece98db47a8075/qiskit_ibm_runtime-0.41.0-py3-none-any.whl", hash = "sha256:09692ef0b2fc8562298f5f0ebee394486233359149326490b59bb16ea5b68f2b", size = 1418666, upload-time = "2025-08-05T18:23:54.956Z" }, ] [[package]] @@ -3091,37 +3054,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3e/79/9bdd52d2a33d468c81c1827de1b588080cb055d1d3561b194ab7bf2635b5/rustworkx-0.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:905df608843c32fa45ac023687769fe13056edf7584474c801d5c50705d76e9b", size = 1953559, upload-time = "2025-01-24T01:22:06.136Z" }, ] -[[package]] -name = "sb3-contrib" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", -] -dependencies = [ - { name = "stable-baselines3", version = "2.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/4e/dd31aba603634a7b9473b502fe85b694e4392c448eae0d345640b87211c2/sb3_contrib-2.4.0.tar.gz", hash = "sha256:a3709d97ddd529c45e3d56a5ae7e61a380bb2e11bacb9a3e6951ac0c481350ca", size = 89358, upload-time = "2024-11-18T10:20:53.214Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/de/33d3b00116488de9371a56009089ab408d949cda7057e2560c8efae810df/sb3_contrib-2.4.0-py3-none-any.whl", hash = "sha256:725d90157028a94c69804f2e7332128518fb7cbab39e7e141d2d0355547a72ab", size = 92752, upload-time = "2024-11-18T10:20:51.074Z" }, -] - [[package]] name = "sb3-contrib" version = "2.7.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", - "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", - "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", -] dependencies = [ - { name = "stable-baselines3", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "stable-baselines3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/23/2831ccecc8fc2fcda401804f3ed1dc3b81f7c4ad3cb32dc6b1cd79f91c49/sb3_contrib-2.7.0.tar.gz", hash = "sha256:87281ae64e6965e46ac24b58778241d2b07b29996044491267ed844c1a75acfe", size = 90289, upload-time = "2025-07-25T13:02:07.208Z" } wheels = [ @@ -3234,11 +3172,9 @@ name = "scipy" version = "1.16.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version >= '3.13'", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -3391,11 +3327,9 @@ name = "sphinx" version = "8.2.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", + "python_full_version >= '3.13'", "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", ] @@ -3563,15 +3497,15 @@ wheels = [ [[package]] name = "sphinxext-opengraph" -version = "0.10.0" +version = "0.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/27/d8e269030e1f063494ee2b8110256de8fa05b1ef532c76e6807b5c42c8b1/sphinxext_opengraph-0.10.0.tar.gz", hash = "sha256:5781149c1dfc306c3701661acdd02c512c2e6f21d2253487bf0b39639017fc24", size = 1027562, upload-time = "2025-04-04T21:35:19.646Z" } +sdist = { url = "https://files.pythonhosted.org/packages/76/8f/6c0d869ac0fd25ae90510350800312f80bd0618d19f093e70fca3d670b32/sphinxext_opengraph-0.12.0.tar.gz", hash = "sha256:38bc17addd5d8bccc148daa7c6c13845c329c2687378ee8fdfc81942cc72a79d", size = 1026784, upload-time = "2025-08-04T21:53:36.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/3f/bb8bbee4d26aa2abd46e76025697040708e1b0d37c9f198877cebf0e3ba0/sphinxext_opengraph-0.10.0-py3-none-any.whl", hash = "sha256:8afd33f96a02d9506d9dc8f284840888ca8948482ac93015a68d88493df43712", size = 1004031, upload-time = "2025-04-04T21:35:17.637Z" }, + { url = "https://files.pythonhosted.org/packages/1b/26/8388918251df75086c7fcd9cd7e231f08774e3f4ce6fc911ff105a87a300/sphinxext_opengraph-0.12.0-py3-none-any.whl", hash = "sha256:f60892d5fa4cc25889b0baa5ec1c778a8ef87aa7c1f4bb5f93f11befdb0d7b9c", size = 1004063, upload-time = "2025-08-04T21:53:34.641Z" }, ] [[package]] @@ -3639,48 +3573,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/35/dd/698e7a1701908c62bfe371c197eba258182c3f41a3fc51ae588f8d46f3a7/sspilib-0.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:44b89f866e0d14c8393dbc5a49c59296dd7b83a7ca97a0f9d6bd49cc46a04498", size = 528415, upload-time = "2025-04-30T19:37:13.551Z" }, ] -[[package]] -name = "stable-baselines3" -version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", -] -dependencies = [ - { name = "cloudpickle", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "gymnasium", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "matplotlib", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "pandas", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fa/3b/13aacfe41697455f559449ad0dc5f51b4f30aed8fb000131225c64cc60f4/stable_baselines3-2.4.1.tar.gz", hash = "sha256:3bbf0e46b9aa4b1fd2696ff4c806ddb8ba719966ef0f71fba61f7a177e563c81", size = 212611, upload-time = "2025-01-07T13:22:42.455Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/96/04e1e987b5dd8ac0f192e74ad740fb5d72b4c9acd04f3ee13f5f9d6eacae/stable_baselines3-2.4.1-py3-none-any.whl", hash = "sha256:f74cde94a15c1d9d90343e73d790e1898b4c1cbb3f09eeeb580303d33f3fc4d6", size = 183963, upload-time = "2025-01-07T13:22:39.666Z" }, -] - [[package]] name = "stable-baselines3" version = "2.7.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version >= '3.13' and 'x86_64' in platform_machine) or (python_full_version >= '3.13' and sys_platform == 'darwin')", - "python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform != 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform != 'darwin') or (python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin')", - "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", - "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", -] dependencies = [ - { name = "cloudpickle", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "gymnasium", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "matplotlib", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')" }, + { name = "cloudpickle" }, + { name = "gymnasium" }, + { name = "matplotlib" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, - { name = "pandas", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "torch", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "pandas" }, + { name = "torch" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/cc/9a334071fae143bc7177e17a3191db83c1a4bf9038b09c4c5a34e427ca33/stable_baselines3-2.7.0.tar.gz", hash = "sha256:5258561e5becd15234274262cf09fcb9a082a73c2c67a85322f5652a05195ec4", size = 219012, upload-time = "2025-07-25T09:54:35.113Z" } wheels = [ From 845f7de230b82d7b33c91ccf069b20b0ebe697a6 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 12:52:05 +0200 Subject: [PATCH 18/98] Use default Qiskit settings for VF2Layout and add assertion for native gate check --- src/mqt/predictor/rl/actions.py | 4 ++++ tests/compilation/test_predictor_rl.py | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 7d0b856d3..0b88c90aa 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -576,6 +576,8 @@ def get_openqasm_gates() -> list[str]: VF2Layout( coupling_map=CouplingMap(device.build_coupling_map()), target=device, + call_limit=30000000, + max_trials=250000, ), ConditionalController( [ @@ -617,6 +619,8 @@ def get_openqasm_gates() -> list[str]: VF2Layout( coupling_map=CouplingMap(device.build_coupling_map()), target=device, + call_limit=30000000, + max_trials=250000, ), ConditionalController( [ diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index ac62c2fae..9e4c1ded2 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -19,6 +19,7 @@ from qiskit.circuit.library import CXGate from qiskit.qasm2 import dump from qiskit.transpiler import InstructionProperties, Target +from qiskit.transpiler.passes import GatesInBasis from mqt.predictor.rl import Predictor, rl_compile from mqt.predictor.rl.actions import ( @@ -89,8 +90,14 @@ def test_qcompile_with_newly_trained_models() -> None: ) qc_compiled, compilation_information = rl_compile(qc, device=device, figure_of_merit=figure_of_merit) + + check_nat_gates = GatesInBasis(basis_gates=device.operation_names) + check_nat_gates(qc_compiled) + only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] + assert qc_compiled.layout is not None assert compilation_information is not None + assert only_nat_gates, "Circuit should only contain native gates but was not detected as such" def test_qcompile_with_false_input() -> None: From 34189365b1ce9e3a7c24572e605a0b0c3c62c694 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 14:03:44 +0200 Subject: [PATCH 19/98] Debug --- noxfile.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index ee7980b69..ff94cf423 100644 --- a/noxfile.py +++ b/noxfile.py @@ -70,6 +70,7 @@ def _run_tests( "-v", *pytest_run_args, "--disable-warnings", + "--log-cli-level=INFO", *session.posargs, "--cov-config=pyproject.toml", env=env, @@ -140,6 +141,6 @@ def docs(session: nox.Session) -> None: "sphinx-autobuild" if serve else "sphinx-build", *shared_args, "-v", - "--disable-warnings", + "--log-cli-level=INFO--disable-warnings", env=env, ) From ae870cc37930cca4a69628babe4ef2b2ef9f9ff5 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 14:56:59 +0200 Subject: [PATCH 20/98] Fix missing argument --- .../test_estimated_hellinger_distance.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/hellinger_distance/test_estimated_hellinger_distance.py b/tests/hellinger_distance/test_estimated_hellinger_distance.py index d13151d51..6a92e94a4 100644 --- a/tests/hellinger_distance/test_estimated_hellinger_distance.py +++ b/tests/hellinger_distance/test_estimated_hellinger_distance.py @@ -220,17 +220,15 @@ def test_train_and_qcompile_with_hellinger_model(source_path: Path, target_path: if sys.platform == "win32": with pytest.warns(RuntimeWarning, match=re.escape("Timeout is not supported on Windows.")): ml_predictor.compile_training_circuits( - timeout=600, path_compiled_circuits=target_path, path_uncompiled_circuits=source_path, num_workers=1 + timeout=6000, path_compiled_circuits=target_path, path_uncompiled_circuits=source_path ) else: ml_predictor.compile_training_circuits( - timeout=600, path_compiled_circuits=target_path, path_uncompiled_circuits=source_path, num_workers=1 + timeout=6000, path_compiled_circuits=target_path, path_uncompiled_circuits=source_path ) # Generate training data from the compiled circuits - ml_predictor.generate_training_data( - path_uncompiled_circuits=source_path, path_compiled_circuits=target_path, num_workers=1 - ) + ml_predictor.generate_training_data(path_uncompiled_circuits=source_path, path_compiled_circuits=target_path) for file in [ "training_data_estimated_hellinger_distance.npy", From 861bc621a76647dd3694928e8bcbe7b249cf612f Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 15:38:57 +0200 Subject: [PATCH 21/98] Fix warning issues --- noxfile.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/noxfile.py b/noxfile.py index ff94cf423..cc639edc0 100644 --- a/noxfile.py +++ b/noxfile.py @@ -69,7 +69,6 @@ def _run_tests( "pytest", "-v", *pytest_run_args, - "--disable-warnings", "--log-cli-level=INFO", *session.posargs, "--cov-config=pyproject.toml", @@ -141,6 +140,6 @@ def docs(session: nox.Session) -> None: "sphinx-autobuild" if serve else "sphinx-build", *shared_args, "-v", - "--log-cli-level=INFO--disable-warnings", + "--log-cli-level=INFO", env=env, ) From fa989b6962b4109534d24ebdc7f9840ab5db54ab Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 17:49:39 +0200 Subject: [PATCH 22/98] Fix window runtime warning problem --- src/mqt/predictor/ml/predictor.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 3b844caf2..30f89fb65 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -12,6 +12,7 @@ import logging import sys +import warnings import zipfile from importlib import resources from pathlib import Path @@ -191,7 +192,13 @@ def _compile_all_circuits_devicewise( if (path_compiled_circuits / (target_filename + ".qasm")).exists(): continue try: - res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) + if sys.platform == "win32": + warnings.warn( + "Timeout is not supported on Windows. Running without timeout.", RuntimeWarning, stacklevel=2 + ) + res = rl_compile(qc, device, self.figure_of_merit, rl_pred) + else: + res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) if isinstance(res, tuple): compiled_qc = res[0] with Path(path_compiled_circuits / (target_filename + ".qasm")).open("w", encoding="utf-8") as f: @@ -205,7 +212,7 @@ def compile_training_circuits( self, path_uncompiled_circuits: Path | None = None, path_compiled_circuits: Path | None = None, - timeout: int = 6000, + timeout: int = 600, ) -> None: """Compiles all circuits in the given directory with the given timeout and saves them in the given directory. From 405bd398e76d345cb2b550b2ab13cbba41bb6e71 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 18:19:12 +0200 Subject: [PATCH 23/98] Fix window runtime warning problem --- src/mqt/predictor/ml/predictor.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 30f89fb65..0ca7b5a72 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -12,7 +12,6 @@ import logging import sys -import warnings import zipfile from importlib import resources from pathlib import Path @@ -192,13 +191,7 @@ def _compile_all_circuits_devicewise( if (path_compiled_circuits / (target_filename + ".qasm")).exists(): continue try: - if sys.platform == "win32": - warnings.warn( - "Timeout is not supported on Windows. Running without timeout.", RuntimeWarning, stacklevel=2 - ) - res = rl_compile(qc, device, self.figure_of_merit, rl_pred) - else: - res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) + res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) if isinstance(res, tuple): compiled_qc = res[0] with Path(path_compiled_circuits / (target_filename + ".qasm")).open("w", encoding="utf-8") as f: @@ -233,12 +226,18 @@ def compile_training_circuits( with zipfile.ZipFile(str(path_zip), "r") as zip_ref: zip_ref.extractall(path_uncompiled_circuits) - Parallel(n_jobs=1, verbose=100)( - delayed(self._compile_all_circuits_devicewise)( - device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level + if sys.platform != "win32": + Parallel(n_jobs=1, verbose=100)( + delayed(self._compile_all_circuits_devicewise)( + device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level + ) + for device in self.devices ) - for device in self.devices - ) + else: + for device in self.devices: + self._compile_all_circuits_devicewise( + device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level + ) def generate_training_data( self, From 7b2f321bc3a9aac5ea90144c34fe79ce649db41c Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 18:34:52 +0200 Subject: [PATCH 24/98] Add time limit for VF2PostLayout --- src/mqt/predictor/rl/actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 0b88c90aa..005948d25 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -395,7 +395,7 @@ def get_openqasm_gates() -> list[str]: "VF2PostLayout", CompilationOrigin.QISKIT, PassType.FINAL_OPT, - transpile_pass=lambda device: VF2PostLayout(target=device), + transpile_pass=lambda device: VF2PostLayout(target=device, time_limit=100), ) ) From b67d0a601783d4e7d7944c089825cf69c62bafc1 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 7 Aug 2025 19:06:13 +0200 Subject: [PATCH 25/98] Fix windows runtime warning problem Fix windows runtime warning problem Fix windows runtime warning issue --- src/mqt/predictor/ml/predictor.py | 5 ++++- .../test_estimated_hellinger_distance.py | 13 +++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 0ca7b5a72..155c09e04 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -191,7 +191,10 @@ def _compile_all_circuits_devicewise( if (path_compiled_circuits / (target_filename + ".qasm")).exists(): continue try: - res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) + if sys.platform == "win32": + res = rl_compile(qc, device, self.figure_of_merit, rl_pred) + else: + res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) if isinstance(res, tuple): compiled_qc = res[0] with Path(path_compiled_circuits / (target_filename + ".qasm")).open("w", encoding="utf-8") as f: diff --git a/tests/hellinger_distance/test_estimated_hellinger_distance.py b/tests/hellinger_distance/test_estimated_hellinger_distance.py index 6a92e94a4..14d2ac3ea 100644 --- a/tests/hellinger_distance/test_estimated_hellinger_distance.py +++ b/tests/hellinger_distance/test_estimated_hellinger_distance.py @@ -11,7 +11,6 @@ from __future__ import annotations import re -import sys import warnings from pathlib import Path from typing import TYPE_CHECKING @@ -217,15 +216,9 @@ def test_train_and_qcompile_with_hellinger_model(source_path: Path, target_path: dump(qc, f) # Generate compiled circuits (using trained RL model) - if sys.platform == "win32": - with pytest.warns(RuntimeWarning, match=re.escape("Timeout is not supported on Windows.")): - ml_predictor.compile_training_circuits( - timeout=6000, path_compiled_circuits=target_path, path_uncompiled_circuits=source_path - ) - else: - ml_predictor.compile_training_circuits( - timeout=6000, path_compiled_circuits=target_path, path_uncompiled_circuits=source_path - ) + ml_predictor.compile_training_circuits( + timeout=6000, path_compiled_circuits=target_path, path_uncompiled_circuits=source_path + ) # Generate training data from the compiled circuits ml_predictor.generate_training_data(path_uncompiled_circuits=source_path, path_compiled_circuits=target_path) From bf7c9ee42d36ef0aefeb33404aab5b46f11d79b1 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 29 Aug 2025 16:32:37 +0200 Subject: [PATCH 26/98] Add new actions --- noxfile.py | 4 - src/mqt/predictor/reward.py | 7 +- src/mqt/predictor/rl/actions.py | 412 ++++++++++--------------- src/mqt/predictor/rl/helper.py | 89 +----- src/mqt/predictor/rl/predictor.py | 20 +- src/mqt/predictor/rl/predictorenv.py | 119 ++++--- tests/compilation/test_predictor_rl.py | 54 ++-- 7 files changed, 281 insertions(+), 424 deletions(-) diff --git a/noxfile.py b/noxfile.py index cc639edc0..8a7e78ddc 100644 --- a/noxfile.py +++ b/noxfile.py @@ -67,9 +67,7 @@ def _run_tests( "test", *install_args, "pytest", - "-v", *pytest_run_args, - "--log-cli-level=INFO", *session.posargs, "--cov-config=pyproject.toml", env=env, @@ -139,7 +137,5 @@ def docs(session: nox.Session) -> None: "--frozen", "sphinx-autobuild" if serve else "sphinx-build", *shared_args, - "-v", - "--log-cli-level=INFO", env=env, ) diff --git a/src/mqt/predictor/reward.py b/src/mqt/predictor/reward.py index 86632873d..38be96bce 100644 --- a/src/mqt/predictor/reward.py +++ b/src/mqt/predictor/reward.py @@ -67,7 +67,12 @@ def expected_fidelity(qc: QuantumCircuit, device: Target, precision: int = 10) - specific_fidelity = 1 - device[gate_type][first_qubit_idx,].error else: second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) - specific_fidelity = 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error + try: + specific_fidelity = 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error + except KeyError: + # try flipped orientation + specific_fidelity = 1 - device[gate_type][second_qubit_idx, first_qubit_idx].error + res *= specific_fidelity diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 005948d25..a8975426f 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -50,6 +50,7 @@ from qiskit.transpiler import CouplingMap from qiskit.transpiler.passes import ( ApplyLayout, + BasicSwap, BasisTranslator, Collect2qBlocks, CollectCliffords, @@ -132,6 +133,7 @@ class Action: ] ) stochastic: bool | None = False + preserve: bool | None = False @dataclass @@ -233,7 +235,8 @@ def get_openqasm_gates() -> list[str]: "Optimize1qGatesDecomposition", CompilationOrigin.QISKIT, PassType.OPT, - [Optimize1qGatesDecomposition(basis=get_openqasm_gates())], + preserve=True, + transpile_pass= lambda device: [Optimize1qGatesDecomposition(basis=device.operation_names)], ) ) @@ -243,6 +246,7 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.QISKIT, PassType.OPT, [CommutativeCancellation()], + preserve=True, ) ) @@ -252,6 +256,7 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.QISKIT, PassType.OPT, [CommutativeInverseCancellation()], + preserve=True, ) ) @@ -261,6 +266,7 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.QISKIT, PassType.OPT, [RemoveDiagonalGatesBeforeMeasure()], + preserve=True, ) ) @@ -285,6 +291,7 @@ def get_openqasm_gates() -> list[str]: (SXGate(), SXdgGate()), ]) ], + preserve=True, ) ) @@ -307,6 +314,7 @@ def get_openqasm_gates() -> list[str]: ConsolidateBlocks(basis_gates=native_gate), UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), ], + preserve=True, ) ) @@ -346,56 +354,70 @@ def get_openqasm_gates() -> list[str]: ) ) -register_action( - DeviceDependentAction( - "QiskitO3", - CompilationOrigin.QISKIT, - PassType.OPT, - transpile_pass=lambda native_gate, coupling_map: [ - Collect2qBlocks(), - ConsolidateBlocks(basis_gates=native_gate), - UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), - Optimize1qGatesDecomposition(basis=native_gate), - CommutativeCancellation(basis_gates=native_gate), - GatesInBasis(native_gate), - ConditionalController( - common.generate_translation_passmanager( - target=None, basis_gates=native_gate, coupling_map=coupling_map - ).to_flow_controller(), - condition=lambda property_set: not property_set["all_gates_in_basis"], - ), - Depth(recurse=True), - FixedPoint("depth"), - Size(recurse=True), - FixedPoint("size"), - MinimumPoint(["depth", "size"], "optimization_loop"), - ], - do_while=lambda property_set: not property_set["optimization_loop_minimum_point"], - ) -) +# register_action( +# DeviceDependentAction( +# "QiskitO3", +# CompilationOrigin.QISKIT, +# PassType.OPT, +# transpile_pass=lambda native_gate, coupling_map: [ +# Collect2qBlocks(), +# ConsolidateBlocks(basis_gates=native_gate), +# UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), +# Optimize1qGatesDecomposition(basis=native_gate), +# CommutativeCancellation(basis_gates=native_gate), +# GatesInBasis(native_gate), +# ConditionalController( +# common.generate_translation_passmanager( +# target=None, basis_gates=native_gate, coupling_map=coupling_map +# ).to_flow_controller(), +# condition=lambda property_set: not property_set["all_gates_in_basis"], +# ), +# Depth(recurse=True), +# FixedPoint("depth"), +# Size(recurse=True), +# FixedPoint("size"), +# MinimumPoint(["depth", "size"], "optimization_loop"), +# ], +# do_while=lambda property_set: not property_set["optimization_loop_minimum_point"], +# ) +# ) + +# register_action( +# DeviceDependentAction( +# "BQSKitO2", +# CompilationOrigin.BQSKIT, +# PassType.OPT, +# transpile_pass=lambda circuit: bqskit_compile( +# circuit, +# optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, +# synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, +# max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, +# seed=10, +# num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, +# ), +# ) +# ) register_action( DeviceDependentAction( - "BQSKitO2", - CompilationOrigin.BQSKIT, - PassType.OPT, - transpile_pass=lambda circuit: bqskit_compile( - circuit, - optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, - synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, - max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, - seed=10, - num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, - ), + "VF2PostLayout", + CompilationOrigin.QISKIT, + PassType.FINAL_OPT, + transpile_pass=lambda device: VF2PostLayout(target=device, call_limit=30000000, max_trials=250000), ) ) register_action( DeviceDependentAction( - "VF2PostLayout", + "TrivialLayout", CompilationOrigin.QISKIT, - PassType.FINAL_OPT, - transpile_pass=lambda device: VF2PostLayout(target=device, time_limit=100), + PassType.LAYOUT, + transpile_pass=lambda device: [ + TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + ], ) ) @@ -419,7 +441,7 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.QISKIT, PassType.LAYOUT, transpile_pass=lambda device: [ - VF2Layout(target=device), + VF2Layout(target=device, call_limit=30000000, max_trials=250000), ConditionalController( [ FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), @@ -433,6 +455,23 @@ def get_openqasm_gates() -> list[str]: ) ) +# register_action( +# DeviceDependentAction( +# "SabreLayout", +# CompilationOrigin.QISKIT, +# PassType.LAYOUT, +# transpile_pass=lambda device: [ +# SabreLayout( +# coupling_map=CouplingMap(device.build_coupling_map()), +# skip_routing=True, +# ), +# FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), +# EnlargeWithAncilla(), +# ApplyLayout(), +# ], +# ) +# ) + register_action( DeviceDependentAction( "RoutingPass", @@ -447,205 +486,96 @@ def get_openqasm_gates() -> list[str]: register_action( DeviceDependentAction( - "SabreMapping", + "BasicSwap", CompilationOrigin.QISKIT, - PassType.MAPPING, - stochastic=True, - # Qiskit O3 by default uses (max_iterations, layout_trials, swap_trials) = (4, 20, 20) - transpile_pass=lambda device, max_iteration=(20, 20): [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=False, - layout_trials=max_iteration[0], - swap_trials=max_iteration[1], - max_iterations=4, - seed=None, - ), - ], - ) -) - -register_action( - DeviceDependentAction( - "SabreLayout+AIRouting", - CompilationOrigin.QISKIT, - PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device, max_iteration=(20, 20): [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=True, - layout_trials=max_iteration[0], - swap_trials=max_iteration[1], - max_iterations=4, - seed=None, - ), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="improve"), - ], + PassType.ROUTING, + transpile_pass=lambda device: [BasicSwap(coupling_map=CouplingMap(device.build_coupling_map()))], ) ) +# register_action( +# DeviceDependentAction( +# "SabreSwap", +# CompilationOrigin.QISKIT, +# PassType.ROUTING, +# stochastic=True, +# transpile_pass=lambda device: [ +# SabreSwap(coupling_map=CouplingMap(device.build_coupling_map()), heuristic="decay") +# ], +# ) +# ) + +# register_action( +# DeviceDependentAction( +# "AIRouting", +# CompilationOrigin.QISKIT, +# PassType.ROUTING, +# stochastic=True, +# transpile_pass=lambda device: [ +# SafeAIRouting( +# coupling_map=device.build_coupling_map(), +# optimization_level=3, +# layout_mode="improve", +# local_mode=True +# ) +# ], +# ) +# ) register_action( DeviceDependentAction( - "AIRouting", + "SabreMapping", CompilationOrigin.QISKIT, PassType.MAPPING, stochastic=True, + # Qiskit O3 by default uses (max_iterations, layout_trials, swap_trials) = (4, 20, 20) transpile_pass=lambda device: [ - ### Requires a initial layout, but "optimize" mode overwrites it - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), - ], - ) -) - -register_action( - DeviceDependentAction( - "BQSKitMapping", - CompilationOrigin.BQSKIT, - PassType.MAPPING, - transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( - bqskit_circuit, - model=MachineModel( - num_qudits=device.num_qubits, - gate_set=get_bqskit_native_gates(device), - coupling_graph=[(elem[0], elem[1]) for elem in device.build_coupling_map()], - ), - with_mapping=True, - optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, - synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, - max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, - seed=10, - num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, - ), - ) -) - - -register_action( - DeviceDependentAction( - name="DenseLayout+SabreSwap", - origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device, max_iteration=(20, 20): [ - DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SabreSwap( - coupling_map=CouplingMap(device.build_coupling_map()), - heuristic="decay", - trials=max_iteration[1], - seed=None, - ), - ], - ) -) - -register_action( - DeviceDependentAction( - name="DenseLayout+AIRouting", - origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device: [ - DenseLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="improve"), - ], - ) -) - - -register_action( - DeviceDependentAction( - name="VF2Layout+SabreSwap", - origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device, max_iteration=(20, 20): [ - VF2Layout( - coupling_map=CouplingMap(device.build_coupling_map()), - target=device, - call_limit=30000000, - max_trials=250000, - ), - ConditionalController( - [ - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - == VF2LayoutStopReason.SOLUTION_FOUND, - ), - ConditionalController( - [ - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - # Run if VF2Layout did not find a solution - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - != VF2LayoutStopReason.SOLUTION_FOUND, - ), - SabreSwap( + SabreLayout( coupling_map=CouplingMap(device.build_coupling_map()), - heuristic="decay", - trials=max_iteration[1], + skip_routing=False, seed=None, ), ], ) ) -register_action( - DeviceDependentAction( - name="VF2Layout+AIRouting", - origin=CompilationOrigin.QISKIT, - pass_type=PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device: [ - VF2Layout( - coupling_map=CouplingMap(device.build_coupling_map()), - target=device, - call_limit=30000000, - max_trials=250000, - ), - ConditionalController( - [ - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - == VF2LayoutStopReason.SOLUTION_FOUND, - ), - ConditionalController( - [ - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], - # Run if VF2Layout did not find a solution - condition=lambda property_set: property_set["VF2Layout_stop_reason"] - != VF2LayoutStopReason.SOLUTION_FOUND, - ), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="improve"), - ], - ) -) +# register_action( +# DeviceDependentAction( +# "AIRouting_opt", +# CompilationOrigin.QISKIT, +# PassType.MAPPING, +# stochastic=True, +# transpile_pass=lambda device: [ +# ### Requires a initial layout, but "optimize" mode overwrites it +# TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), +# FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), +# EnlargeWithAncilla(), +# ApplyLayout(), +# SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), +# ], +# ) +# ) + +# register_action( +# DeviceDependentAction( +# "BQSKitMapping", +# CompilationOrigin.BQSKIT, +# PassType.MAPPING, +# transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( +# bqskit_circuit, +# model=MachineModel( +# num_qudits=device.num_qubits, +# gate_set=get_bqskit_native_gates(device), +# coupling_graph=[(elem[0], elem[1]) for elem in device.build_coupling_map()], +# ), +# with_mapping=True, +# optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, +# synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, +# max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, +# seed=10, +# num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, +# ), +# ) +# ) register_action( DeviceDependentAction( @@ -658,22 +588,22 @@ def get_openqasm_gates() -> list[str]: ) ) -register_action( - DeviceDependentAction( - "BQSKitSynthesis", - CompilationOrigin.BQSKIT, - PassType.SYNTHESIS, - transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( - bqskit_circuit, - model=MachineModel(bqskit_circuit.num_qudits, gate_set=get_bqskit_native_gates(device)), - optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, - synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, - max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, - seed=10, - num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, - ), - ) -) +# register_action( +# DeviceDependentAction( +# "BQSKitSynthesis", +# CompilationOrigin.BQSKIT, +# PassType.SYNTHESIS, +# transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( +# bqskit_circuit, +# model=MachineModel(bqskit_circuit.num_qudits, gate_set=get_bqskit_native_gates(device)), +# optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, +# synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, +# max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, +# seed=10, +# num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, +# ), +# ) +# ) register_action( DeviceIndependentAction( diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 558ba262f..f23ca3320 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -12,109 +12,22 @@ import logging from pathlib import Path -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING import numpy as np from qiskit import QuantumCircuit -from qiskit.transpiler import PassManager, Target from mqt.predictor.utils import calc_supermarq_features if TYPE_CHECKING: - from collections.abc import Callable - from numpy.random import Generator from numpy.typing import NDArray - from mqt.predictor.rl.actions import Action - - # from mqt.predictor.rl.actions import Action - import zipfile from importlib import resources logger = logging.getLogger("mqt-predictor") - -def best_of_n_passmanager( - action: Action, - device: Target, - qc: QuantumCircuit, - max_iteration: tuple[int, int] = (20, 20), - metric_fn: Callable[[QuantumCircuit], float] | None = None, -) -> tuple[QuantumCircuit, dict[str, Any]]: - """Runs the given transpile_pass multiple times and keeps the best result. - - Args: - action: The action dictionary with a 'transpile_pass' key - (lambda device -> [passes]). - device: The target backend or device. - qc: The input quantum circuit. - max_iteration: A tuple (layout_trials, routing_trials) specifying - how many times to try. - metric_fn: Optional function to score circuits; defaults to circuit depth. - - Returns: - A tuple containing the best transpiled circuit and its corresponding - property set. - """ - best_val = None - best_result = None - best_property_set = None - - if callable(action.transpile_pass): - try: - if action.name == "SabreLayout+AIRouting": - all_passes = action.transpile_pass(device, max_iteration) - else: - all_passes = action.transpile_pass(device) - except TypeError as e: - msg = f"Error calling transpile_pass for {action.name}: {e}" - raise ValueError(msg) from e - else: - all_passes = action.transpile_pass - - if not isinstance(all_passes, list): - msg = f"Expected list of passes, got {type(all_passes)}" - raise TypeError(msg) - - layout_passes = all_passes[:-1] - routing_pass = all_passes[-1:] - - # Run layout once - layout_pm = PassManager(layout_passes) - try: - layouted_qc = layout_pm.run(qc) - layout_props = dict(layout_pm.property_set) - except Exception: - return qc, {} - - # Run routing multiple times and optimize for the given metric - for i in range(max_iteration[1]): - pm = PassManager(routing_pass) - pm.property_set.update(layout_props) - try: - out_circ = pm.run(layouted_qc) - prop_set = dict(pm.property_set) - - val = metric_fn(out_circ) if metric_fn else out_circ.depth() - if best_val is None or val < best_val: - best_val = val - best_result = out_circ - best_property_set = prop_set - if best_val == 0: - break - except Exception as e: - print(f"[Routing] Trial {i + 1} failed: {e}") - continue - if best_result is not None: - if best_property_set is None: - best_property_set = {} - return best_result, best_property_set - print("All mapping attempts failed; returning original circuit.") - return qc, {} - - def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generator) -> tuple[QuantumCircuit, str]: """Returns a random quantum circuit from the training circuits folder. diff --git a/src/mqt/predictor/rl/predictor.py b/src/mqt/predictor/rl/predictor.py index 3ffe07733..558e43021 100644 --- a/src/mqt/predictor/rl/predictor.py +++ b/src/mqt/predictor/rl/predictor.py @@ -51,7 +51,7 @@ def __init__( def compile_as_predicted( self, qc: QuantumCircuit, - ) -> tuple[QuantumCircuit, list[str]]: + ) -> tuple[QuantumCircuit, float, list[str]]: """Compiles a given quantum circuit such that the given figure of merit is maximized by using the respectively trained optimized compiler. Arguments: @@ -76,10 +76,19 @@ def compile_as_predicted( action = int(action) action_item = self.env.action_set[action] used_compilation_passes.append(action_item.name) - obs, _reward_val, terminated, truncated, _info = self.env.step(action) + # if action_item.name == "terminate": + # swap_count = self.env.state.count_ops().get("swap", 0) + # depth = self.env.state.depth() + # critical_depth = reward.crit_depth(self.env.state) + # esp= reward.estimated_success_probability(self.env.state, self.env.device) + obs, reward_val, terminated, truncated, _info = self.env.step(action) if not self.env.error_occurred: - return self.env.state, used_compilation_passes + return ( + self.env.state, + reward_val, + used_compilation_passes, + ) # swap_count, depth, critical_depth, esp msg = "Error occurred during compilation." raise RuntimeError(msg) @@ -110,7 +119,7 @@ def train_model( n_steps = 2048 n_epochs = 10 batch_size = 64 - progress_bar = True + progress_bar = False logger.debug("Start training for: " + self.figure_of_merit + " on " + self.device_name) model = MaskablePPO( @@ -181,4 +190,5 @@ def rl_compile( else: predictor = predictor_singleton - return predictor.compile_as_predicted(qc) + qc, _, info = predictor.compile_as_predicted(qc) + return qc, info diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index a3cbae20b..a7239c232 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -42,6 +42,7 @@ from qiskit.passmanager.flow_controllers import DoWhileController from qiskit.transpiler import CouplingMap, PassManager, Target, TranspileLayout from qiskit.transpiler.passes import CheckMap, GatesInBasis +from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from mqt.predictor.hellinger import get_hellinger_model_path from mqt.predictor.reward import ( @@ -60,7 +61,6 @@ get_openqasm_gates, ) from mqt.predictor.rl.helper import ( - best_of_n_passmanager, create_feature_dict, get_path_training_circuits, get_state_sample, @@ -104,6 +104,7 @@ def __init__( self.actions_mapping_indices = [] self.actions_opt_indices = [] self.actions_final_optimization_indices = [] + self.actions_preserving_indices = [] self.used_actions: list[str] = [] self.device = device @@ -123,6 +124,8 @@ def __init__( for elem in action_dict[PassType.OPT]: self.action_set[index] = elem self.actions_opt_indices.append(index) + if getattr(elem, "preserve", False): + self.actions_preserving_indices.append(index) index += 1 for elem in action_dict[PassType.LAYOUT]: self.action_set[index] = elem @@ -209,6 +212,7 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any if action == self.action_terminate_index: reward_val = self.calculate_reward() + logger.info(f"Fidelity: {reward_val}") done = True else: reward_val = 0 @@ -334,83 +338,57 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: return self._apply_bqskit_action(action, action_index) msg = f"Origin {action.origin} not supported." raise ValueError(msg) - + def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: - if getattr(action, "stochastic", False): - - def metric_fn(circ: QuantumCircuit) -> float: - return float(circ.count_ops().get("swap", 0)) - - max_iteration = self.max_iter - if "Sabre" in action.name and "AIRouting" not in action.name: - # Internal trials for Sabre - assert callable(action.transpile_pass) - transpile_pass = action.transpile_pass(self.device, max_iteration) - pm = PassManager(transpile_pass) - altered_qc = pm.run(self.state) - pm_property_set = dict(pm.property_set) - elif "AIRouting" in action.name: - # Run AIRouting in custom loop - altered_qc, pm_property_set = best_of_n_passmanager( - action, - self.device, - self.state, - max_iteration=max_iteration, - metric_fn=metric_fn, - ) + if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): + passes = action.transpile_pass( + self.device.operation_names, + CouplingMap(self.device.build_coupling_map()) if self.layout else None, + ) + if action.name == "QiskitO3": + pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) else: - msg = f"Unknown stochastic action: {action.name}" - raise ValueError(msg) - + pm = PassManager(passes) else: - if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): - passes = action.transpile_pass( - self.device.operation_names, - CouplingMap(self.device.build_coupling_map()) if self.layout else None, - ) - if action.name == "QiskitO3": - pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) - else: - pm = PassManager(passes) - altered_qc = pm.run(self.state) - pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} - else: - transpile_pass = ( - action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass - ) - pm = PassManager(transpile_pass) - altered_qc = pm.run(self.state) - pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + transpile_pass = ( + action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass + ) + pm = PassManager(transpile_pass) - if action_index in (self.actions_mapping_indices + self.actions_final_optimization_indices): - altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) + altered_qc = pm.run(self.state) + + if action_index in ( + self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices + ): + altered_qc = self._handle_qiskit_layout_postprocessing(action, pm, altered_qc) + + elif action_index in self.actions_routing_indices and self.layout: + self.layout.final_layout = pm.property_set["final_layout"] return altered_qc def _handle_qiskit_layout_postprocessing( - self, - action: Action, - pm_property_set: dict[str, Any], - altered_qc: QuantumCircuit, + self, action: Action, pm: PassManager, altered_qc: QuantumCircuit ) -> QuantumCircuit: if action.name == "VF2PostLayout": - assert pm_property_set["VF2PostLayout_stop_reason"] is not None - post_layout = pm_property_set.get("post_layout") + assert pm.property_set["VF2PostLayout_stop_reason"] is not None + post_layout = pm.property_set["post_layout"] if post_layout: altered_qc, _ = postprocess_vf2postlayout(altered_qc, post_layout, self.layout) + elif action.name == "VF2Layout": + if pm.property_set["VF2Layout_stop_reason"] == VF2LayoutStopReason.SOLUTION_FOUND: + assert pm.property_set["layout"] + else: + assert pm.property_set["layout"] - layout = pm_property_set.get("layout") - if layout: + if pm.property_set["layout"]: self.layout = TranspileLayout( - initial_layout=layout, - input_qubit_mapping=pm_property_set["original_qubit_indices"], - final_layout=pm_property_set["final_layout"], + initial_layout=pm.property_set["layout"], + input_qubit_mapping=pm.property_set["original_qubit_indices"], + final_layout=pm.property_set["final_layout"], _output_qubit_list=altered_qc.qubits, _input_qubit_count=self.num_qubits_uncompiled_circuit, ) - - if self.layout is not None and pm_property_set.get("final_layout"): - self.layout.final_layout = pm_property_set["final_layout"] return altered_qc def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircuit: @@ -479,11 +457,20 @@ def determine_valid_actions_for_state(self) -> list[int]: mapped = check_mapping.property_set["is_swap_mapped"] if not only_nat_gates: # not native gates yet - return self.actions_synthesis_indices + self.actions_opt_indices + if not mapped: + return self.actions_synthesis_indices + self.actions_opt_indices + else: + return self.actions_synthesis_indices + self.actions_preserving_indices if mapped and self.layout is not None: # The circuit is correctly mapped return [self.action_terminate_index, *self.actions_opt_indices, *self.actions_final_optimization_indices] - # The circuit is not mapped yet - # Or the circuit was mapped but some optimization actions change its structure and the circuit is again unmapped - # In this case, re-do mapping completely as the previous layout is not optimal on the new structure - return self.actions_mapping_indices + self.actions_opt_indices + + if self.layout is not None: + # The circuit is not yet mapped but a layout is set. + return self.actions_routing_indices + else: + # The circuit already fulfils coupling map but no layout is assigned, could explore better layout options + if mapped: + return self.actions_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices + else: + return self.actions_opt_indices + self.actions_layout_indices + self.actions_mapping_indices diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index 9e4c1ded2..d90423ab1 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -14,6 +14,7 @@ from pathlib import Path import pytest +from qiskit_ibm_runtime import QiskitRuntimeService from mqt.bench import BenchmarkLevel, get_benchmark from mqt.bench.targets import get_device from qiskit.circuit.library import CXGate @@ -30,7 +31,7 @@ register_action, remove_action, ) -from mqt.predictor.rl.helper import create_feature_dict, get_path_trained_model +from mqt.predictor.rl.helper import create_feature_dict def test_predictor_env_reset_from_string() -> None: @@ -68,30 +69,45 @@ def test_qcompile_with_newly_trained_models() -> None: Important: Those trained models are used in later tests and must not be deleted. To test ESP as well, training must be done with a device that provides all relevant information (i.e. T1, T2 and gate times). """ + # figure_of_merit = "expected_fidelity" + # device = get_device("ibm_eagle_127") + # qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 20) + # predictor = Predictor(figure_of_merit=figure_of_merit, device=device) + + # model_name = "model_" + figure_of_merit + "_" + device.description + # model_path = Path(get_path_trained_model() / (model_name + ".zip")) + # if not model_path.exists(): + # with pytest.raises( + # FileNotFoundError, + # match=re.escape( + # "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." + # ), + # ): + # rl_compile(qc, device=device, figure_of_merit=figure_of_merit) figure_of_merit = "expected_fidelity" - device = get_device("ibm_falcon_127") - qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 3) - predictor = Predictor(figure_of_merit=figure_of_merit, device=device) - - model_name = "model_" + figure_of_merit + "_" + device.description - model_path = Path(get_path_trained_model() / (model_name + ".zip")) - if not model_path.exists(): - with pytest.raises( - FileNotFoundError, - match=re.escape( - "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." - ), - ): - rl_compile(qc, device=device, figure_of_merit=figure_of_merit) + + api_token = "f--aKMqeiWLjkaazIlxEFVKxJ5cVgAqhxbP9K87iPbP2" + available_devices = ["ibm_brisbane", "ibm_torino"] + device = available_devices[0] + + service = QiskitRuntimeService(channel="ibm_cloud", token=api_token) + backend = service.backend(device) + backend.target.description = "ibm_brisbane" # HACK + print(backend.target) + predictor = Predictor(figure_of_merit=figure_of_merit, device=backend.target) + qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 17, target=backend.target) predictor.train_model( - timesteps=100, - test=True, + timesteps=100000, + test=False, ) - qc_compiled, compilation_information = rl_compile(qc, device=device, figure_of_merit=figure_of_merit) + qc_compiled, reward, compilation_information = rl_compile( + qc, device=backend.target, figure_of_merit=figure_of_merit + ) + print(f"Fidelity: {reward}") - check_nat_gates = GatesInBasis(basis_gates=device.operation_names) + check_nat_gates = GatesInBasis(basis_gates=backend.target.operation_names) check_nat_gates(qc_compiled) only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] From 6d2733f231599d811b295d2e3f13cc79467496c6 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 29 Aug 2025 16:39:30 +0200 Subject: [PATCH 27/98] Add new actions --- tests/compilation/test_predictor_rl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index d90423ab1..43211af0a 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -14,13 +14,13 @@ from pathlib import Path import pytest -from qiskit_ibm_runtime import QiskitRuntimeService from mqt.bench import BenchmarkLevel, get_benchmark from mqt.bench.targets import get_device from qiskit.circuit.library import CXGate from qiskit.qasm2 import dump from qiskit.transpiler import InstructionProperties, Target from qiskit.transpiler.passes import GatesInBasis +from qiskit_ibm_runtime import QiskitRuntimeService from mqt.predictor.rl import Predictor, rl_compile from mqt.predictor.rl.actions import ( @@ -86,7 +86,7 @@ def test_qcompile_with_newly_trained_models() -> None: # rl_compile(qc, device=device, figure_of_merit=figure_of_merit) figure_of_merit = "expected_fidelity" - api_token = "f--aKMqeiWLjkaazIlxEFVKxJ5cVgAqhxbP9K87iPbP2" + api_token = "" available_devices = ["ibm_brisbane", "ibm_torino"] device = available_devices[0] From 878185af1099cfc79b03542da3c2548443381981 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 3 Sep 2025 13:21:10 +0200 Subject: [PATCH 28/98] Add evaluation code for baseline model --- src/mqt/predictor/reward.py | 16 ++++-- src/mqt/predictor/rl/actions.py | 58 ++++++++++--------- src/mqt/predictor/rl/helper.py | 9 ++- src/mqt/predictor/rl/predictor.py | 72 +++++++++++++++++------- src/mqt/predictor/rl/predictorenv.py | 77 ++++++++++++++++++++------ tests/compilation/test_predictor_rl.py | 59 ++++++++++++++++++-- 6 files changed, 216 insertions(+), 75 deletions(-) diff --git a/src/mqt/predictor/reward.py b/src/mqt/predictor/reward.py index 38be96bce..3cc726eed 100644 --- a/src/mqt/predictor/reward.py +++ b/src/mqt/predictor/reward.py @@ -73,7 +73,6 @@ def expected_fidelity(qc: QuantumCircuit, device: Target, precision: int = 10) - # try flipped orientation specific_fidelity = 1 - device[gate_type][second_qubit_idx, first_qubit_idx].error - res *= specific_fidelity return float(np.round(res, precision).item()) @@ -146,7 +145,10 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: else: # multi-qubit gate second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) active_qubits.add(second_qubit_idx) - duration = device[gate_type][first_qubit_idx, second_qubit_idx].duration + try: + duration = device[gate_type][first_qubit_idx, second_qubit_idx].duration + except KeyError: + duration = device[gate_type][second_qubit_idx, first_qubit_idx].duration op_times.append((gate_type, [first_qubit_idx, second_qubit_idx], duration, "s")) exec_time_per_qubit[first_qubit_idx] += duration exec_time_per_qubit[second_qubit_idx] += duration @@ -187,6 +189,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: res = 1.0 for instr in scheduled_circ.data: + instruction = instr.operation qargs = instr.qubits gate_type = instruction.name @@ -199,6 +202,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: if len(qargs) == 1: if gate_type == "measure": + res *= 1 - device[gate_type][first_qubit_idx,].error continue if gate_type == "delay": @@ -207,16 +211,18 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: # only consider active qubits if first_qubit_idx not in active_qubits: continue - + + dt=5e-10 # discrete time unit used in duration res *= np.exp( - -instruction.duration + -instruction.duration * dt / min(device.qubit_properties[first_qubit_idx].t1, device.qubit_properties[first_qubit_idx].t2) ) continue res *= 1 - device[gate_type][first_qubit_idx,].error + else: second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) - res *= 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error + res *= 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error if qiskit_version >= "2.0.0": for i in range(device.num_qubits): diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index a8975426f..8c73f6b70 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -10,14 +10,11 @@ from __future__ import annotations -import os from collections import defaultdict from dataclasses import dataclass from enum import Enum from typing import TYPE_CHECKING, Any -from bqskit import MachineModel -from bqskit import compile as bqskit_compile from pytket.architecture import Architecture from pytket.passes import ( CliffordSimp, @@ -58,31 +55,23 @@ CommutativeInverseCancellation, ConsolidateBlocks, DenseLayout, - Depth, EnlargeWithAncilla, - FixedPoint, FullAncillaAllocation, - GatesInBasis, InverseCancellation, - MinimumPoint, Optimize1qGatesDecomposition, OptimizeCliffords, RemoveDiagonalGatesBeforeMeasure, SabreLayout, - SabreSwap, - Size, TrivialLayout, UnitarySynthesis, VF2Layout, VF2PostLayout, ) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason -from qiskit.transpiler.preset_passmanagers import common from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.rl.parsing import ( PreProcessTKETRoutingAfterQiskitLayout, - get_bqskit_native_gates, ) if TYPE_CHECKING: @@ -230,13 +219,22 @@ def get_openqasm_gates() -> list[str]: ] +# register_action( +# DeviceIndependentAction( +# "Optimize1qGatesDecomposition", +# CompilationOrigin.QISKIT, +# PassType.OPT, +# preserve=True, +# transpile_pass=lambda device: [Optimize1qGatesDecomposition(basis=device.operation_names)], +# ) +# ) + register_action( DeviceIndependentAction( "Optimize1qGatesDecomposition", CompilationOrigin.QISKIT, PassType.OPT, - preserve=True, - transpile_pass= lambda device: [Optimize1qGatesDecomposition(basis=device.operation_names)], + [Optimize1qGatesDecomposition()], ) ) @@ -304,17 +302,26 @@ def get_openqasm_gates() -> list[str]: ) ) +# register_action( +# DeviceDependentAction( +# "Opt2qBlocks", +# CompilationOrigin.QISKIT, +# PassType.OPT, +# transpile_pass=lambda native_gate, coupling_map: [ +# Collect2qBlocks(), +# ConsolidateBlocks(basis_gates=native_gate), +# UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), +# ], +# preserve=True, +# ) +# ) + register_action( - DeviceDependentAction( + DeviceIndependentAction( "Opt2qBlocks", CompilationOrigin.QISKIT, PassType.OPT, - transpile_pass=lambda native_gate, coupling_map: [ - Collect2qBlocks(), - ConsolidateBlocks(basis_gates=native_gate), - UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), - ], - preserve=True, + [Collect2qBlocks(), ConsolidateBlocks(), UnitarySynthesis()], ) ) @@ -403,7 +410,7 @@ def get_openqasm_gates() -> list[str]: "VF2PostLayout", CompilationOrigin.QISKIT, PassType.FINAL_OPT, - transpile_pass=lambda device: VF2PostLayout(target=device, call_limit=30000000, max_trials=250000), + transpile_pass=lambda device: VF2PostLayout(target=device), ) ) @@ -441,7 +448,7 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.QISKIT, PassType.LAYOUT, transpile_pass=lambda device: [ - VF2Layout(target=device, call_limit=30000000, max_trials=250000), + VF2Layout(target=device), ConditionalController( [ FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), @@ -462,7 +469,7 @@ def get_openqasm_gates() -> list[str]: # PassType.LAYOUT, # transpile_pass=lambda device: [ # SabreLayout( -# coupling_map=CouplingMap(device.build_coupling_map()), +# coupling_map=CouplingMap(device.build_coupling_map()), # skip_routing=True, # ), # FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), @@ -514,7 +521,7 @@ def get_openqasm_gates() -> list[str]: # SafeAIRouting( # coupling_map=device.build_coupling_map(), # optimization_level=3, -# layout_mode="improve", +# layout_mode="improve", # local_mode=True # ) # ], @@ -532,7 +539,6 @@ def get_openqasm_gates() -> list[str]: SabreLayout( coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=False, - seed=None, ), ], ) @@ -540,7 +546,7 @@ def get_openqasm_gates() -> list[str]: # register_action( # DeviceDependentAction( -# "AIRouting_opt", +# "AIRouting_opt", # CompilationOrigin.QISKIT, # PassType.MAPPING, # stochastic=True, diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index f23ca3320..c3b8ead5e 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -11,6 +11,7 @@ from __future__ import annotations import logging +import ctypes from pathlib import Path from typing import TYPE_CHECKING @@ -28,6 +29,7 @@ logger = logging.getLogger("mqt-predictor") + def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generator) -> tuple[QuantumCircuit, str]: """Returns a random quantum circuit from the training circuits folder. @@ -88,7 +90,6 @@ def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float6 feature_dict["entanglement_ratio"] = np.array([supermarq_features.entanglement_ratio], dtype=np.float32) feature_dict["parallelism"] = np.array([supermarq_features.parallelism], dtype=np.float32) feature_dict["liveness"] = np.array([supermarq_features.liveness], dtype=np.float32) - return feature_dict @@ -105,3 +106,9 @@ def get_path_trained_model() -> Path: def get_path_training_circuits() -> Path: """Returns the path to the training circuits folder used for RL training.""" return get_path_training_data() / "training_circuits" + +def trim_memory() -> None: + try: + ctypes.CDLL("libc.so.6").malloc_trim(0) + except Exception as e: + pass # Not available on all platforms diff --git a/src/mqt/predictor/rl/predictor.py b/src/mqt/predictor/rl/predictor.py index 558e43021..39ead54f2 100644 --- a/src/mqt/predictor/rl/predictor.py +++ b/src/mqt/predictor/rl/predictor.py @@ -13,6 +13,8 @@ import logging from pathlib import Path from typing import TYPE_CHECKING +from collections import deque +from copy import deepcopy from sb3_contrib import MaskablePPO from sb3_contrib.common.maskable.policies import MaskableMultiInputActorCriticPolicy @@ -21,12 +23,13 @@ from mqt.predictor.rl.helper import get_path_trained_model, logger from mqt.predictor.rl.predictorenv import PredictorEnv +from mqt.predictor.reward import figure_of_merit, crit_depth, estimated_success_probability if TYPE_CHECKING: from qiskit import QuantumCircuit from qiskit.transpiler import Target - from mqt.predictor.reward import figure_of_merit + from mqt.predictor.reward import figure_of_merit, crit_depth, estimated_success_probability class Predictor: @@ -70,17 +73,39 @@ def compile_as_predicted( used_compilation_passes = [] terminated = False truncated = False + recent_actions = deque(maxlen=8) + blocked_actions = set() while not (terminated or truncated): action_masks = get_action_masks(self.env) - action, _ = trained_rl_model.predict(obs, action_masks=action_masks) + if blocked_actions: + action_masks = deepcopy(action_masks) + for idx in blocked_actions: + action_masks[idx] = False + action, _ = trained_rl_model.predict(obs, action_masks=action_masks, deterministic=True) action = int(action) + + recent_actions.append(action) + + max_cycle_length = 4 + + def is_cycle(lst, k): + if len(lst) < 2*k: + return False + return lst[-2*k:-k] == lst[-k:] + + for k in range(3, max_cycle_length+1): + if is_cycle(list(recent_actions), k): + print(f"Avoiding {k}-cycle infinite loop pattern") + for cyc_action in set(list(recent_actions)[-k:]): + blocked_actions.add(cyc_action) + break + action_item = self.env.action_set[action] used_compilation_passes.append(action_item.name) - # if action_item.name == "terminate": - # swap_count = self.env.state.count_ops().get("swap", 0) - # depth = self.env.state.depth() - # critical_depth = reward.crit_depth(self.env.state) - # esp= reward.estimated_success_probability(self.env.state, self.env.device) + if action_item.name == "terminate": + depth = self.env.state.depth() + critical_depth = crit_depth(self.env.state) + esp= estimated_success_probability(self.env.state, self.env.device) obs, reward_val, terminated, truncated, _info = self.env.step(action) if not self.env.error_occurred: @@ -88,7 +113,7 @@ def compile_as_predicted( self.env.state, reward_val, used_compilation_passes, - ) # swap_count, depth, critical_depth, esp + depth, critical_depth, esp) msg = "Error occurred during compilation." raise RuntimeError(msg) @@ -122,20 +147,27 @@ def train_model( progress_bar = False logger.debug("Start training for: " + self.figure_of_merit + " on " + self.device_name) - model = MaskablePPO( - MaskableMultiInputActorCriticPolicy, - self.env, - verbose=verbose, - tensorboard_log="./" + model_name + "_" + self.figure_of_merit + "_" + self.device_name, - gamma=0.98, - n_steps=n_steps, - batch_size=batch_size, - n_epochs=n_epochs, - ) + # model = MaskablePPO( + # MaskableMultiInputActorCriticPolicy, + # self.env, + # verbose=verbose, + # tensorboard_log="./" + model_name + "_" + self.figure_of_merit + "_" + self.device_name, + # gamma=0.98, + # n_steps=n_steps, + # batch_size=batch_size, + # n_epochs=n_epochs, + # ) + model = MaskablePPO.load( + get_path_trained_model() / "model_expected_fidelity_ibm_brisbane.zip", + env=self.env, + verbose=verbose, + device="cuda", + ) # Training Loop: In each iteration, the agent collects n_steps steps (rollout), # updates the policy for n_epochs, and then repeats the process until total_timesteps steps have been taken. model.learn(total_timesteps=timesteps, progress_bar=progress_bar) model.save(get_path_trained_model() / (model_name + "_" + self.figure_of_merit + "_" + self.device_name)) + print("Model saved") def load_model(model_name: str) -> MaskablePPO: @@ -190,5 +222,5 @@ def rl_compile( else: predictor = predictor_singleton - qc, _, info = predictor.compile_as_predicted(qc) - return qc, info + qc, reward, info, depth, critical_depth, esp = predictor.compile_as_predicted(qc) + return qc, reward, info, depth, critical_depth, esp diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index a7239c232..f300fda0d 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -12,6 +12,7 @@ import logging import sys +import gc from typing import TYPE_CHECKING, Any if sys.version_info >= (3, 11) and TYPE_CHECKING: # pragma: no cover @@ -64,6 +65,7 @@ create_feature_dict, get_path_training_circuits, get_state_sample, + trim_memory ) from mqt.predictor.rl.parsing import ( final_layout_bqskit_to_qiskit, @@ -166,7 +168,7 @@ def __init__( self.rng = np.random.default_rng(10) spaces = { - "num_qubits": Discrete(128), + "num_qubits": Discrete(134), "depth": Discrete(1000000), "program_communication": Box(low=0, high=1, shape=(1,), dtype=np.float32), "critical_depth": Box(low=0, high=1, shape=(1,), dtype=np.float32), @@ -192,8 +194,16 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any """ self.used_actions.append(str(self.action_set[action].name)) logger.info(f"Applying: {self.action_set[action].name!s}") + if self.num_steps > 70: + return ( + create_feature_dict(self.state), + 0, + True, + False, + {}, + ) altered_qc = self.apply_action(action) - if not altered_qc: + if not altered_qc : return ( create_feature_dict(self.state), 0, @@ -203,6 +213,9 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any ) self.state: QuantumCircuit = altered_qc + + del altered_qc + gc.collect() self.num_steps += 1 self.valid_actions = self.determine_valid_actions_for_state() @@ -223,13 +236,18 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any temp_circ = self.state.decompose(gates_to_decompose="unitary") # qiskit fallback to ['id', 'u1', 'u2', 'u3', 'cx'] by default according to https://quantum.cloud.ibm.com/docs/en/api/qiskit/0.24/transpiler self.state = transpile(temp_circ, basis_gates=get_openqasm_gates(), optimization_level=0) + del temp_circ + gc.collect() elif self.state.count_ops().get("clifford"): temp_circ = self.state.decompose(gates_to_decompose="clifford") self.state = transpile(temp_circ, basis_gates=get_openqasm_gates(), optimization_level=0) + del temp_circ + gc.collect() self.state._layout = self.layout # noqa: SLF001 - obs = create_feature_dict(self.state) - return obs, reward_val, done, False, {} + #obs = create_feature_dict(self.state) + trim_memory() + return create_feature_dict(self.state), reward_val, done, False, {} def calculate_reward(self) -> float: """Calculates and returns the reward for the current state.""" @@ -283,6 +301,7 @@ def reset( self.num_qubits_uncompiled_circuit = self.state.num_qubits self.has_parameterized_gates = len(self.state.parameters) > 0 + trim_memory() return create_feature_dict(self.state), {} def action_masks(self) -> list[bool]: @@ -337,8 +356,11 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: if action.origin == CompilationOrigin.BQSKIT: return self._apply_bqskit_action(action, action_index) msg = f"Origin {action.origin} not supported." + + gc.collect() + trim_memory() raise ValueError(msg) - + def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): passes = action.transpile_pass( @@ -408,6 +430,7 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui assert self.layout is not None self.layout.final_layout = final_layout_pytket_to_qiskit(tket_qc, altered_qc) # Decompose to the allowed gates (by default generic u gates are used) + del tket_qc return transpile(altered_qc, basis_gates=get_openqasm_gates(), optimization_level=0) def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCircuit: @@ -456,21 +479,41 @@ def determine_valid_actions_for_state(self) -> list[int]: check_mapping(self.state) mapped = check_mapping.property_set["is_swap_mapped"] + logger.info(f"Mapped:{mapped}") + if not only_nat_gates: # not native gates yet - if not mapped: + if not mapped: return self.actions_synthesis_indices + self.actions_opt_indices - else: - return self.actions_synthesis_indices + self.actions_preserving_indices + return self.actions_synthesis_indices + self.actions_preserving_indices if mapped and self.layout is not None: # The circuit is correctly mapped - return [self.action_terminate_index, *self.actions_opt_indices, *self.actions_final_optimization_indices] - - if self.layout is not None: + return [self.action_terminate_index, *self.actions_opt_indices] #*self.actions_final_optimization_indices] + + if self.layout is not None: # The circuit is not yet mapped but a layout is set. return self.actions_routing_indices - else: - # The circuit already fulfils coupling map but no layout is assigned, could explore better layout options - if mapped: - return self.actions_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices - else: - return self.actions_opt_indices + self.actions_layout_indices + self.actions_mapping_indices + # The circuit already fulfils coupling map but no layout is assigned, could explore better layout options + if mapped: + return self.actions_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices + return self.actions_opt_indices + self.actions_layout_indices + self.actions_mapping_indices + + + + # if not only_nat_gates: + # actions = self.actions_synthesis_indices + self.actions_opt_indices + # if self.layout is not None: + # actions += self.actions_routing_indices + # return actions + + # check_mapping = CheckMap(coupling_map=self.device.build_coupling_map()) + # check_mapping(self.state) + # mapped = check_mapping.property_set["is_swap_mapped"] + + # if mapped and self.layout is not None: # The circuit is correctly mapped. + # return [self.action_terminate_index, *self.actions_opt_indices] + + # if self.layout is not None: # The circuit is not yet mapped but a layout is set. + # return self.actions_routing_indices + + # # No layout applied yet + # return self.actions_mapping_indices + self.actions_layout_indices + self.actions_opt_indices diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index 43211af0a..9f1205a57 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -12,15 +12,16 @@ import re from pathlib import Path +import pandas as pd import pytest +from qiskit_ibm_runtime import QiskitRuntimeService from mqt.bench import BenchmarkLevel, get_benchmark from mqt.bench.targets import get_device from qiskit.circuit.library import CXGate from qiskit.qasm2 import dump from qiskit.transpiler import InstructionProperties, Target from qiskit.transpiler.passes import GatesInBasis -from qiskit_ibm_runtime import QiskitRuntimeService from mqt.predictor.rl import Predictor, rl_compile from mqt.predictor.rl.actions import ( @@ -31,7 +32,8 @@ register_action, remove_action, ) -from mqt.predictor.rl.helper import create_feature_dict +from mqt.predictor.rl.helper import create_feature_dict, get_path_training_circuits +from qiskit import QuantumCircuit def test_predictor_env_reset_from_string() -> None: @@ -93,19 +95,18 @@ def test_qcompile_with_newly_trained_models() -> None: service = QiskitRuntimeService(channel="ibm_cloud", token=api_token) backend = service.backend(device) backend.target.description = "ibm_brisbane" # HACK - print(backend.target) + print(backend.configuration().dt) predictor = Predictor(figure_of_merit=figure_of_merit, device=backend.target) qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 17, target=backend.target) predictor.train_model( - timesteps=100000, + timesteps=30000, test=False, ) - qc_compiled, reward, compilation_information = rl_compile( + qc_compiled, compilation_information = rl_compile( qc, device=backend.target, figure_of_merit=figure_of_merit ) - print(f"Fidelity: {reward}") check_nat_gates = GatesInBasis(basis_gates=backend.target.operation_names) check_nat_gates(qc_compiled) @@ -152,3 +153,49 @@ def test_register_action() -> None: with pytest.raises(KeyError, match=re.escape("No action with name wrong_action_name is registered")): remove_action("wrong_action_name") + + +def test_evaluations() -> None: + test_dir = get_path_training_circuits() / "new_indep_circuits" / "test" + results_dir = Path(__file__).resolve().parent / "results" / "baseline" + results_dir.mkdir(parents=True, exist_ok=True) + output_path = results_dir / "info.csv" + figure_of_merit = "expected_fidelity" + + api_token = "" + available_devices = ["ibm_brisbane", "ibm_torino"] + device = available_devices[0] + + service = QiskitRuntimeService(channel="ibm_cloud", token=api_token) + backend = service.backend(device) + backend.target.description = "ibm_brisbane" # HACK + model_results = [] + model_label= "baseline" + for file_path in test_dir.glob("*.qasm"): + file_name = file_path.name + print(f"File: {file_name}") + qc = QuantumCircuit.from_qasm_file(str(file_path)) + qc_compiled, reward, info, depth, critical_depth, esp = rl_compile( + qc, device=backend.target, figure_of_merit=figure_of_merit + ) + model_results.append({ + "model": model_label, + "file": file_path.name, + "depth": depth, + "crit_depth": critical_depth, + "esp": esp, + "reward": reward, + "ep_length_mean": len(info) + }) + print(f"✅ Size {qc.num_qubits} | File: {file_path.name} | " + f"Reward: {reward:.4f} | " + f"Depth: {depth} | " + f"Critical Depth: {critical_depth} |" + f"ESP: {esp} |" + f"Mean Steps: {len(info):.1f}") + + df = pd.DataFrame(model_results) + df.sort_values(by=["depth", "model"], inplace=True) + df.to_csv(output_path, index=False) + print(f"📁 Results saved to: {output_path}") + From eae11a2c4a41e7c57494effecc94a668cea09509 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 5 Sep 2025 15:42:49 +0200 Subject: [PATCH 29/98] Set up code for testing new model --- docs/setup.md | 2 +- noxfile.py | 5 +- pyproject.toml | 4 +- src/mqt/predictor/reward.py | 4 +- src/mqt/predictor/rl/actions.py | 301 +++++++++++++++--------- src/mqt/predictor/rl/helper.py | 9 - src/mqt/predictor/rl/predictor.py | 24 +- src/mqt/predictor/rl/predictorenv.py | 308 +++++++++++++++++-------- tests/compilation/test_predictor_rl.py | 16 +- uv.lock | 10 +- 10 files changed, 444 insertions(+), 239 deletions(-) diff --git a/docs/setup.md b/docs/setup.md index f37bc88e8..da572bb00 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -109,7 +109,7 @@ After setup, any quantum circuit can be compiled for the most suitable device wi from mqt.predictor import qcompile from mqt.bench import get_benchmark, BenchmarkLevel -uncompiled_qc = get_benchmark("ghz", level=BenchmarkLevel.ALG, circuit_size=5) +uncompiled_qc = get_benchmark("ghz", level=BenchmarkLevel.INDEP, circuit_size=5) compiled_qc, compilation_info, selected_device = qcompile( uncompiled_qc, figure_of_merit="expected_fidelity" ) diff --git a/noxfile.py b/noxfile.py index 8a7e78ddc..bc2755126 100644 --- a/noxfile.py +++ b/noxfile.py @@ -30,7 +30,7 @@ # TODO(denialhaag): Add 3.14 when all dependencies support it # https://github.com/munich-quantum-toolkit/predictor/issues/420 -PYTHON_ALL_VERSIONS = ["3.10", "3.11", "3.12"] +PYTHON_ALL_VERSIONS = ["3.10", "3.11", "3.12", "3.13"] if os.environ.get("CI", None): nox.options.error_on_missing_interpreters = True @@ -83,9 +83,6 @@ def tests(session: nox.Session) -> None: @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) def minimums(session: nox.Session) -> None: """Test the minimum versions of dependencies.""" - if platform.system() == "Windows": - session.skip("Too slow on Windows — skipping minimums session.") - return _run_tests( session, install_args=["--resolution=lowest-direct"], diff --git a/pyproject.toml b/pyproject.toml index e161979cf..a8adfea9b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 - "torch>=2.7.1,<2.8.0", + "torch>=2.7.1,<2.8.0" , "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1", "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'" @@ -253,5 +253,5 @@ ignore = ["GH200"] [tool.uv] override-dependencies = [ - "networkx==2.8.5", + "networkx==2.8.5; python_version < '3.13'", # qiskit-ibm-ai-local-transpiler requires this specific version of networkx ] diff --git a/src/mqt/predictor/reward.py b/src/mqt/predictor/reward.py index 3cc726eed..65282c6dc 100644 --- a/src/mqt/predictor/reward.py +++ b/src/mqt/predictor/reward.py @@ -70,7 +70,7 @@ def expected_fidelity(qc: QuantumCircuit, device: Target, precision: int = 10) - try: specific_fidelity = 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error except KeyError: - # try flipped orientation + # try flipped orientation (for uni-directional devices) specific_fidelity = 1 - device[gate_type][second_qubit_idx, first_qubit_idx].error res *= specific_fidelity @@ -212,7 +212,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: if first_qubit_idx not in active_qubits: continue - dt=5e-10 # discrete time unit used in duration + dt = device.dt # discrete time unit used in duration res *= np.exp( -instruction.duration * dt / min(device.qubit_properties[first_qubit_idx].t1, device.qubit_properties[first_qubit_idx].t2) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 8c73f6b70..cacd7ab10 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -14,6 +14,7 @@ from dataclasses import dataclass from enum import Enum from typing import TYPE_CHECKING, Any +import sys from pytket.architecture import Architecture from pytket.passes import ( @@ -23,6 +24,7 @@ RemoveRedundancies, RoutingPass, ) +from pytket.placement import GraphPlacement, NoiseAwarePlacement from qiskit import QuantumCircuit from qiskit.circuit import ClassicalRegister, Instruction, QuantumRegister, Qubit, StandardEquivalenceLibrary from qiskit.circuit.library import ( @@ -62,6 +64,7 @@ OptimizeCliffords, RemoveDiagonalGatesBeforeMeasure, SabreLayout, + SabreSwap, TrivialLayout, UnitarySynthesis, VF2Layout, @@ -218,23 +221,13 @@ def get_openqasm_gates() -> list[str]: "rccx", ] - -# register_action( -# DeviceIndependentAction( -# "Optimize1qGatesDecomposition", -# CompilationOrigin.QISKIT, -# PassType.OPT, -# preserve=True, -# transpile_pass=lambda device: [Optimize1qGatesDecomposition(basis=device.operation_names)], -# ) -# ) - register_action( - DeviceIndependentAction( + DeviceDependentAction( "Optimize1qGatesDecomposition", CompilationOrigin.QISKIT, PassType.OPT, - [Optimize1qGatesDecomposition()], + preserve=True, + transpile_pass=lambda device: [Optimize1qGatesDecomposition(basis=device.operation_names)], ) ) @@ -302,26 +295,17 @@ def get_openqasm_gates() -> list[str]: ) ) -# register_action( -# DeviceDependentAction( -# "Opt2qBlocks", -# CompilationOrigin.QISKIT, -# PassType.OPT, -# transpile_pass=lambda native_gate, coupling_map: [ -# Collect2qBlocks(), -# ConsolidateBlocks(basis_gates=native_gate), -# UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), -# ], -# preserve=True, -# ) -# ) - register_action( - DeviceIndependentAction( + DeviceDependentAction( "Opt2qBlocks", CompilationOrigin.QISKIT, PassType.OPT, - [Collect2qBlocks(), ConsolidateBlocks(), UnitarySynthesis()], + transpile_pass=lambda native_gate, coupling_map: [ + Collect2qBlocks(), + ConsolidateBlocks(basis_gates=native_gate), + UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), + ], + preserve=True, ) ) @@ -410,21 +394,7 @@ def get_openqasm_gates() -> list[str]: "VF2PostLayout", CompilationOrigin.QISKIT, PassType.FINAL_OPT, - transpile_pass=lambda device: VF2PostLayout(target=device), - ) -) - -register_action( - DeviceDependentAction( - "TrivialLayout", - CompilationOrigin.QISKIT, - PassType.LAYOUT, - transpile_pass=lambda device: [ - TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - ], + transpile_pass=lambda device: VF2PostLayout(target=device, time_limit=100), ) ) @@ -462,22 +432,27 @@ def get_openqasm_gates() -> list[str]: ) ) -# register_action( -# DeviceDependentAction( -# "SabreLayout", -# CompilationOrigin.QISKIT, -# PassType.LAYOUT, -# transpile_pass=lambda device: [ -# SabreLayout( -# coupling_map=CouplingMap(device.build_coupling_map()), -# skip_routing=True, -# ), -# FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), -# EnlargeWithAncilla(), -# ApplyLayout(), -# ], -# ) -# ) +register_action( + DeviceDependentAction( + "GraphPlacement", + CompilationOrigin.TKET, + PassType.LAYOUT, + transpile_pass=lambda device: [ + GraphPlacement(Architecture(list(device.build_coupling_map())),timeout=5000, maximum_matches=5000) + ], + ) +) + +register_action( + DeviceDependentAction( + "NoiseAwarePlacement", + CompilationOrigin.TKET, + PassType.LAYOUT, + transpile_pass=lambda device, node_err, edge_err, readout_err: [ + NoiseAwarePlacement(Architecture(list(device.build_coupling_map())), node_err, edge_err, readout_err, timeout=5000, maximum_matches=5000) + ], + ) +) register_action( DeviceDependentAction( @@ -493,40 +468,49 @@ def get_openqasm_gates() -> list[str]: register_action( DeviceDependentAction( - "BasicSwap", + "SabreSwap", CompilationOrigin.QISKIT, PassType.ROUTING, - transpile_pass=lambda device: [BasicSwap(coupling_map=CouplingMap(device.build_coupling_map()))], + stochastic=True, + transpile_pass=lambda device: [ + SabreSwap(coupling_map=CouplingMap(device.build_coupling_map()), heuristic="decay") + ], ) ) -# register_action( -# DeviceDependentAction( -# "SabreSwap", -# CompilationOrigin.QISKIT, -# PassType.ROUTING, -# stochastic=True, -# transpile_pass=lambda device: [ -# SabreSwap(coupling_map=CouplingMap(device.build_coupling_map()), heuristic="decay") -# ], -# ) -# ) +if sys.version_info < (3, 13): + register_action( + DeviceDependentAction( + "AIRouting", + CompilationOrigin.QISKIT, + PassType.ROUTING, + stochastic=True, + transpile_pass=lambda device: [ + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="improve", + local_mode=True + ) + ], + ) + ) -# register_action( -# DeviceDependentAction( -# "AIRouting", -# CompilationOrigin.QISKIT, -# PassType.ROUTING, -# stochastic=True, -# transpile_pass=lambda device: [ -# SafeAIRouting( -# coupling_map=device.build_coupling_map(), -# optimization_level=3, -# layout_mode="improve", -# local_mode=True -# ) -# ], -# ) -# ) + register_action( + DeviceDependentAction( + "AIRouting_opt", + CompilationOrigin.QISKIT, + PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device: [ + ### Requires a initial layout, but "optimize" mode overwrites it + SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=True, max_iterations=1), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), + ], + ) + ) register_action( DeviceDependentAction( @@ -539,28 +523,12 @@ def get_openqasm_gates() -> list[str]: SabreLayout( coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=False, + max_iterations=1 ), ], ) ) -# register_action( -# DeviceDependentAction( -# "AIRouting_opt", -# CompilationOrigin.QISKIT, -# PassType.MAPPING, -# stochastic=True, -# transpile_pass=lambda device: [ -# ### Requires a initial layout, but "optimize" mode overwrites it -# TrivialLayout(coupling_map=CouplingMap(device.build_coupling_map())), -# FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), -# EnlargeWithAncilla(), -# ApplyLayout(), -# SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), -# ], -# ) -# ) - # register_action( # DeviceDependentAction( # "BQSKitMapping", @@ -749,3 +717,124 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) # 8. Return as dag return circuit_to_dag(qc_final) + +def extract_cregs_and_measurements( + qc: QuantumCircuit, +) -> tuple[list[ClassicalRegister], list[tuple[Instruction, list[Any], list[Any]]]]: + """Extracts classical registers and measurement operations from a quantum circuit. + + Args: + qc: The input QuantumCircuit. + + Returns: + A tuple containing a list of classical registers and a list of measurement operations. + """ + cregs = [ClassicalRegister(cr.size, name=cr.name) for cr in qc.cregs] + measurements = [(item.operation, item.qubits, item.clbits) for item in qc.data if item.operation.name == "measure"] + return cregs, measurements + + +def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: + """Removes classical registers and measurement operations from the circuit. + + Args: + qc: The input QuantumCircuit. + + Returns: + A new QuantumCircuit with only quantum operations (no cregs or measurements). + """ + qregs = [QuantumRegister(qr.size, name=qr.name) for qr in qc.qregs] + new_qc = QuantumCircuit(*qregs) + old_to_new = {} + for orig_qr, new_qr in zip(qc.qregs, new_qc.qregs, strict=False): + for idx in range(orig_qr.size): + old_to_new[orig_qr[idx]] = new_qr[idx] + for item in qc.data: + instr = item.operation + qargs = [old_to_new[q] for q in item.qubits] + if instr.name not in ("measure", "barrier"): + new_qc.append(instr, qargs) + return new_qc + + +def add_cregs_and_measurements( + qc: QuantumCircuit, + cregs: list[ClassicalRegister], + measurements: list[tuple[Instruction, list[Any], list[Any]]], + qubit_map: dict[Qubit, Qubit] | None = None, +) -> QuantumCircuit: + """Adds classical registers and measurement operations back to the quantum circuit. + + Args: + qc: The quantum circuit to which cregs and measurements are added. + cregs: List of ClassicalRegister to add. + measurements: List of measurement instructions as tuples (Instruction, qubits, clbits). + qubit_map: Optional dictionary mapping original qubits to new qubits. + + Returns: + The modified QuantumCircuit with cregs and measurements added. + """ + for cr in cregs: + qc.add_register(cr) + for instr, qargs, cargs in measurements: + new_qargs = [qubit_map[q] for q in qargs] if qubit_map else qargs + qc.append(instr, new_qargs, cargs) + return qc + + +class SafeAIRouting(AIRouting): # type: ignore[misc] + """Custom AIRouting wrapper that removes classical registers before routing. + + This prevents failures in AIRouting when classical bits are present by + temporarily removing classical registers and measurements and restoring + them after routing is completed. + """ + + def run(self, dag: DAGCircuit) -> DAGCircuit: + """Run the routing pass on a DAGCircuit.""" + # 1. Convert input dag to circuit + qc_orig = dag_to_circuit(dag) + + # 2. Extract classical registers and measurement instructions + cregs, measurements = extract_cregs_and_measurements(qc_orig) + + # 3. Remove cregs and measurements + qc_noclassical = remove_cregs(qc_orig) + + # 4. Convert back to dag and run routing (AIRouting) + dag_noclassical = circuit_to_dag(qc_noclassical) + dag_routed = super().run(dag_noclassical) + + # 5. Convert routed dag to circuit for restoration + qc_routed = dag_to_circuit(dag_routed) + + # 6. Build mapping from original qubits to qubits in routed circuit + final_layout = getattr(self, "property_set", {}).get("final_layout", None) + if final_layout is None and hasattr(dag_routed, "property_set"): + final_layout = dag_routed.property_set.get("final_layout", None) + + assert final_layout is not None, "final_layout is None — cannot map virtual qubits" + qubit_map = {} + for virt in qc_orig.qubits: + try: + phys = final_layout[virt] + except KeyError as err: + msg = f"Virtual qubit {virt} not found in final layout!" + raise RuntimeError(msg) from err + if isinstance(phys, int): + try: + qubit_map[virt] = qc_routed.qubits[phys] + except IndexError as err: + msg = f"Physical index {phys} is out of range in routed circuit!" + raise RuntimeError(msg) from err + else: + try: + idx = qc_routed.qubits.index(phys) + except ValueError as err: + msg = f"Physical qubit {phys} not found in output circuit!" + raise RuntimeError(msg) from err + qubit_map[virt] = qc_routed.qubits[idx] + # 7. Restore classical registers and measurement instructions + qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) + # 8. Return as dag + return circuit_to_dag(qc_final) \ No newline at end of file diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index c3b8ead5e..2226cc151 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -11,13 +11,11 @@ from __future__ import annotations import logging -import ctypes from pathlib import Path from typing import TYPE_CHECKING import numpy as np from qiskit import QuantumCircuit - from mqt.predictor.utils import calc_supermarq_features if TYPE_CHECKING: @@ -29,7 +27,6 @@ logger = logging.getLogger("mqt-predictor") - def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generator) -> tuple[QuantumCircuit, str]: """Returns a random quantum circuit from the training circuits folder. @@ -106,9 +103,3 @@ def get_path_trained_model() -> Path: def get_path_training_circuits() -> Path: """Returns the path to the training circuits folder used for RL training.""" return get_path_training_data() / "training_circuits" - -def trim_memory() -> None: - try: - ctypes.CDLL("libc.so.6").malloc_trim(0) - except Exception as e: - pass # Not available on all platforms diff --git a/src/mqt/predictor/rl/predictor.py b/src/mqt/predictor/rl/predictor.py index 39ead54f2..fea4fac76 100644 --- a/src/mqt/predictor/rl/predictor.py +++ b/src/mqt/predictor/rl/predictor.py @@ -66,7 +66,7 @@ def compile_as_predicted( Raises: RuntimeError: If an error occurs during compilation. """ - trained_rl_model = load_model("model_" + self.figure_of_merit + "_" + self.device_name) + trained_rl_model = load_model("model_new_actions_" + self.figure_of_merit + "_" + self.device_name) obs, _ = self.env.reset(qc, seed=0) @@ -147,18 +147,18 @@ def train_model( progress_bar = False logger.debug("Start training for: " + self.figure_of_merit + " on " + self.device_name) - # model = MaskablePPO( - # MaskableMultiInputActorCriticPolicy, - # self.env, - # verbose=verbose, - # tensorboard_log="./" + model_name + "_" + self.figure_of_merit + "_" + self.device_name, - # gamma=0.98, - # n_steps=n_steps, - # batch_size=batch_size, - # n_epochs=n_epochs, - # ) + model = MaskablePPO( + MaskableMultiInputActorCriticPolicy, + self.env, + verbose=verbose, + tensorboard_log="./" + model_name + "_" + self.figure_of_merit + "_" + self.device_name, + gamma=0.98, + n_steps=n_steps, + batch_size=batch_size, + n_epochs=n_epochs, + ) model = MaskablePPO.load( - get_path_trained_model() / "model_expected_fidelity_ibm_brisbane.zip", + get_path_trained_model() / "model_new_actions_expected_fidelity_ibm_torino.zip", env=self.env, verbose=verbose, device="cuda", diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index f300fda0d..684378d5d 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -31,18 +31,21 @@ import warnings from typing import cast +import ctypes import numpy as np from bqskit.ext import bqskit_to_qiskit, qiskit_to_bqskit from gymnasium import Env from gymnasium.spaces import Box, Dict, Discrete from joblib import load -from pytket.circuit import Qubit +from pytket.circuit import Qubit, Node from pytket.extensions.qiskit import qiskit_to_tk, tk_to_qiskit from qiskit import QuantumCircuit, transpile +from qiskit.circuit import StandardEquivalenceLibrary +from qiskit.passmanager import PropertySet from qiskit.passmanager.flow_controllers import DoWhileController -from qiskit.transpiler import CouplingMap, PassManager, Target, TranspileLayout -from qiskit.transpiler.passes import CheckMap, GatesInBasis +from qiskit.transpiler import CouplingMap, PassManager, Target, TranspileLayout, Layout +from qiskit.transpiler.passes import CheckMap, GatesInBasis, BasisTranslator, SetLayout, EnlargeWithAncilla, FullAncillaAllocation, ApplyLayout from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from mqt.predictor.hellinger import get_hellinger_model_path @@ -65,7 +68,6 @@ create_feature_dict, get_path_training_circuits, get_state_sample, - trim_memory ) from mqt.predictor.rl.parsing import ( final_layout_bqskit_to_qiskit, @@ -178,8 +180,8 @@ def __init__( } self.observation_space = Dict(spaces) self.filename = "" - self.max_iter = (20, 20) # (layout_trials, routing _trials) - + self.max_iter = 20 + self.node_err = self.edge_err = self.readout_err = None def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any, Any]]: """Executes the given action and returns the new state, the reward, whether the episode is done, whether the episode is truncated and additional information. @@ -194,14 +196,6 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any """ self.used_actions.append(str(self.action_set[action].name)) logger.info(f"Applying: {self.action_set[action].name!s}") - if self.num_steps > 70: - return ( - create_feature_dict(self.state), - 0, - True, - False, - {}, - ) altered_qc = self.apply_action(action) if not altered_qc : return ( @@ -225,7 +219,7 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any if action == self.action_terminate_index: reward_val = self.calculate_reward() - logger.info(f"Fidelity: {reward_val}") + logger.info(f"{self.reward_function}: {reward_val}") done = True else: reward_val = 0 @@ -245,21 +239,31 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any gc.collect() self.state._layout = self.layout # noqa: SLF001 - #obs = create_feature_dict(self.state) - trim_memory() + self.trim_memory() return create_feature_dict(self.state), reward_val, done, False, {} - def calculate_reward(self) -> float: + def calculate_reward(self, qc=None) -> float: """Calculates and returns the reward for the current state.""" - if self.reward_function == "expected_fidelity": - return expected_fidelity(self.state, self.device) - if self.reward_function == "estimated_success_probability": - return estimated_success_probability(self.state, self.device) - if self.reward_function == "estimated_hellinger_distance": - return estimated_hellinger_distance(self.state, self.device, self.hellinger_model) - if self.reward_function == "critical_depth": - return crit_depth(self.state) - assert_never(self.state) + if qc==None: + if self.reward_function == "expected_fidelity": + return expected_fidelity(self.state, self.device) + if self.reward_function == "estimated_success_probability": + return estimated_success_probability(self.state, self.device) + if self.reward_function == "estimated_hellinger_distance": + return estimated_hellinger_distance(self.state, self.device, self.hellinger_model) + if self.reward_function == "critical_depth": + return crit_depth(self.state) + assert_never(self.state) + else: + if self.reward_function == "expected_fidelity": + return expected_fidelity(qc, self.device) + if self.reward_function == "estimated_success_probability": + return estimated_success_probability(qc, self.device) + if self.reward_function == "estimated_hellinger_distance": + return estimated_hellinger_distance(qc, self.device, self.hellinger_model) + if self.reward_function == "critical_depth": + return crit_depth(qc) + def render(self) -> None: """Renders the current state.""" @@ -282,6 +286,7 @@ def reset( The initial state and additional information. """ super().reset(seed=seed) + self.trim_memory() if isinstance(qc, QuantumCircuit): self.state = qc elif qc: @@ -301,14 +306,14 @@ def reset( self.num_qubits_uncompiled_circuit = self.state.num_qubits self.has_parameterized_gates = len(self.state.parameters) > 0 - trim_memory() + return create_feature_dict(self.state), {} def action_masks(self) -> list[bool]: """Returns a list of valid actions for the current state.""" action_mask = [action in self.valid_actions for action in self.action_set] - # it is not clear how tket will handle the layout, so we remove all actions that are from "origin"=="tket" if a layout is set + # # it is not clear how tket will handle the layout, so we remove all actions that are from "origin"=="tket" if a layout is set if self.layout is not None: action_mask = [ action_mask[i] and self.action_set[i].origin != CompilationOrigin.TKET for i in range(len(action_mask)) @@ -358,69 +363,205 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: msg = f"Origin {action.origin} not supported." gc.collect() - trim_memory() + self.trim_memory() raise ValueError(msg) + + def fom_aware_compile( + self, + action: Action, + device: Target, + qc: QuantumCircuit, + max_iteration: int = 4 + ) -> tuple[QuantumCircuit, PropertySet|None]: + best_result = None + best_property_set = None + best_fom = -1.0 + best_swap_count = float("inf") # for fallback + + for i in range(max_iteration): + pm = PassManager(action.transpile_pass(device)) + try: + out_circ = pm.run(qc) + prop_set = dict(pm.property_set) + + try: + # Synthesize for lookahead fidelity (Mapping could insert non-local SWAP gates) + if self.reward_function in ["expected_fidelity", "estimated_success_probability", "estimated_hellinger_distance"]: + synth_pass = PassManager([BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names)]) + synth_circ = synth_pass.run(out_circ.copy()) + fom = self.calculate_reward(synth_circ) + del synth_circ + + if fom > best_fom: + print(f"New best {self.reward_function}: {fom}") + best_fom = fom + best_result = out_circ + best_property_set = prop_set + else: + fom = self.calculate_reward(out_circ) + if fom < best_fom: + print(f"New best {self.reward_function}: {fom}") + best_fom = fom + best_result = out_circ + best_property_set = prop_set + + except Exception as e: + logger.warning(f"[Fallback to SWAP counts] Synthesis or fidelity computation failed: {e}") + swap_count = out_circ.count_ops().get("swap", 0) + if best_result is None or (best_fom == -1.0 and swap_count < best_swap_count): + print(f"[Fallback] New best (lower) swap count: {swap_count}") + best_swap_count = swap_count + best_result = out_circ + best_property_set = prop_set + + except Exception as e: + logger.error(f"[Error] Pass failed at iteration {i+1}: {e}") + continue + gc.collect() + if best_result is not None: + return best_result, best_property_set + else: + logger.error("All attempts failed.") + return qc, {} def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: - if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): - passes = action.transpile_pass( - self.device.operation_names, - CouplingMap(self.device.build_coupling_map()) if self.layout else None, + if getattr(action, "stochastic", False): # Wrap stochastic action to optimize for the used figure of merit + altered_qc, pm_property_set = self.fom_aware_compile( + action, + self.device, + self.state, + max_iteration=self.max_iter, ) - if action.name == "QiskitO3": - pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) - else: - pm = PassManager(passes) else: - transpile_pass = ( - action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass - ) - pm = PassManager(transpile_pass) - - altered_qc = pm.run(self.state) - - if action_index in ( - self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices - ): - altered_qc = self._handle_qiskit_layout_postprocessing(action, pm, altered_qc) - + if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): + passes = action.transpile_pass( + self.device.operation_names, + CouplingMap(self.device.build_coupling_map()) if self.layout else None, + ) + if action.name == "QiskitO3": + pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) + else: + pm = PassManager(passes) + altered_qc = pm.run(self.state) + pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + else: + transpile_pass = ( + action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass + ) + pm = PassManager(transpile_pass) + altered_qc = pm.run(self.state) + pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + + if action_index in (self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices): + altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) elif action_index in self.actions_routing_indices and self.layout: - self.layout.final_layout = pm.property_set["final_layout"] + self.layout.final_layout = pm_property_set["final_layout"] + + del pm_property_set + gc.collect() return altered_qc def _handle_qiskit_layout_postprocessing( - self, action: Action, pm: PassManager, altered_qc: QuantumCircuit + self, + action: Action, + pm_property_set: dict[str, Any], + altered_qc: QuantumCircuit, ) -> QuantumCircuit: if action.name == "VF2PostLayout": - assert pm.property_set["VF2PostLayout_stop_reason"] is not None - post_layout = pm.property_set["post_layout"] + assert pm_property_set["VF2PostLayout_stop_reason"] is not None + post_layout = pm_property_set.get("post_layout") if post_layout: altered_qc, _ = postprocess_vf2postlayout(altered_qc, post_layout, self.layout) elif action.name == "VF2Layout": - if pm.property_set["VF2Layout_stop_reason"] == VF2LayoutStopReason.SOLUTION_FOUND: - assert pm.property_set["layout"] + if pm_property_set["VF2Layout_stop_reason"] == VF2LayoutStopReason.SOLUTION_FOUND: + assert pm_property_set["layout"] else: - assert pm.property_set["layout"] + assert pm_property_set["layout"] - if pm.property_set["layout"]: + layout = pm_property_set.get("layout") + if layout: self.layout = TranspileLayout( - initial_layout=pm.property_set["layout"], - input_qubit_mapping=pm.property_set["original_qubit_indices"], - final_layout=pm.property_set["final_layout"], + initial_layout=layout, + input_qubit_mapping=pm_property_set.get("original_qubit_indices"), + final_layout=pm_property_set.get("final_layout"), _output_qubit_list=altered_qc.qubits, _input_qubit_count=self.num_qubits_uncompiled_circuit, ) + + if self.layout is not None and pm_property_set.get("final_layout"): + self.layout.final_layout = pm_property_set["final_layout"] return altered_qc def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircuit: tket_qc = qiskit_to_tk(self.state, preserve_param_uuid=True) - transpile_pass = ( - action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass - ) + if action.name == "NoiseAwarePlacement": + if self.node_err==None or self.edge_err==None or self.readout_err==None: + node_err: dict = {} + edge_err: dict = {} + readout_err: dict = {} + # Calculate avg node, edge and readout error + for op_name in self.device.operation_names: + inst_props = self.device[op_name] # this is a dict-like object + for qtuple, props in inst_props.items(): + if props is None or not hasattr(props, "error") or props.error is None: + continue + if len(qtuple) == 1: # single-qubit op + q = qtuple[0] + node_err[Node(q)] = props.error + elif len(qtuple) == 2: # two-qubit op + q1, q2 = qtuple + edge_err[(Node(q1), Node(q2))] = props.error + + # Readout errors (they are in the Target under "measure") + if "measure" in self.device: + for (q,), props in self.device["measure"].items(): + if props is not None and hasattr(props, "error") and props.error is not None: + readout_err[Node(q)] = props.error + self.node_err = node_err + self.edge_err = edge_err + self.readout_err = readout_err + transpile_pass = (action.transpile_pass(self.device, self.node_err, self.edge_err, self.readout_err)) + else: + transpile_pass = ( + action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass + ) assert isinstance(transpile_pass, list) - for p in transpile_pass: - p.apply(tket_qc) + if action_index in self.actions_layout_indices: + try: + placement = transpile_pass[0].get_placement_map(tket_qc) + qc_tmp = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) + qiskit_mapping = { + qc_tmp.qubits[i]: placement[list(placement.keys())[i]].index[0] + for i in range(len(placement)) + } + layout = Layout(qiskit_mapping) + pm = PassManager([ + SetLayout(layout), + FullAncillaAllocation(coupling_map=CouplingMap(self.device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout() + ]) + altered_qc = pm.run(qc_tmp) + self.layout = TranspileLayout( + initial_layout=pm.property_set.get("layout"), + input_qubit_mapping=pm.property_set["original_qubit_indices"], + final_layout=pm.property_set["final_layout"], + _output_qubit_list=altered_qc.qubits, + _input_qubit_count=self.num_qubits_uncompiled_circuit, + ) + del qc_tmp + del tket_qc + gc.collect() + return altered_qc + except Exception as e: + print(f"[Warning] Placement failed ({action.name}): {e}. Falling back to the original circuit.") + altered_qc = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) + return altered_qc + + else: + for p in transpile_pass: + p.apply(tket_qc) qbs = tket_qc.qubits tket_qc.rename_units({qbs[i]: Qubit("q", i) for i in range(len(qbs))}) @@ -429,9 +570,11 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui if action_index in self.actions_routing_indices: assert self.layout is not None self.layout.final_layout = final_layout_pytket_to_qiskit(tket_qc, altered_qc) - # Decompose to the allowed gates (by default generic u gates are used) + del tket_qc - return transpile(altered_qc, basis_gates=get_openqasm_gates(), optimization_level=0) + gc.collect() + return altered_qc + def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCircuit: """Applies the given BQSKit action to the current state and returns the altered state. @@ -479,7 +622,7 @@ def determine_valid_actions_for_state(self) -> list[int]: check_mapping(self.state) mapped = check_mapping.property_set["is_swap_mapped"] - logger.info(f"Mapped:{mapped}") + logger.info(f"Mapped:{mapped}, Native:{only_nat_gates}") if not only_nat_gates: # not native gates yet if not mapped: @@ -487,7 +630,7 @@ def determine_valid_actions_for_state(self) -> list[int]: return self.actions_synthesis_indices + self.actions_preserving_indices if mapped and self.layout is not None: # The circuit is correctly mapped - return [self.action_terminate_index, *self.actions_opt_indices] #*self.actions_final_optimization_indices] + return [self.action_terminate_index, *self.actions_preserving_indices, *self.actions_final_optimization_indices] if self.layout is not None: # The circuit is not yet mapped but a layout is set. @@ -497,23 +640,8 @@ def determine_valid_actions_for_state(self) -> list[int]: return self.actions_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices return self.actions_opt_indices + self.actions_layout_indices + self.actions_mapping_indices - - - # if not only_nat_gates: - # actions = self.actions_synthesis_indices + self.actions_opt_indices - # if self.layout is not None: - # actions += self.actions_routing_indices - # return actions - - # check_mapping = CheckMap(coupling_map=self.device.build_coupling_map()) - # check_mapping(self.state) - # mapped = check_mapping.property_set["is_swap_mapped"] - - # if mapped and self.layout is not None: # The circuit is correctly mapped. - # return [self.action_terminate_index, *self.actions_opt_indices] - - # if self.layout is not None: # The circuit is not yet mapped but a layout is set. - # return self.actions_routing_indices - - # # No layout applied yet - # return self.actions_mapping_indices + self.actions_layout_indices + self.actions_opt_indices + def trim_memory(self): + try: + ctypes.CDLL("libc.so.6").malloc_trim(0) + except Exception as e: + pass # Not available on all platforms diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index 9f1205a57..25b7f8f48 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -90,18 +90,18 @@ def test_qcompile_with_newly_trained_models() -> None: api_token = "" available_devices = ["ibm_brisbane", "ibm_torino"] - device = available_devices[0] + device = available_devices[1] service = QiskitRuntimeService(channel="ibm_cloud", token=api_token) backend = service.backend(device) - backend.target.description = "ibm_brisbane" # HACK - print(backend.configuration().dt) + backend.target.description = "ibm_torino" # HACK predictor = Predictor(figure_of_merit=figure_of_merit, device=backend.target) qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 17, target=backend.target) predictor.train_model( - timesteps=30000, + timesteps=10000, test=False, + model_name="model_new_actions" ) qc_compiled, compilation_information = rl_compile( @@ -157,20 +157,20 @@ def test_register_action() -> None: def test_evaluations() -> None: test_dir = get_path_training_circuits() / "new_indep_circuits" / "test" - results_dir = Path(__file__).resolve().parent / "results" / "baseline" + results_dir = Path(__file__).resolve().parent / "results" / "new_actions" results_dir.mkdir(parents=True, exist_ok=True) output_path = results_dir / "info.csv" figure_of_merit = "expected_fidelity" api_token = "" available_devices = ["ibm_brisbane", "ibm_torino"] - device = available_devices[0] + device = available_devices[1] service = QiskitRuntimeService(channel="ibm_cloud", token=api_token) backend = service.backend(device) - backend.target.description = "ibm_brisbane" # HACK + backend.target.description = "ibm_torino" # HACK model_results = [] - model_label= "baseline" + model_label= "new_actions" for file_path in test_dir.glob("*.qasm"): file_name = file_path.name print(f"File: {file_name}") diff --git a/uv.lock b/uv.lock index d9e9e8d01..7f0a518db 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ ] [manifest] -overrides = [{ name = "networkx", specifier = "==2.8.5" }] +overrides = [{ name = "networkx", marker = "python_full_version < '3.13'", specifier = "==2.8.5" }] [[package]] name = "absl-py" @@ -1499,7 +1499,7 @@ name = "mqt-bench" version = "2.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "networkx" }, + { name = "networkx", marker = "python_full_version < '3.13'" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, { name = "qiskit", extra = ["qasm3-import"] }, @@ -2484,7 +2484,7 @@ dependencies = [ { name = "graphviz" }, { name = "jinja2" }, { name = "lark" }, - { name = "networkx" }, + { name = "networkx", marker = "python_full_version < '3.13'" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, { name = "qwasm" }, @@ -2806,7 +2806,7 @@ version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backoff" }, - { name = "networkx" }, + { name = "networkx", marker = "python_full_version < '3.13'" }, { name = "qiskit" }, { name = "qiskit-qasm3-import" }, { name = "requests" }, @@ -3762,7 +3762,7 @@ dependencies = [ { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, - { name = "networkx" }, + { name = "networkx", marker = "python_full_version < '3.13'" }, { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, From 68306ec03cb95bf2f9627677b542b50f127be39a Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 5 Sep 2025 16:33:57 +0200 Subject: [PATCH 30/98] Reset --- src/mqt/predictor/ml/predictor.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 155c09e04..fc470a409 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -191,10 +191,7 @@ def _compile_all_circuits_devicewise( if (path_compiled_circuits / (target_filename + ".qasm")).exists(): continue try: - if sys.platform == "win32": - res = rl_compile(qc, device, self.figure_of_merit, rl_pred) - else: - res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) + res = timeout_watcher(rl_compile, [qc, device, self.figure_of_merit, rl_pred], timeout) if isinstance(res, tuple): compiled_qc = res[0] with Path(path_compiled_circuits / (target_filename + ".qasm")).open("w", encoding="utf-8") as f: @@ -209,6 +206,7 @@ def compile_training_circuits( path_uncompiled_circuits: Path | None = None, path_compiled_circuits: Path | None = None, timeout: int = 600, + num_workers: int = -1 ) -> None: """Compiles all circuits in the given directory with the given timeout and saves them in the given directory. @@ -229,24 +227,19 @@ def compile_training_circuits( with zipfile.ZipFile(str(path_zip), "r") as zip_ref: zip_ref.extractall(path_uncompiled_circuits) - if sys.platform != "win32": - Parallel(n_jobs=1, verbose=100)( - delayed(self._compile_all_circuits_devicewise)( - device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level - ) - for device in self.devices + Parallel(n_jobs=num_workers, verbose=100)( + delayed(self._compile_all_circuits_devicewise)( + device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level ) - else: - for device in self.devices: - self._compile_all_circuits_devicewise( - device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level - ) + for device in self.devices + ) def generate_training_data( self, path_uncompiled_circuits: Path | None = None, path_compiled_circuits: Path | None = None, path_training_data: Path | None = None, + num_workers: int = -1 ) -> None: """Creates and saves training data from all generated training samples. @@ -274,7 +267,7 @@ def generate_training_data( names_list = [] scores_list = [] - results = Parallel(n_jobs=1, verbose=100)( + results = Parallel(n_jobs=num_workers, verbose=100)( delayed(self._generate_training_sample)( filename.name, path_uncompiled_circuits, From fcba8fa810f1fe80ea6f4ba52be1ec6498254db9 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Sat, 6 Sep 2025 15:22:58 +0200 Subject: [PATCH 31/98] Add new actions --- noxfile.py | 1 - pyproject.toml | 4 +- src/mqt/predictor/ml/predictor.py | 4 +- src/mqt/predictor/reward.py | 13 +- src/mqt/predictor/rl/actions.py | 397 ++++++++----------------- src/mqt/predictor/rl/predictor.py | 58 +--- src/mqt/predictor/rl/predictorenv.py | 178 +++++------ tests/compilation/test_predictor_rl.py | 111 ++----- 8 files changed, 252 insertions(+), 514 deletions(-) diff --git a/noxfile.py b/noxfile.py index bc2755126..9e13b37f9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -12,7 +12,6 @@ import argparse import os -import platform import shutil from typing import TYPE_CHECKING diff --git a/pyproject.toml b/pyproject.toml index a8adfea9b..bdcf1b7db 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,9 +44,9 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 - "torch>=2.7.1,<2.8.0" , + "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler>=0.11.1", + "qiskit-ibm-transpiler>=0.11.1; python_version < '3.13'", "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'" ] diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index fc470a409..3f0ec5497 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -206,7 +206,7 @@ def compile_training_circuits( path_uncompiled_circuits: Path | None = None, path_compiled_circuits: Path | None = None, timeout: int = 600, - num_workers: int = -1 + num_workers: int = -1, ) -> None: """Compiles all circuits in the given directory with the given timeout and saves them in the given directory. @@ -239,7 +239,7 @@ def generate_training_data( path_uncompiled_circuits: Path | None = None, path_compiled_circuits: Path | None = None, path_training_data: Path | None = None, - num_workers: int = -1 + num_workers: int = -1, ) -> None: """Creates and saves training data from all generated training samples. diff --git a/src/mqt/predictor/reward.py b/src/mqt/predictor/reward.py index 65282c6dc..8394d6eee 100644 --- a/src/mqt/predictor/reward.py +++ b/src/mqt/predictor/reward.py @@ -189,7 +189,6 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: res = 1.0 for instr in scheduled_circ.data: - instruction = instr.operation qargs = instr.qubits gate_type = instruction.name @@ -202,7 +201,6 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: if len(qargs) == 1: if gate_type == "measure": - res *= 1 - device[gate_type][first_qubit_idx,].error continue if gate_type == "delay": @@ -211,18 +209,19 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: # only consider active qubits if first_qubit_idx not in active_qubits: continue - - dt = device.dt # discrete time unit used in duration + + dt = device.dt # discrete time unit used in duration res *= np.exp( - -instruction.duration * dt + -instruction.duration + * dt / min(device.qubit_properties[first_qubit_idx].t1, device.qubit_properties[first_qubit_idx].t2) ) continue res *= 1 - device[gate_type][first_qubit_idx,].error - + else: second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) - res *= 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error + res *= 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error if qiskit_version >= "2.0.0": for i in range(device.num_qubits): diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index cacd7ab10..05bffd82a 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -10,12 +10,15 @@ from __future__ import annotations +import os +import sys from collections import defaultdict from dataclasses import dataclass from enum import Enum -from typing import TYPE_CHECKING, Any -import sys +from typing import TYPE_CHECKING +from bqskit import MachineModel +from bqskit import compile as bqskit_compile from pytket.architecture import Architecture from pytket.passes import ( CliffordSimp, @@ -49,7 +52,6 @@ from qiskit.transpiler import CouplingMap from qiskit.transpiler.passes import ( ApplyLayout, - BasicSwap, BasisTranslator, Collect2qBlocks, CollectCliffords, @@ -57,24 +59,30 @@ CommutativeInverseCancellation, ConsolidateBlocks, DenseLayout, + Depth, EnlargeWithAncilla, + FixedPoint, FullAncillaAllocation, + GatesInBasis, InverseCancellation, + MinimumPoint, Optimize1qGatesDecomposition, OptimizeCliffords, RemoveDiagonalGatesBeforeMeasure, SabreLayout, SabreSwap, - TrivialLayout, + Size, UnitarySynthesis, VF2Layout, VF2PostLayout, ) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason +from qiskit.transpiler.preset_passmanagers import common from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.rl.parsing import ( PreProcessTKETRoutingAfterQiskitLayout, + get_bqskit_native_gates, ) if TYPE_CHECKING: @@ -177,50 +185,6 @@ def remove_action(name: str) -> None: del _ACTIONS[name] -def get_openqasm_gates() -> list[str]: - """Returns a list of all quantum gates within the openQASM 2.0 standard header. - - According to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc - Removes generic single qubit gates u1, u2, u3 since they are no meaningful features for RL - - """ - return [ - "cx", - "id", - "u", - "p", - "x", - "y", - "z", - "h", - "r", - "s", - "sdg", - "t", - "tdg", - "rx", - "ry", - "rz", - "sx", - "sxdg", - "cz", - "cy", - "swap", - "ch", - "ccx", - "cswap", - "crx", - "cry", - "crz", - "cu1", - "cp", - "csx", - "cu", - "rxx", - "rzz", - "rccx", - ] - register_action( DeviceDependentAction( "Optimize1qGatesDecomposition", @@ -345,49 +309,49 @@ def get_openqasm_gates() -> list[str]: ) ) -# register_action( -# DeviceDependentAction( -# "QiskitO3", -# CompilationOrigin.QISKIT, -# PassType.OPT, -# transpile_pass=lambda native_gate, coupling_map: [ -# Collect2qBlocks(), -# ConsolidateBlocks(basis_gates=native_gate), -# UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), -# Optimize1qGatesDecomposition(basis=native_gate), -# CommutativeCancellation(basis_gates=native_gate), -# GatesInBasis(native_gate), -# ConditionalController( -# common.generate_translation_passmanager( -# target=None, basis_gates=native_gate, coupling_map=coupling_map -# ).to_flow_controller(), -# condition=lambda property_set: not property_set["all_gates_in_basis"], -# ), -# Depth(recurse=True), -# FixedPoint("depth"), -# Size(recurse=True), -# FixedPoint("size"), -# MinimumPoint(["depth", "size"], "optimization_loop"), -# ], -# do_while=lambda property_set: not property_set["optimization_loop_minimum_point"], -# ) -# ) - -# register_action( -# DeviceDependentAction( -# "BQSKitO2", -# CompilationOrigin.BQSKIT, -# PassType.OPT, -# transpile_pass=lambda circuit: bqskit_compile( -# circuit, -# optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, -# synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, -# max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, -# seed=10, -# num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, -# ), -# ) -# ) +register_action( + DeviceDependentAction( + "QiskitO3", + CompilationOrigin.QISKIT, + PassType.OPT, + transpile_pass=lambda native_gate, coupling_map: [ + Collect2qBlocks(), + ConsolidateBlocks(basis_gates=native_gate), + UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), + Optimize1qGatesDecomposition(basis=native_gate), + CommutativeCancellation(basis_gates=native_gate), + GatesInBasis(native_gate), + ConditionalController( + common.generate_translation_passmanager( + target=None, basis_gates=native_gate, coupling_map=coupling_map + ).to_flow_controller(), + condition=lambda property_set: not property_set["all_gates_in_basis"], + ), + Depth(recurse=True), + FixedPoint("depth"), + Size(recurse=True), + FixedPoint("size"), + MinimumPoint(["depth", "size"], "optimization_loop"), + ], + do_while=lambda property_set: not property_set["optimization_loop_minimum_point"], + ) +) + +register_action( + DeviceDependentAction( + "BQSKitO2", + CompilationOrigin.BQSKIT, + PassType.OPT, + transpile_pass=lambda circuit: bqskit_compile( + circuit, + optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, + synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, + max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, + seed=10, + num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, + ), + ) +) register_action( DeviceDependentAction( @@ -438,7 +402,7 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.TKET, PassType.LAYOUT, transpile_pass=lambda device: [ - GraphPlacement(Architecture(list(device.build_coupling_map())),timeout=5000, maximum_matches=5000) + GraphPlacement(Architecture(list(device.build_coupling_map())), timeout=5000, maximum_matches=5000) ], ) ) @@ -449,7 +413,14 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.TKET, PassType.LAYOUT, transpile_pass=lambda device, node_err, edge_err, readout_err: [ - NoiseAwarePlacement(Architecture(list(device.build_coupling_map())), node_err, edge_err, readout_err, timeout=5000, maximum_matches=5000) + NoiseAwarePlacement( + Architecture(list(device.build_coupling_map())), + node_err, + edge_err, + readout_err, + timeout=5000, + maximum_matches=5000, + ) ], ) ) @@ -485,13 +456,13 @@ def get_openqasm_gates() -> list[str]: PassType.ROUTING, stochastic=True, transpile_pass=lambda device: [ - SafeAIRouting( - coupling_map=device.build_coupling_map(), - optimization_level=3, - layout_mode="improve", - local_mode=True - ) - ], + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="improve", + local_mode=True, + ) + ], ) ) @@ -518,38 +489,33 @@ def get_openqasm_gates() -> list[str]: CompilationOrigin.QISKIT, PassType.MAPPING, stochastic=True, - # Qiskit O3 by default uses (max_iterations, layout_trials, swap_trials) = (4, 20, 20) transpile_pass=lambda device: [ - SabreLayout( - coupling_map=CouplingMap(device.build_coupling_map()), - skip_routing=False, - max_iterations=1 - ), + SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=False, max_iterations=1), ], ) ) -# register_action( -# DeviceDependentAction( -# "BQSKitMapping", -# CompilationOrigin.BQSKIT, -# PassType.MAPPING, -# transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( -# bqskit_circuit, -# model=MachineModel( -# num_qudits=device.num_qubits, -# gate_set=get_bqskit_native_gates(device), -# coupling_graph=[(elem[0], elem[1]) for elem in device.build_coupling_map()], -# ), -# with_mapping=True, -# optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, -# synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, -# max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, -# seed=10, -# num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, -# ), -# ) -# ) +register_action( + DeviceDependentAction( + "BQSKitMapping", + CompilationOrigin.BQSKIT, + PassType.MAPPING, + transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( + bqskit_circuit, + model=MachineModel( + num_qudits=device.num_qubits, + gate_set=get_bqskit_native_gates(device), + coupling_graph=[(elem[0], elem[1]) for elem in device.build_coupling_map()], + ), + with_mapping=True, + optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, + synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, + max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, + seed=10, + num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, + ), + ) +) register_action( DeviceDependentAction( @@ -562,22 +528,22 @@ def get_openqasm_gates() -> list[str]: ) ) -# register_action( -# DeviceDependentAction( -# "BQSKitSynthesis", -# CompilationOrigin.BQSKIT, -# PassType.SYNTHESIS, -# transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( -# bqskit_circuit, -# model=MachineModel(bqskit_circuit.num_qudits, gate_set=get_bqskit_native_gates(device)), -# optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, -# synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, -# max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, -# seed=10, -# num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, -# ), -# ) -# ) +register_action( + DeviceDependentAction( + "BQSKitSynthesis", + CompilationOrigin.BQSKIT, + PassType.SYNTHESIS, + transpile_pass=lambda device: lambda bqskit_circuit: bqskit_compile( + bqskit_circuit, + model=MachineModel(bqskit_circuit.num_qudits, gate_set=get_bqskit_native_gates(device)), + optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, + synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, + max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, + seed=10, + num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, + ), + ) +) register_action( DeviceIndependentAction( @@ -599,7 +565,7 @@ def get_actions_by_pass_type() -> dict[PassType, list[Action]]: def extract_cregs_and_measurements( qc: QuantumCircuit, -) -> tuple[list[ClassicalRegister], list[tuple[Instruction, list[Any], list[Any]]]]: +) -> tuple[list[ClassicalRegister], list[tuple[Instruction, list[Qubit], list[ClassicalRegister]]]]: """Extracts classical registers and measurement operations from a quantum circuit. Args: @@ -639,7 +605,7 @@ def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: def add_cregs_and_measurements( qc: QuantumCircuit, cregs: list[ClassicalRegister], - measurements: list[tuple[Instruction, list[Any], list[Any]]], + measurements: list[tuple[Instruction, list[Qubit], list[ClassicalRegister]]], qubit_map: dict[Qubit, Qubit] | None = None, ) -> QuantumCircuit: """Adds classical registers and measurement operations back to the quantum circuit. @@ -671,23 +637,17 @@ class SafeAIRouting(AIRouting): # type: ignore[misc] def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the routing pass on a DAGCircuit.""" - # 1. Convert input dag to circuit qc_orig = dag_to_circuit(dag) - - # 2. Extract classical registers and measurement instructions + # Extract classical registers and measurement instructions cregs, measurements = extract_cregs_and_measurements(qc_orig) - - # 3. Remove cregs and measurements + # Remove cregs and measurements qc_noclassical = remove_cregs(qc_orig) - - # 4. Convert back to dag and run routing (AIRouting) + # Convert back to dag and run routing (AIRouting) dag_noclassical = circuit_to_dag(qc_noclassical) dag_routed = super().run(dag_noclassical) - - # 5. Convert routed dag to circuit for restoration + # Convert routed dag to circuit for restoration qc_routed = dag_to_circuit(dag_routed) - - # 6. Build mapping from original qubits to qubits in routed circuit + # Build mapping from original qubits to qubits in routed circuit final_layout = getattr(self, "property_set", {}).get("final_layout", None) if final_layout is None and hasattr(dag_routed, "property_set"): final_layout = dag_routed.property_set.get("final_layout", None) @@ -713,128 +673,7 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: msg = f"Physical qubit {phys} not found in output circuit!" raise RuntimeError(msg) from err qubit_map[virt] = qc_routed.qubits[idx] - # 7. Restore classical registers and measurement instructions + # Restore classical registers and measurement instructions qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) - # 8. Return as dag + # Return as dag return circuit_to_dag(qc_final) - -def extract_cregs_and_measurements( - qc: QuantumCircuit, -) -> tuple[list[ClassicalRegister], list[tuple[Instruction, list[Any], list[Any]]]]: - """Extracts classical registers and measurement operations from a quantum circuit. - - Args: - qc: The input QuantumCircuit. - - Returns: - A tuple containing a list of classical registers and a list of measurement operations. - """ - cregs = [ClassicalRegister(cr.size, name=cr.name) for cr in qc.cregs] - measurements = [(item.operation, item.qubits, item.clbits) for item in qc.data if item.operation.name == "measure"] - return cregs, measurements - - -def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: - """Removes classical registers and measurement operations from the circuit. - - Args: - qc: The input QuantumCircuit. - - Returns: - A new QuantumCircuit with only quantum operations (no cregs or measurements). - """ - qregs = [QuantumRegister(qr.size, name=qr.name) for qr in qc.qregs] - new_qc = QuantumCircuit(*qregs) - old_to_new = {} - for orig_qr, new_qr in zip(qc.qregs, new_qc.qregs, strict=False): - for idx in range(orig_qr.size): - old_to_new[orig_qr[idx]] = new_qr[idx] - for item in qc.data: - instr = item.operation - qargs = [old_to_new[q] for q in item.qubits] - if instr.name not in ("measure", "barrier"): - new_qc.append(instr, qargs) - return new_qc - - -def add_cregs_and_measurements( - qc: QuantumCircuit, - cregs: list[ClassicalRegister], - measurements: list[tuple[Instruction, list[Any], list[Any]]], - qubit_map: dict[Qubit, Qubit] | None = None, -) -> QuantumCircuit: - """Adds classical registers and measurement operations back to the quantum circuit. - - Args: - qc: The quantum circuit to which cregs and measurements are added. - cregs: List of ClassicalRegister to add. - measurements: List of measurement instructions as tuples (Instruction, qubits, clbits). - qubit_map: Optional dictionary mapping original qubits to new qubits. - - Returns: - The modified QuantumCircuit with cregs and measurements added. - """ - for cr in cregs: - qc.add_register(cr) - for instr, qargs, cargs in measurements: - new_qargs = [qubit_map[q] for q in qargs] if qubit_map else qargs - qc.append(instr, new_qargs, cargs) - return qc - - -class SafeAIRouting(AIRouting): # type: ignore[misc] - """Custom AIRouting wrapper that removes classical registers before routing. - - This prevents failures in AIRouting when classical bits are present by - temporarily removing classical registers and measurements and restoring - them after routing is completed. - """ - - def run(self, dag: DAGCircuit) -> DAGCircuit: - """Run the routing pass on a DAGCircuit.""" - # 1. Convert input dag to circuit - qc_orig = dag_to_circuit(dag) - - # 2. Extract classical registers and measurement instructions - cregs, measurements = extract_cregs_and_measurements(qc_orig) - - # 3. Remove cregs and measurements - qc_noclassical = remove_cregs(qc_orig) - - # 4. Convert back to dag and run routing (AIRouting) - dag_noclassical = circuit_to_dag(qc_noclassical) - dag_routed = super().run(dag_noclassical) - - # 5. Convert routed dag to circuit for restoration - qc_routed = dag_to_circuit(dag_routed) - - # 6. Build mapping from original qubits to qubits in routed circuit - final_layout = getattr(self, "property_set", {}).get("final_layout", None) - if final_layout is None and hasattr(dag_routed, "property_set"): - final_layout = dag_routed.property_set.get("final_layout", None) - - assert final_layout is not None, "final_layout is None — cannot map virtual qubits" - qubit_map = {} - for virt in qc_orig.qubits: - try: - phys = final_layout[virt] - except KeyError as err: - msg = f"Virtual qubit {virt} not found in final layout!" - raise RuntimeError(msg) from err - if isinstance(phys, int): - try: - qubit_map[virt] = qc_routed.qubits[phys] - except IndexError as err: - msg = f"Physical index {phys} is out of range in routed circuit!" - raise RuntimeError(msg) from err - else: - try: - idx = qc_routed.qubits.index(phys) - except ValueError as err: - msg = f"Physical qubit {phys} not found in output circuit!" - raise RuntimeError(msg) from err - qubit_map[virt] = qc_routed.qubits[idx] - # 7. Restore classical registers and measurement instructions - qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) - # 8. Return as dag - return circuit_to_dag(qc_final) \ No newline at end of file diff --git a/src/mqt/predictor/rl/predictor.py b/src/mqt/predictor/rl/predictor.py index fea4fac76..3ffe07733 100644 --- a/src/mqt/predictor/rl/predictor.py +++ b/src/mqt/predictor/rl/predictor.py @@ -13,8 +13,6 @@ import logging from pathlib import Path from typing import TYPE_CHECKING -from collections import deque -from copy import deepcopy from sb3_contrib import MaskablePPO from sb3_contrib.common.maskable.policies import MaskableMultiInputActorCriticPolicy @@ -23,13 +21,12 @@ from mqt.predictor.rl.helper import get_path_trained_model, logger from mqt.predictor.rl.predictorenv import PredictorEnv -from mqt.predictor.reward import figure_of_merit, crit_depth, estimated_success_probability if TYPE_CHECKING: from qiskit import QuantumCircuit from qiskit.transpiler import Target - from mqt.predictor.reward import figure_of_merit, crit_depth, estimated_success_probability + from mqt.predictor.reward import figure_of_merit class Predictor: @@ -54,7 +51,7 @@ def __init__( def compile_as_predicted( self, qc: QuantumCircuit, - ) -> tuple[QuantumCircuit, float, list[str]]: + ) -> tuple[QuantumCircuit, list[str]]: """Compiles a given quantum circuit such that the given figure of merit is maximized by using the respectively trained optimized compiler. Arguments: @@ -66,54 +63,23 @@ def compile_as_predicted( Raises: RuntimeError: If an error occurs during compilation. """ - trained_rl_model = load_model("model_new_actions_" + self.figure_of_merit + "_" + self.device_name) + trained_rl_model = load_model("model_" + self.figure_of_merit + "_" + self.device_name) obs, _ = self.env.reset(qc, seed=0) used_compilation_passes = [] terminated = False truncated = False - recent_actions = deque(maxlen=8) - blocked_actions = set() while not (terminated or truncated): action_masks = get_action_masks(self.env) - if blocked_actions: - action_masks = deepcopy(action_masks) - for idx in blocked_actions: - action_masks[idx] = False - action, _ = trained_rl_model.predict(obs, action_masks=action_masks, deterministic=True) + action, _ = trained_rl_model.predict(obs, action_masks=action_masks) action = int(action) - - recent_actions.append(action) - - max_cycle_length = 4 - - def is_cycle(lst, k): - if len(lst) < 2*k: - return False - return lst[-2*k:-k] == lst[-k:] - - for k in range(3, max_cycle_length+1): - if is_cycle(list(recent_actions), k): - print(f"Avoiding {k}-cycle infinite loop pattern") - for cyc_action in set(list(recent_actions)[-k:]): - blocked_actions.add(cyc_action) - break - action_item = self.env.action_set[action] used_compilation_passes.append(action_item.name) - if action_item.name == "terminate": - depth = self.env.state.depth() - critical_depth = crit_depth(self.env.state) - esp= estimated_success_probability(self.env.state, self.env.device) - obs, reward_val, terminated, truncated, _info = self.env.step(action) + obs, _reward_val, terminated, truncated, _info = self.env.step(action) if not self.env.error_occurred: - return ( - self.env.state, - reward_val, - used_compilation_passes, - depth, critical_depth, esp) + return self.env.state, used_compilation_passes msg = "Error occurred during compilation." raise RuntimeError(msg) @@ -144,7 +110,7 @@ def train_model( n_steps = 2048 n_epochs = 10 batch_size = 64 - progress_bar = False + progress_bar = True logger.debug("Start training for: " + self.figure_of_merit + " on " + self.device_name) model = MaskablePPO( @@ -157,17 +123,10 @@ def train_model( batch_size=batch_size, n_epochs=n_epochs, ) - model = MaskablePPO.load( - get_path_trained_model() / "model_new_actions_expected_fidelity_ibm_torino.zip", - env=self.env, - verbose=verbose, - device="cuda", - ) # Training Loop: In each iteration, the agent collects n_steps steps (rollout), # updates the policy for n_epochs, and then repeats the process until total_timesteps steps have been taken. model.learn(total_timesteps=timesteps, progress_bar=progress_bar) model.save(get_path_trained_model() / (model_name + "_" + self.figure_of_merit + "_" + self.device_name)) - print("Model saved") def load_model(model_name: str) -> MaskablePPO: @@ -222,5 +181,4 @@ def rl_compile( else: predictor = predictor_singleton - qc, reward, info, depth, critical_depth, esp = predictor.compile_as_predicted(qc) - return qc, reward, info, depth, critical_depth, esp + return predictor.compile_as_predicted(qc) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 684378d5d..01ae26ee1 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -12,7 +12,6 @@ import logging import sys -import gc from typing import TYPE_CHECKING, Any if sys.version_info >= (3, 11) and TYPE_CHECKING: # pragma: no cover @@ -25,27 +24,34 @@ from pathlib import Path from bqskit import Circuit + from qiskit.passmanager import PropertySet from mqt.predictor.rl.actions import Action import warnings from typing import cast -import ctypes import numpy as np from bqskit.ext import bqskit_to_qiskit, qiskit_to_bqskit from gymnasium import Env from gymnasium.spaces import Box, Dict, Discrete from joblib import load -from pytket.circuit import Qubit, Node +from pytket.circuit import Node, Qubit from pytket.extensions.qiskit import qiskit_to_tk, tk_to_qiskit -from qiskit import QuantumCircuit, transpile +from qiskit import QuantumCircuit from qiskit.circuit import StandardEquivalenceLibrary -from qiskit.passmanager import PropertySet from qiskit.passmanager.flow_controllers import DoWhileController -from qiskit.transpiler import CouplingMap, PassManager, Target, TranspileLayout, Layout -from qiskit.transpiler.passes import CheckMap, GatesInBasis, BasisTranslator, SetLayout, EnlargeWithAncilla, FullAncillaAllocation, ApplyLayout +from qiskit.transpiler import CouplingMap, Layout, PassManager, Target, TranspileLayout +from qiskit.transpiler.passes import ( + ApplyLayout, + BasisTranslator, + CheckMap, + EnlargeWithAncilla, + FullAncillaAllocation, + GatesInBasis, + SetLayout, +) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from mqt.predictor.hellinger import get_hellinger_model_path @@ -62,7 +68,6 @@ DeviceDependentAction, PassType, get_actions_by_pass_type, - get_openqasm_gates, ) from mqt.predictor.rl.helper import ( create_feature_dict, @@ -170,7 +175,7 @@ def __init__( self.rng = np.random.default_rng(10) spaces = { - "num_qubits": Discrete(134), + "num_qubits": Discrete(self.device.num_qubits + 1), "depth": Discrete(1000000), "program_communication": Box(low=0, high=1, shape=(1,), dtype=np.float32), "critical_depth": Box(low=0, high=1, shape=(1,), dtype=np.float32), @@ -180,8 +185,11 @@ def __init__( } self.observation_space = Dict(spaces) self.filename = "" - self.max_iter = 20 - self.node_err = self.edge_err = self.readout_err = None + self.max_iter = 10 + self.node_err: dict[Node, float] | None = None + self.edge_err: dict[tuple[Node, Node], float] | None = None + self.readout_err: dict[Node, float] | None = None + def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any, Any]]: """Executes the given action and returns the new state, the reward, whether the episode is done, whether the episode is truncated and additional information. @@ -195,9 +203,8 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any RuntimeError: If no valid actions are left. """ self.used_actions.append(str(self.action_set[action].name)) - logger.info(f"Applying: {self.action_set[action].name!s}") altered_qc = self.apply_action(action) - if not altered_qc : + if not altered_qc: return ( create_feature_dict(self.state), 0, @@ -208,8 +215,6 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any self.state: QuantumCircuit = altered_qc - del altered_qc - gc.collect() self.num_steps += 1 self.valid_actions = self.determine_valid_actions_for_state() @@ -219,7 +224,6 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any if action == self.action_terminate_index: reward_val = self.calculate_reward() - logger.info(f"{self.reward_function}: {reward_val}") done = True else: reward_val = 0 @@ -227,24 +231,17 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any # in case the Qiskit.QuantumCircuit has unitary or u gates or clifford in it, decompose them (because otherwise qiskit will throw an error when applying the BasisTranslator if self.state.count_ops().get("unitary"): - temp_circ = self.state.decompose(gates_to_decompose="unitary") - # qiskit fallback to ['id', 'u1', 'u2', 'u3', 'cx'] by default according to https://quantum.cloud.ibm.com/docs/en/api/qiskit/0.24/transpiler - self.state = transpile(temp_circ, basis_gates=get_openqasm_gates(), optimization_level=0) - del temp_circ - gc.collect() + self.state = self.state.decompose(gates_to_decompose="unitary") elif self.state.count_ops().get("clifford"): - temp_circ = self.state.decompose(gates_to_decompose="clifford") - self.state = transpile(temp_circ, basis_gates=get_openqasm_gates(), optimization_level=0) - del temp_circ - gc.collect() + self.state = self.state.decompose(gates_to_decompose="clifford") self.state._layout = self.layout # noqa: SLF001 - self.trim_memory() + return create_feature_dict(self.state), reward_val, done, False, {} - def calculate_reward(self, qc=None) -> float: + def calculate_reward(self, qc: QuantumCircuit | None = None) -> float: """Calculates and returns the reward for the current state.""" - if qc==None: + if qc is None: if self.reward_function == "expected_fidelity": return expected_fidelity(self.state, self.device) if self.reward_function == "estimated_success_probability": @@ -263,7 +260,7 @@ def calculate_reward(self, qc=None) -> float: return estimated_hellinger_distance(qc, self.device, self.hellinger_model) if self.reward_function == "critical_depth": return crit_depth(qc) - + assert_never(self.state) def render(self) -> None: """Renders the current state.""" @@ -286,7 +283,7 @@ def reset( The initial state and additional information. """ super().reset(seed=seed) - self.trim_memory() + if isinstance(qc, QuantumCircuit): self.state = qc elif qc: @@ -362,22 +359,28 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: return self._apply_bqskit_action(action, action_index) msg = f"Origin {action.origin} not supported." - gc.collect() - self.trim_memory() raise ValueError(msg) - + def fom_aware_compile( - self, - action: Action, - device: Target, - qc: QuantumCircuit, - max_iteration: int = 4 - ) -> tuple[QuantumCircuit, PropertySet|None]: + self, action: Action, device: Target, qc: QuantumCircuit, max_iteration: int = 4 + ) -> tuple[QuantumCircuit, PropertySet | None]: + """Run a stochastic pass multiple times optimizing for the given figure of merit. + + Args: + action: The action containing the transpile pass. + device: The compilation target device. + qc: The input quantum circuit. + max_iteration: Maximum number of attempts to run the pass. + + Returns: + A tuple of the best circuit found and its property set (if available). + """ best_result = None best_property_set = None best_fom = -1.0 best_swap_count = float("inf") # for fallback + assert callable(action.transpile_pass), "Mapping action should be callable" for i in range(max_iteration): pm = PassManager(action.transpile_pass(device)) try: @@ -386,18 +389,23 @@ def fom_aware_compile( try: # Synthesize for lookahead fidelity (Mapping could insert non-local SWAP gates) - if self.reward_function in ["expected_fidelity", "estimated_success_probability", "estimated_hellinger_distance"]: - synth_pass = PassManager([BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names)]) + if self.reward_function in [ + "expected_fidelity", + "estimated_success_probability", + "estimated_hellinger_distance", + ]: + synth_pass = PassManager([ + BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names) + ]) synth_circ = synth_pass.run(out_circ.copy()) fom = self.calculate_reward(synth_circ) - del synth_circ if fom > best_fom: print(f"New best {self.reward_function}: {fom}") best_fom = fom best_result = out_circ best_property_set = prop_set - else: + else: fom = self.calculate_reward(out_circ) if fom < best_fom: print(f"New best {self.reward_function}: {fom}") @@ -409,27 +417,26 @@ def fom_aware_compile( logger.warning(f"[Fallback to SWAP counts] Synthesis or fidelity computation failed: {e}") swap_count = out_circ.count_ops().get("swap", 0) if best_result is None or (best_fom == -1.0 and swap_count < best_swap_count): - print(f"[Fallback] New best (lower) swap count: {swap_count}") best_swap_count = swap_count best_result = out_circ best_property_set = prop_set - except Exception as e: - logger.error(f"[Error] Pass failed at iteration {i+1}: {e}") + except Exception: + logger.exception(f"[Error] Pass failed at iteration {i + 1}") continue - gc.collect() + if best_result is not None: return best_result, best_property_set - else: - logger.error("All attempts failed.") - return qc, {} + logger.error("All attempts failed.") + return qc, {} def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: - if getattr(action, "stochastic", False): # Wrap stochastic action to optimize for the used figure of merit + pm_property_set: PropertySet | None = {} + if getattr(action, "stochastic", False): # Wrap stochastic action to optimize for the used figure of merit altered_qc, pm_property_set = self.fom_aware_compile( - action, + action, self.device, - self.state, + self.state, max_iteration=self.max_iter, ) else: @@ -452,22 +459,23 @@ def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCirc altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} - if action_index in (self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices): + if action_index in ( + self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices + ): altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) - elif action_index in self.actions_routing_indices and self.layout: + elif action_index in self.actions_routing_indices and self.layout and pm_property_set is not None: self.layout.final_layout = pm_property_set["final_layout"] - del pm_property_set - gc.collect() - return altered_qc def _handle_qiskit_layout_postprocessing( self, action: Action, - pm_property_set: dict[str, Any], + pm_property_set: dict[str, Any] | None, altered_qc: QuantumCircuit, ) -> QuantumCircuit: + if not pm_property_set: + return altered_qc if action.name == "VF2PostLayout": assert pm_property_set["VF2PostLayout_stop_reason"] is not None post_layout = pm_property_set.get("post_layout") @@ -496,10 +504,11 @@ def _handle_qiskit_layout_postprocessing( def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircuit: tket_qc = qiskit_to_tk(self.state, preserve_param_uuid=True) if action.name == "NoiseAwarePlacement": - if self.node_err==None or self.edge_err==None or self.readout_err==None: - node_err: dict = {} - edge_err: dict = {} - readout_err: dict = {} + if self.node_err is None or self.edge_err is None or self.readout_err is None: + node_err: dict[Node, float] = {} + edge_err: dict[tuple[Node, Node], float] = {} + readout_err: dict[Node, float] = {} + # Calculate avg node, edge and readout error for op_name in self.device.operation_names: inst_props = self.device[op_name] # this is a dict-like object @@ -511,7 +520,7 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui node_err[Node(q)] = props.error elif len(qtuple) == 2: # two-qubit op q1, q2 = qtuple - edge_err[(Node(q1), Node(q2))] = props.error + edge_err[Node(q1), Node(q2)] = props.error # Readout errors (they are in the Target under "measure") if "measure" in self.device: @@ -521,7 +530,8 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui self.node_err = node_err self.edge_err = edge_err self.readout_err = readout_err - transpile_pass = (action.transpile_pass(self.device, self.node_err, self.edge_err, self.readout_err)) + assert callable(action.transpile_pass) + transpile_pass = action.transpile_pass(self.device, self.node_err, self.edge_err, self.readout_err) else: transpile_pass = ( action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass @@ -530,19 +540,25 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui if action_index in self.actions_layout_indices: try: placement = transpile_pass[0].get_placement_map(tket_qc) + except Exception as e: + print(f"[Warning] Placement failed ({action.name}): {e}. Falling back to original circuit.") + return tk_to_qiskit(tket_qc, replace_implicit_swaps=True) + else: qc_tmp = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) + qiskit_mapping = { - qc_tmp.qubits[i]: placement[list(placement.keys())[i]].index[0] - for i in range(len(placement)) + qc_tmp.qubits[i]: placement[list(placement.keys())[i]].index[0] for i in range(len(placement)) } layout = Layout(qiskit_mapping) + pm = PassManager([ SetLayout(layout), FullAncillaAllocation(coupling_map=CouplingMap(self.device.build_coupling_map())), EnlargeWithAncilla(), - ApplyLayout() + ApplyLayout(), ]) altered_qc = pm.run(qc_tmp) + self.layout = TranspileLayout( initial_layout=pm.property_set.get("layout"), input_qubit_mapping=pm.property_set["original_qubit_indices"], @@ -550,13 +566,6 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui _output_qubit_list=altered_qc.qubits, _input_qubit_count=self.num_qubits_uncompiled_circuit, ) - del qc_tmp - del tket_qc - gc.collect() - return altered_qc - except Exception as e: - print(f"[Warning] Placement failed ({action.name}): {e}. Falling back to the original circuit.") - altered_qc = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) return altered_qc else: @@ -570,11 +579,8 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui if action_index in self.actions_routing_indices: assert self.layout is not None self.layout.final_layout = final_layout_pytket_to_qiskit(tket_qc, altered_qc) - - del tket_qc - gc.collect() + return altered_qc - def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCircuit: """Applies the given BQSKit action to the current state and returns the altered state. @@ -622,15 +628,17 @@ def determine_valid_actions_for_state(self) -> list[int]: check_mapping(self.state) mapped = check_mapping.property_set["is_swap_mapped"] - logger.info(f"Mapped:{mapped}, Native:{only_nat_gates}") - if not only_nat_gates: # not native gates yet if not mapped: return self.actions_synthesis_indices + self.actions_opt_indices return self.actions_synthesis_indices + self.actions_preserving_indices if mapped and self.layout is not None: # The circuit is correctly mapped - return [self.action_terminate_index, *self.actions_preserving_indices, *self.actions_final_optimization_indices] + return [ + self.action_terminate_index, + *self.actions_preserving_indices, + *self.actions_final_optimization_indices, + ] if self.layout is not None: # The circuit is not yet mapped but a layout is set. @@ -639,9 +647,3 @@ def determine_valid_actions_for_state(self) -> list[int]: if mapped: return self.actions_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices return self.actions_opt_indices + self.actions_layout_indices + self.actions_mapping_indices - - def trim_memory(self): - try: - ctypes.CDLL("libc.so.6").malloc_trim(0) - except Exception as e: - pass # Not available on all platforms diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index 25b7f8f48..ebb8f8e34 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -12,16 +12,14 @@ import re from pathlib import Path -import pandas as pd import pytest -from qiskit_ibm_runtime import QiskitRuntimeService from mqt.bench import BenchmarkLevel, get_benchmark from mqt.bench.targets import get_device from qiskit.circuit.library import CXGate from qiskit.qasm2 import dump -from qiskit.transpiler import InstructionProperties, Target -from qiskit.transpiler.passes import GatesInBasis +from qiskit.transpiler import CouplingMap, InstructionProperties, Target +from qiskit.transpiler.passes import CheckMap, GatesInBasis from mqt.predictor.rl import Predictor, rl_compile from mqt.predictor.rl.actions import ( @@ -32,8 +30,7 @@ register_action, remove_action, ) -from mqt.predictor.rl.helper import create_feature_dict, get_path_training_circuits -from qiskit import QuantumCircuit +from mqt.predictor.rl.helper import create_feature_dict, get_path_trained_model def test_predictor_env_reset_from_string() -> None: @@ -71,50 +68,40 @@ def test_qcompile_with_newly_trained_models() -> None: Important: Those trained models are used in later tests and must not be deleted. To test ESP as well, training must be done with a device that provides all relevant information (i.e. T1, T2 and gate times). """ - # figure_of_merit = "expected_fidelity" - # device = get_device("ibm_eagle_127") - # qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 20) - # predictor = Predictor(figure_of_merit=figure_of_merit, device=device) - - # model_name = "model_" + figure_of_merit + "_" + device.description - # model_path = Path(get_path_trained_model() / (model_name + ".zip")) - # if not model_path.exists(): - # with pytest.raises( - # FileNotFoundError, - # match=re.escape( - # "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." - # ), - # ): - # rl_compile(qc, device=device, figure_of_merit=figure_of_merit) figure_of_merit = "expected_fidelity" - - api_token = "" - available_devices = ["ibm_brisbane", "ibm_torino"] - device = available_devices[1] - - service = QiskitRuntimeService(channel="ibm_cloud", token=api_token) - backend = service.backend(device) - backend.target.description = "ibm_torino" # HACK - predictor = Predictor(figure_of_merit=figure_of_merit, device=backend.target) - qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 17, target=backend.target) + device = get_device("ibm_falcon_127") + qc = get_benchmark("ghz", BenchmarkLevel.ALG, 3) + predictor = Predictor(figure_of_merit=figure_of_merit, device=device) + + model_name = "model_" + figure_of_merit + "_" + device.description + model_path = Path(get_path_trained_model() / (model_name + ".zip")) + if not model_path.exists(): + with pytest.raises( + FileNotFoundError, + match=re.escape( + "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." + ), + ): + rl_compile(qc, device=device, figure_of_merit=figure_of_merit) predictor.train_model( - timesteps=10000, - test=False, - model_name="model_new_actions" + timesteps=100, + test=True, ) - qc_compiled, compilation_information = rl_compile( - qc, device=backend.target, figure_of_merit=figure_of_merit - ) + qc_compiled, compilation_information = rl_compile(qc, device=device, figure_of_merit=figure_of_merit) - check_nat_gates = GatesInBasis(basis_gates=backend.target.operation_names) + check_nat_gates = GatesInBasis(basis_gates=device.operation_names) check_nat_gates(qc_compiled) only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] + check_mapping = CheckMap(coupling_map=CouplingMap(device.build_coupling_map())) + check_mapping(qc_compiled) + mapped = check_mapping.property_set["is_swap_mapped"] assert qc_compiled.layout is not None assert compilation_information is not None - assert only_nat_gates, "Circuit should only contain native gates but was not detected as such" + assert only_nat_gates, "Circuit should only contain native gates but was not detected as such." + assert mapped, "Circuit should be mapped to the device's coupling map." def test_qcompile_with_false_input() -> None: @@ -153,49 +140,3 @@ def test_register_action() -> None: with pytest.raises(KeyError, match=re.escape("No action with name wrong_action_name is registered")): remove_action("wrong_action_name") - - -def test_evaluations() -> None: - test_dir = get_path_training_circuits() / "new_indep_circuits" / "test" - results_dir = Path(__file__).resolve().parent / "results" / "new_actions" - results_dir.mkdir(parents=True, exist_ok=True) - output_path = results_dir / "info.csv" - figure_of_merit = "expected_fidelity" - - api_token = "" - available_devices = ["ibm_brisbane", "ibm_torino"] - device = available_devices[1] - - service = QiskitRuntimeService(channel="ibm_cloud", token=api_token) - backend = service.backend(device) - backend.target.description = "ibm_torino" # HACK - model_results = [] - model_label= "new_actions" - for file_path in test_dir.glob("*.qasm"): - file_name = file_path.name - print(f"File: {file_name}") - qc = QuantumCircuit.from_qasm_file(str(file_path)) - qc_compiled, reward, info, depth, critical_depth, esp = rl_compile( - qc, device=backend.target, figure_of_merit=figure_of_merit - ) - model_results.append({ - "model": model_label, - "file": file_path.name, - "depth": depth, - "crit_depth": critical_depth, - "esp": esp, - "reward": reward, - "ep_length_mean": len(info) - }) - print(f"✅ Size {qc.num_qubits} | File: {file_path.name} | " - f"Reward: {reward:.4f} | " - f"Depth: {depth} | " - f"Critical Depth: {critical_depth} |" - f"ESP: {esp} |" - f"Mean Steps: {len(info):.1f}") - - df = pd.DataFrame(model_results) - df.sort_values(by=["depth", "model"], inplace=True) - df.to_csv(output_path, index=False) - print(f"📁 Results saved to: {output_path}") - From e5b75186a68a85413d97506cd7726ddf6235c4fb Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 8 Sep 2025 17:27:41 +0200 Subject: [PATCH 32/98] Fix dependencies --- pyproject.toml | 4 +- src/mqt/predictor/rl/actions.py | 100 ++++++++++--------- src/mqt/predictor/rl/helper.py | 2 + uv.lock | 170 ++++++++++++++++++++++++++------ 4 files changed, 196 insertions(+), 80 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bdcf1b7db..c3a370b03 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1; python_version < '3.13'", - "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'" + "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'", ] classifiers = [ @@ -253,5 +253,5 @@ ignore = ["GH200"] [tool.uv] override-dependencies = [ - "networkx==2.8.5; python_version < '3.13'", # qiskit-ibm-ai-local-transpiler requires this specific version of networkx + "networkx==2.8.5", ] diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 05bffd82a..510653781 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -78,7 +78,9 @@ ) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler.preset_passmanagers import common -from qiskit_ibm_transpiler.ai.routing import AIRouting + +if sys.version_info < (3, 13): + from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.rl.parsing import ( PreProcessTKETRoutingAfterQiskitLayout, @@ -627,53 +629,55 @@ def add_cregs_and_measurements( return qc -class SafeAIRouting(AIRouting): # type: ignore[misc] - """Custom AIRouting wrapper that removes classical registers before routing. - - This prevents failures in AIRouting when classical bits are present by - temporarily removing classical registers and measurements and restoring - them after routing is completed. - """ +if sys.version_info < (3, 13): - def run(self, dag: DAGCircuit) -> DAGCircuit: - """Run the routing pass on a DAGCircuit.""" - qc_orig = dag_to_circuit(dag) - # Extract classical registers and measurement instructions - cregs, measurements = extract_cregs_and_measurements(qc_orig) - # Remove cregs and measurements - qc_noclassical = remove_cregs(qc_orig) - # Convert back to dag and run routing (AIRouting) - dag_noclassical = circuit_to_dag(qc_noclassical) - dag_routed = super().run(dag_noclassical) - # Convert routed dag to circuit for restoration - qc_routed = dag_to_circuit(dag_routed) - # Build mapping from original qubits to qubits in routed circuit - final_layout = getattr(self, "property_set", {}).get("final_layout", None) - if final_layout is None and hasattr(dag_routed, "property_set"): - final_layout = dag_routed.property_set.get("final_layout", None) - - assert final_layout is not None, "final_layout is None — cannot map virtual qubits" - qubit_map = {} - for virt in qc_orig.qubits: - try: - phys = final_layout[virt] - except KeyError as err: - msg = f"Virtual qubit {virt} not found in final layout!" - raise RuntimeError(msg) from err - if isinstance(phys, int): - try: - qubit_map[virt] = qc_routed.qubits[phys] - except IndexError as err: - msg = f"Physical index {phys} is out of range in routed circuit!" - raise RuntimeError(msg) from err - else: + class SafeAIRouting(AIRouting): # type: ignore[misc] + """Custom AIRouting wrapper that removes classical registers before routing. + + This prevents failures in AIRouting when classical bits are present by + temporarily removing classical registers and measurements and restoring + them after routing is completed. + """ + + def run(self, dag: DAGCircuit) -> DAGCircuit: + """Run the routing pass on a DAGCircuit.""" + qc_orig = dag_to_circuit(dag) + # Extract classical registers and measurement instructions + cregs, measurements = extract_cregs_and_measurements(qc_orig) + # Remove cregs and measurements + qc_noclassical = remove_cregs(qc_orig) + # Convert back to dag and run routing (AIRouting) + dag_noclassical = circuit_to_dag(qc_noclassical) + dag_routed = super().run(dag_noclassical) + # Convert routed dag to circuit for restoration + qc_routed = dag_to_circuit(dag_routed) + # Build mapping from original qubits to qubits in routed circuit + final_layout = getattr(self, "property_set", {}).get("final_layout", None) + if final_layout is None and hasattr(dag_routed, "property_set"): + final_layout = dag_routed.property_set.get("final_layout", None) + + assert final_layout is not None, "final_layout is None — cannot map virtual qubits" + qubit_map = {} + for virt in qc_orig.qubits: try: - idx = qc_routed.qubits.index(phys) - except ValueError as err: - msg = f"Physical qubit {phys} not found in output circuit!" + phys = final_layout[virt] + except KeyError as err: + msg = f"Virtual qubit {virt} not found in final layout!" raise RuntimeError(msg) from err - qubit_map[virt] = qc_routed.qubits[idx] - # Restore classical registers and measurement instructions - qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) - # Return as dag - return circuit_to_dag(qc_final) + if isinstance(phys, int): + try: + qubit_map[virt] = qc_routed.qubits[phys] + except IndexError as err: + msg = f"Physical index {phys} is out of range in routed circuit!" + raise RuntimeError(msg) from err + else: + try: + idx = qc_routed.qubits.index(phys) + except ValueError as err: + msg = f"Physical qubit {phys} not found in output circuit!" + raise RuntimeError(msg) from err + qubit_map[virt] = qc_routed.qubits[idx] + # Restore classical registers and measurement instructions + qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) + # Return as dag + return circuit_to_dag(qc_final) diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 2226cc151..e5fe95d52 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -16,6 +16,7 @@ import numpy as np from qiskit import QuantumCircuit + from mqt.predictor.utils import calc_supermarq_features if TYPE_CHECKING: @@ -27,6 +28,7 @@ logger = logging.getLogger("mqt-predictor") + def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generator) -> tuple[QuantumCircuit, str]: """Returns a random quantum circuit from the training circuits folder. diff --git a/uv.lock b/uv.lock index 7f0a518db..8a844219a 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ ] [manifest] -overrides = [{ name = "networkx", marker = "python_full_version < '3.13'", specifier = "==2.8.5" }] +overrides = [{ name = "networkx", specifier = "==2.8.5" }] [[package]] name = "absl-py" @@ -910,16 +910,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/34/80/de3eb55eb581815342d097214bed4c59e806b05f1b3110df03b2280d6dfd/grpcio-1.74.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd3c71aeee838299c5887230b8a1822795325ddfea635edd82954c1eaa831e24", size = 4489214, upload-time = "2025-07-24T18:53:59.771Z" }, ] +[[package]] +name = "gymnasium" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", +] +dependencies = [ + { name = "cloudpickle", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "farama-notifications", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/12/1047b8fdbfcdce74022048d916e844ad7e6e1114d81d26a7aed657e3a76d/gymnasium-1.0.0.tar.gz", hash = "sha256:9d2b66f30c1b34fe3c2ce7fae65ecf365d0e9982d2b3d860235e773328a3b403", size = 821389, upload-time = "2024-10-08T10:01:02.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/85/f5039ce2df5f0789ff1240f08a59f3e8c92e4c5f99543b7aad7388532f7c/gymnasium-1.0.0-py3-none-any.whl", hash = "sha256:b6f40e1e24c5bd419361e1a5b86a9117d2499baecc3a660d44dfff4c465393ad", size = 958120, upload-time = "2024-10-08T10:01:00.337Z" }, +] + [[package]] name = "gymnasium" version = "1.2.0" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", + "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", +] dependencies = [ - { name = "cloudpickle" }, - { name = "farama-notifications" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, + { name = "cloudpickle", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "farama-notifications", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/17/c2a0e15c2cd5a8e788389b280996db927b923410de676ec5c7b2695e9261/gymnasium-1.2.0.tar.gz", hash = "sha256:344e87561012558f603880baf264ebc97f8a5c997a957b0c9f910281145534b0", size = 821142, upload-time = "2025-06-27T08:21:20.262Z" } wheels = [ @@ -1499,7 +1525,7 @@ name = "mqt-bench" version = "2.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "networkx", marker = "python_full_version < '3.13'" }, + { name = "networkx" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, { name = "qiskit", extra = ["qasm3-import"] }, @@ -1522,12 +1548,13 @@ dependencies = [ { name = "pytket-qiskit" }, { name = "qiskit" }, { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'" }, - { name = "qiskit-ibm-transpiler" }, + { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'" }, { name = "rich" }, - { name = "sb3-contrib" }, + { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "scikit-learn" }, { name = "tensorboard" }, - { name = "torch" }, + { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "tqdm" }, { name = "typing-extensions" }, ] @@ -1579,12 +1606,12 @@ requires-dist = [ { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = "!=1.3.2" }, { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = ">=0.3.2" }, - { name = "qiskit-ibm-transpiler", specifier = ">=0.11.1" }, + { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'", specifier = ">=0.11.1" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "tensorboard", specifier = ">=2.17.0" }, - { name = "torch", specifier = ">=2.7.1,<2.8.0" }, + { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.2.2,<2.3.0" }, { name = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, ] @@ -2484,7 +2511,7 @@ dependencies = [ { name = "graphviz" }, { name = "jinja2" }, { name = "lark" }, - { name = "networkx", marker = "python_full_version < '3.13'" }, + { name = "networkx" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, { name = "qwasm" }, @@ -2805,11 +2832,11 @@ name = "qiskit-ibm-transpiler" version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "backoff" }, + { name = "backoff", marker = "python_full_version < '3.13'" }, { name = "networkx", marker = "python_full_version < '3.13'" }, - { name = "qiskit" }, - { name = "qiskit-qasm3-import" }, - { name = "requests" }, + { name = "qiskit", marker = "python_full_version < '3.13'" }, + { name = "qiskit-qasm3-import", marker = "python_full_version < '3.13'" }, + { name = "requests", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8a/ac/d6f176107a0a07aeae583dbde3e7812cd31f670f0d285a0167ece51f040e/qiskit_ibm_transpiler-0.13.1.tar.gz", hash = "sha256:83631565b3adb6ce3825a82af8b6276e3f5e87d193c6efd01b7edae3bf56b31c", size = 46935, upload-time = "2025-07-21T09:42:49.367Z" } wheels = [ @@ -3054,12 +3081,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3e/79/9bdd52d2a33d468c81c1827de1b588080cb055d1d3561b194ab7bf2635b5/rustworkx-0.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:905df608843c32fa45ac023687769fe13056edf7584474c801d5c50705d76e9b", size = 1953559, upload-time = "2025-01-24T01:22:06.136Z" }, ] +[[package]] +name = "sb3-contrib" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", +] +dependencies = [ + { name = "stable-baselines3", version = "2.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/4e/dd31aba603634a7b9473b502fe85b694e4392c448eae0d345640b87211c2/sb3_contrib-2.4.0.tar.gz", hash = "sha256:a3709d97ddd529c45e3d56a5ae7e61a380bb2e11bacb9a3e6951ac0c481350ca", size = 89358, upload-time = "2024-11-18T10:20:53.214Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/de/33d3b00116488de9371a56009089ab408d949cda7057e2560c8efae810df/sb3_contrib-2.4.0-py3-none-any.whl", hash = "sha256:725d90157028a94c69804f2e7332128518fb7cbab39e7e141d2d0355547a72ab", size = 92752, upload-time = "2024-11-18T10:20:51.074Z" }, +] + [[package]] name = "sb3-contrib" version = "2.7.0" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", + "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", +] dependencies = [ - { name = "stable-baselines3" }, + { name = "stable-baselines3", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/23/2831ccecc8fc2fcda401804f3ed1dc3b81f7c4ad3cb32dc6b1cd79f91c49/sb3_contrib-2.7.0.tar.gz", hash = "sha256:87281ae64e6965e46ac24b58778241d2b07b29996044491267ed844c1a75acfe", size = 90289, upload-time = "2025-07-25T13:02:07.208Z" } wheels = [ @@ -3573,18 +3623,46 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/35/dd/698e7a1701908c62bfe371c197eba258182c3f41a3fc51ae588f8d46f3a7/sspilib-0.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:44b89f866e0d14c8393dbc5a49c59296dd7b83a7ca97a0f9d6bd49cc46a04498", size = 528415, upload-time = "2025-04-30T19:37:13.551Z" }, ] +[[package]] +name = "stable-baselines3" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", +] +dependencies = [ + { name = "cloudpickle", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "gymnasium", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "matplotlib", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "pandas", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/3b/13aacfe41697455f559449ad0dc5f51b4f30aed8fb000131225c64cc60f4/stable_baselines3-2.4.1.tar.gz", hash = "sha256:3bbf0e46b9aa4b1fd2696ff4c806ddb8ba719966ef0f71fba61f7a177e563c81", size = 212611, upload-time = "2025-01-07T13:22:42.455Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/96/04e1e987b5dd8ac0f192e74ad740fb5d72b4c9acd04f3ee13f5f9d6eacae/stable_baselines3-2.4.1-py3-none-any.whl", hash = "sha256:f74cde94a15c1d9d90343e73d790e1898b4c1cbb3f09eeeb580303d33f3fc4d6", size = 183963, upload-time = "2025-01-07T13:22:39.666Z" }, +] + [[package]] name = "stable-baselines3" version = "2.7.0" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", + "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", +] dependencies = [ - { name = "cloudpickle" }, - { name = "gymnasium" }, - { name = "matplotlib" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, + { name = "cloudpickle", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "gymnasium", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "matplotlib", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, - { name = "pandas" }, - { name = "torch" }, + { name = "pandas", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "torch", version = "2.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/cc/9a334071fae143bc7177e17a3191db83c1a4bf9038b09c4c5a34e427ca33/stable_baselines3-2.7.0.tar.gz", hash = "sha256:5258561e5becd15234274262cf09fcb9a082a73c2c67a85322f5652a05195ec4", size = 219012, upload-time = "2025-07-25T09:54:35.113Z" } wheels = [ @@ -3754,15 +3832,47 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, ] +[[package]] +name = "torch" +version = "2.2.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", +] +dependencies = [ + { name = "filelock", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "fsspec", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "jinja2", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "networkx", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "sympy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/55/7192974ab13e5e5577f45d14ce70d42f5a9a686b4f57bbe8c9ab45c4a61a/torch-2.2.2-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:b2e2200b245bd9f263a0d41b6a2dab69c4aca635a01b30cca78064b0ef5b109e", size = 150788930, upload-time = "2024-03-27T21:08:09.98Z" }, + { url = "https://files.pythonhosted.org/packages/33/6b/21496316c9b8242749ee2a9064406271efdf979e91d440e8a3806b5e84bf/torch-2.2.2-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:877b3e6593b5e00b35bbe111b7057464e76a7dd186a287280d941b564b0563c2", size = 59707286, upload-time = "2024-03-27T21:10:28.154Z" }, + { url = "https://files.pythonhosted.org/packages/3f/14/e105b8ef6d324e789c1589e95cb0ab63f3e07c2216d68b1178b7c21b7d2a/torch-2.2.2-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:95b9b44f3bcebd8b6cd8d37ec802048c872d9c567ba52c894bba90863a439059", size = 150796474, upload-time = "2024-03-27T21:09:29.142Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/18b9c16c18a77755e7f15173821c7100f11e6b3b7717bea8d729bdeb92c0/torch-2.2.2-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:49aa4126ede714c5aeef7ae92969b4b0bbe67f19665106463c39f22e0a1860d1", size = 59714938, upload-time = "2024-03-27T21:09:34.709Z" }, + { url = "https://files.pythonhosted.org/packages/79/78/29dcab24a344ffd9ee9549ec0ab2c7885c13df61cde4c65836ee275efaeb/torch-2.2.2-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:eb4d6e9d3663e26cd27dc3ad266b34445a16b54908e74725adb241aa56987533", size = 150797270, upload-time = "2024-03-27T21:08:29.623Z" }, + { url = "https://files.pythonhosted.org/packages/4a/0e/e4e033371a7cba9da0db5ccb507a9174e41b9c29189a932d01f2f61ecfc0/torch-2.2.2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:bf9558da7d2bf7463390b3b2a61a6a3dbb0b45b161ee1dd5ec640bf579d479fc", size = 59678388, upload-time = "2024-03-27T21:08:35.869Z" }, +] + [[package]] name = "torch" version = "2.7.1" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13'", + "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", + "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", + "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", +] dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx", marker = "python_full_version < '3.13'" }, + { name = "filelock", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "fsspec", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "jinja2", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "networkx", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, @@ -3777,10 +3887,10 @@ dependencies = [ { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "setuptools", marker = "python_full_version >= '3.12'" }, - { name = "sympy" }, + { name = "setuptools", marker = "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, + { name = "sympy", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/6a/27/2e06cb52adf89fe6e020963529d17ed51532fc73c1e6d1b18420ef03338c/torch-2.7.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a103b5d782af5bd119b81dbcc7ffc6fa09904c423ff8db397a1e6ea8fd71508f", size = 99089441, upload-time = "2025-06-04T17:38:48.268Z" }, From 907ce2b027cbc232a0a0bab82be921c1419f54e0 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 8 Sep 2025 17:56:44 +0200 Subject: [PATCH 33/98] Fix dependencies --- pyproject.toml | 2 +- uv.lock | 58 +++++++++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c3a370b03..8ee0e59ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 - "torch>=2.2.2,<2.3.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. + "torch>=2.8.0,<2.9.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.11.1; python_version < '3.13'", "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'", diff --git a/uv.lock b/uv.lock index 8a844219a..5f5b8cbb2 100644 --- a/uv.lock +++ b/uv.lock @@ -1554,7 +1554,7 @@ dependencies = [ { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "scikit-learn" }, { name = "tensorboard" }, - { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "torch", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "tqdm" }, { name = "typing-extensions" }, ] @@ -1611,7 +1611,7 @@ requires-dist = [ { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "tensorboard", specifier = ">=2.17.0" }, - { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.2.2,<2.3.0" }, + { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.8.0,<2.9.0" }, { name = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, ] @@ -3638,7 +3638,7 @@ dependencies = [ { name = "matplotlib", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "pandas", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "torch", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fa/3b/13aacfe41697455f559449ad0dc5f51b4f30aed8fb000131225c64cc60f4/stable_baselines3-2.4.1.tar.gz", hash = "sha256:3bbf0e46b9aa4b1fd2696ff4c806ddb8ba719966ef0f71fba61f7a177e563c81", size = 212611, upload-time = "2025-01-07T13:22:42.455Z" } wheels = [ @@ -3832,32 +3832,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, ] -[[package]] -name = "torch" -version = "2.2.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", -] -dependencies = [ - { name = "filelock", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "fsspec", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "jinja2", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "networkx", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "sympy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "typing-extensions", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/55/7192974ab13e5e5577f45d14ce70d42f5a9a686b4f57bbe8c9ab45c4a61a/torch-2.2.2-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:b2e2200b245bd9f263a0d41b6a2dab69c4aca635a01b30cca78064b0ef5b109e", size = 150788930, upload-time = "2024-03-27T21:08:09.98Z" }, - { url = "https://files.pythonhosted.org/packages/33/6b/21496316c9b8242749ee2a9064406271efdf979e91d440e8a3806b5e84bf/torch-2.2.2-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:877b3e6593b5e00b35bbe111b7057464e76a7dd186a287280d941b564b0563c2", size = 59707286, upload-time = "2024-03-27T21:10:28.154Z" }, - { url = "https://files.pythonhosted.org/packages/3f/14/e105b8ef6d324e789c1589e95cb0ab63f3e07c2216d68b1178b7c21b7d2a/torch-2.2.2-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:95b9b44f3bcebd8b6cd8d37ec802048c872d9c567ba52c894bba90863a439059", size = 150796474, upload-time = "2024-03-27T21:09:29.142Z" }, - { url = "https://files.pythonhosted.org/packages/96/23/18b9c16c18a77755e7f15173821c7100f11e6b3b7717bea8d729bdeb92c0/torch-2.2.2-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:49aa4126ede714c5aeef7ae92969b4b0bbe67f19665106463c39f22e0a1860d1", size = 59714938, upload-time = "2024-03-27T21:09:34.709Z" }, - { url = "https://files.pythonhosted.org/packages/79/78/29dcab24a344ffd9ee9549ec0ab2c7885c13df61cde4c65836ee275efaeb/torch-2.2.2-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:eb4d6e9d3663e26cd27dc3ad266b34445a16b54908e74725adb241aa56987533", size = 150797270, upload-time = "2024-03-27T21:08:29.623Z" }, - { url = "https://files.pythonhosted.org/packages/4a/0e/e4e033371a7cba9da0db5ccb507a9174e41b9c29189a932d01f2f61ecfc0/torch-2.2.2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:bf9558da7d2bf7463390b3b2a61a6a3dbb0b45b161ee1dd5ec640bf579d479fc", size = 59678388, upload-time = "2024-03-27T21:08:35.869Z" }, -] - [[package]] name = "torch" version = "2.7.1" @@ -3915,6 +3889,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b1/29/beb45cdf5c4fc3ebe282bf5eafc8dfd925ead7299b3c97491900fe5ed844/torch-2.7.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:988b0cbc4333618a1056d2ebad9eb10089637b659eb645434d0809d8d937b946", size = 68645708, upload-time = "2025-06-04T17:34:39.852Z" }, ] +[[package]] +name = "torch" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", + "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", +] +dependencies = [ + { name = "filelock", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "fsspec", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "jinja2", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "networkx", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "setuptools", marker = "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "sympy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/d6/e6d4c57e61c2b2175d3aafbfb779926a2cfd7c32eeda7c543925dceec923/torch-2.8.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a3f16a58a9a800f589b26d47ee15aca3acf065546137fc2af039876135f4c760", size = 73611154, upload-time = "2025-08-06T14:53:10.919Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5e/05a5c46085d9b97e928f3f037081d3d2b87fb4b4195030fc099aaec5effc/torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:5ae0524688fb6707c57a530c2325e13bb0090b745ba7b4a2cd6a3ce262572916", size = 73621174, upload-time = "2025-08-06T14:53:25.44Z" }, + { url = "https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:619c2869db3ada2c0105487ba21b5008defcc472d23f8b80ed91ac4a380283b0", size = 73630478, upload-time = "2025-08-06T14:53:57.144Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/8b7b13bba430f5e21d77708b616f767683629fc4f8037564a177d20f90ed/torch-2.8.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:1a62a1ec4b0498930e2543535cf70b1bef8c777713de7ceb84cd79115f553767", size = 73915128, upload-time = "2025-08-06T14:54:34.769Z" }, + { url = "https://files.pythonhosted.org/packages/04/6e/650bb7f28f771af0cb791b02348db8b7f5f64f40f6829ee82aa6ce99aabe/torch-2.8.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:7b677e17f5a3e69fdef7eb3b9da72622f8d322692930297e4ccb52fefc6c8211", size = 73632395, upload-time = "2025-08-06T14:55:28.645Z" }, +] + [[package]] name = "tornado" version = "6.5.1" From 70dcd7d2b22a24e3a1e1e2dc3123e899741a0e92 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 8 Sep 2025 19:41:08 +0200 Subject: [PATCH 34/98] Fix dependencies --- pyproject.toml | 1 + uv.lock | 44 ++++++++++---------------------------------- 2 files changed, 11 insertions(+), 34 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8ee0e59ce..8bf021e36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ dependencies = [ "pytket>=1.29.0", # lowest version that supports the used pytket AutoRebase pass instead of auto_rebase "pytket_qiskit>=0.71.0", "sb3_contrib>=2.0.0", + "stable-baselines3>=2.7.0", "tqdm>=4.66.0", "rich>=12.6.0", "scikit-learn>=1.5.1", diff --git a/uv.lock b/uv.lock index 5f5b8cbb2..a0b74975a 100644 --- a/uv.lock +++ b/uv.lock @@ -1553,6 +1553,7 @@ dependencies = [ { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, { name = "scikit-learn" }, + { name = "stable-baselines3" }, { name = "tensorboard" }, { name = "torch", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "tqdm" }, @@ -1610,6 +1611,7 @@ requires-dist = [ { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, + { name = "stable-baselines3", specifier = ">=2.7.0" }, { name = "tensorboard", specifier = ">=2.17.0" }, { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.8.0,<2.9.0" }, { name = "tqdm", specifier = ">=4.66.0" }, @@ -3091,7 +3093,7 @@ resolution-markers = [ "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", ] dependencies = [ - { name = "stable-baselines3", version = "2.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, + { name = "stable-baselines3", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/4e/dd31aba603634a7b9473b502fe85b694e4392c448eae0d345640b87211c2/sb3_contrib-2.4.0.tar.gz", hash = "sha256:a3709d97ddd529c45e3d56a5ae7e61a380bb2e11bacb9a3e6951ac0c481350ca", size = 89358, upload-time = "2024-11-18T10:20:53.214Z" } wheels = [ @@ -3109,7 +3111,7 @@ resolution-markers = [ "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", ] dependencies = [ - { name = "stable-baselines3", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "stable-baselines3", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/23/2831ccecc8fc2fcda401804f3ed1dc3b81f7c4ad3cb32dc6b1cd79f91c49/sb3_contrib-2.7.0.tar.gz", hash = "sha256:87281ae64e6965e46ac24b58778241d2b07b29996044491267ed844c1a75acfe", size = 90289, upload-time = "2025-07-25T13:02:07.208Z" } wheels = [ @@ -3623,46 +3625,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/35/dd/698e7a1701908c62bfe371c197eba258182c3f41a3fc51ae588f8d46f3a7/sspilib-0.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:44b89f866e0d14c8393dbc5a49c59296dd7b83a7ca97a0f9d6bd49cc46a04498", size = 528415, upload-time = "2025-04-30T19:37:13.551Z" }, ] -[[package]] -name = "stable-baselines3" -version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", -] -dependencies = [ - { name = "cloudpickle", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "gymnasium", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "matplotlib", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "pandas", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, - { name = "torch", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fa/3b/13aacfe41697455f559449ad0dc5f51b4f30aed8fb000131225c64cc60f4/stable_baselines3-2.4.1.tar.gz", hash = "sha256:3bbf0e46b9aa4b1fd2696ff4c806ddb8ba719966ef0f71fba61f7a177e563c81", size = 212611, upload-time = "2025-01-07T13:22:42.455Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/96/04e1e987b5dd8ac0f192e74ad740fb5d72b4c9acd04f3ee13f5f9d6eacae/stable_baselines3-2.4.1-py3-none-any.whl", hash = "sha256:f74cde94a15c1d9d90343e73d790e1898b4c1cbb3f09eeeb580303d33f3fc4d6", size = 183963, upload-time = "2025-01-07T13:22:39.666Z" }, -] - [[package]] name = "stable-baselines3" version = "2.7.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", - "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", - "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", -] dependencies = [ - { name = "cloudpickle", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "cloudpickle" }, + { name = "gymnasium", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "gymnasium", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "matplotlib", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')" }, + { name = "matplotlib" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, - { name = "pandas", marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "pandas" }, { name = "torch", version = "2.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, + { name = "torch", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/cc/9a334071fae143bc7177e17a3191db83c1a4bf9038b09c4c5a34e427ca33/stable_baselines3-2.7.0.tar.gz", hash = "sha256:5258561e5becd15234274262cf09fcb9a082a73c2c67a85322f5652a05195ec4", size = 219012, upload-time = "2025-07-25T09:54:35.113Z" } wheels = [ From eb27098628671cda269bbec755ebcf9ab90183fd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 17:55:02 +0000 Subject: [PATCH 35/98] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uv.lock | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/uv.lock b/uv.lock index 5294eb3f5..a0b74975a 100644 --- a/uv.lock +++ b/uv.lock @@ -3096,7 +3096,7 @@ dependencies = [ { name = "stable-baselines3", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/4e/dd31aba603634a7b9473b502fe85b694e4392c448eae0d345640b87211c2/sb3_contrib-2.4.0.tar.gz", hash = "sha256:a3709d97ddd529c45e3d56a5ae7e61a380bb2e11bacb9a3e6951ac0c481350ca", size = 89358, upload-time = "2024-11-18T10:20:53.214Z" } -wheels = [ +wheels = [ { url = "https://files.pythonhosted.org/packages/50/de/33d3b00116488de9371a56009089ab408d949cda7057e2560c8efae810df/sb3_contrib-2.4.0-py3-none-any.whl", hash = "sha256:725d90157028a94c69804f2e7332128518fb7cbab39e7e141d2d0355547a72ab", size = 92752, upload-time = "2024-11-18T10:20:51.074Z" }, ] @@ -4014,4 +4014,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50e wheels = [ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, ] - From 2688c0e45d6834623f2e2d190ba27a5af06aad9b Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 8 Sep 2025 17:56:44 +0200 Subject: [PATCH 36/98] Fix dependencies Fix dependencies Fix dependencies Update Dependencies Update test command Fix multiprocessing on Python 3.13 Fix multiprocessing on Python 3.13 --- noxfile.py | 1 + pyproject.toml | 4 +-- src/mqt/predictor/ml/predictor.py | 48 ++++++++++++++++++++++--------- uv.lock | 4 +-- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/noxfile.py b/noxfile.py index 9e13b37f9..3b1876a5c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -64,6 +64,7 @@ def _run_tests( "--no-dev", "--group", "test", + "--frozen", *install_args, "pytest", *pytest_run_args, diff --git a/pyproject.toml b/pyproject.toml index 8bf021e36..a505249fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,8 +47,8 @@ dependencies = [ "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 "torch>=2.8.0,<2.9.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler>=0.11.1; python_version < '3.13'", - "qiskit-ibm-ai-local-transpiler>=0.3.2; python_version < '3.13'", + "qiskit-ibm-transpiler==0.13.1; python_version < '3.13'", + "qiskit-ibm-ai-local-transpiler==0.4.2; python_version < '3.13'", ] classifiers = [ diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 3f0ec5497..0a7a62382 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -61,6 +61,8 @@ logger = logging.getLogger("mqt-predictor") +NO_PARALLEL = sys.platform == "win32" and sys.version_info >= (3, 13) + def setup_device_predictor( devices: list[Target], @@ -227,12 +229,20 @@ def compile_training_circuits( with zipfile.ZipFile(str(path_zip), "r") as zip_ref: zip_ref.extractall(path_uncompiled_circuits) - Parallel(n_jobs=num_workers, verbose=100)( - delayed(self._compile_all_circuits_devicewise)( - device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level + # On Windows + Python 3.13, joblib's default "loky" process backend is broken + # (missing `_posixsubprocess`). Fall back to no multiprocessing. + if NO_PARALLEL: + for device in self.devices: + self._compile_all_circuits_devicewise( + device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level + ) + else: + Parallel(n_jobs=num_workers, verbose=100)( + delayed(self._compile_all_circuits_devicewise)( + device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level + ) + for device in self.devices ) - for device in self.devices - ) def generate_training_data( self, @@ -267,15 +277,27 @@ def generate_training_data( names_list = [] scores_list = [] - results = Parallel(n_jobs=num_workers, verbose=100)( - delayed(self._generate_training_sample)( - filename.name, - path_uncompiled_circuits, - path_compiled_circuits, - logger.level, + if NO_PARALLEL: + results = Parallel(n_jobs=1, verbose=100)( + delayed(self._generate_training_sample)( + filename.name, + path_uncompiled_circuits, + path_compiled_circuits, + logger.level, + ) + for filename in path_uncompiled_circuits.glob("*.qasm") ) - for filename in path_uncompiled_circuits.glob("*.qasm") - ) + else: + results = Parallel(n_jobs=num_workers, verbose=100)( + delayed(self._generate_training_sample)( + filename.name, + path_uncompiled_circuits, + path_compiled_circuits, + logger.level, + ) + for filename in path_uncompiled_circuits.glob("*.qasm") + ) + for sample in results: training_sample, circuit_name, scores = sample if all(score == -1 for score in scores): diff --git a/uv.lock b/uv.lock index a0b74975a..9c915f7fe 100644 --- a/uv.lock +++ b/uv.lock @@ -1606,8 +1606,8 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = "!=1.3.2" }, - { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = ">=0.3.2" }, - { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'", specifier = ">=0.11.1" }, + { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.4.2" }, + { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.13.1" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, From 840d23da68c610fa7d89ffb61551d1bfdbc5f28a Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Tue, 9 Sep 2025 17:52:47 +0200 Subject: [PATCH 37/98] Fix multiprocessing on Python 3.13 Fix runtime warning error --- pyproject.toml | 2 ++ src/mqt/predictor/ml/predictor.py | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a505249fc..262e5d5a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -130,6 +130,8 @@ filterwarnings = [ 'ignore:.*qiskit.providers.models is deprecated since Qiskit 1.2*:DeprecationWarning:', 'ignore:.*The class ``qiskit.qobj.*`` is deprecated as of Qiskit 1.3.*:DeprecationWarning:', 'ignore:.*The property ``qiskit.circuit.instruction.Instruction.*`` is deprecated as of qiskit 1.3.0.*:DeprecationWarning:', + 'ignore:.*Timeout is not supported on Windows\\.:RuntimeWarning', + ] [tool.coverage] diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 0a7a62382..b05c51efd 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -427,7 +427,10 @@ def train_random_forest_model( if not training_data: training_data = self._get_prepared_training_data() num_cv = min(len(training_data.y_train), 5) - mdl = GridSearchCV(mdl, tree_param, cv=num_cv, n_jobs=8).fit(training_data.X_train, training_data.y_train) + if NO_PARALLEL: + mdl = GridSearchCV(mdl, tree_param, cv=num_cv, n_jobs=1).fit(training_data.X_train, training_data.y_train) + else: + mdl = GridSearchCV(mdl, tree_param, cv=num_cv, n_jobs=8).fit(training_data.X_train, training_data.y_train) joblib_dump(mdl, save_mdl_path) logger.info("Random Forest model is trained and saved.") From ac406ac1903fe372989d6f5152401baff20d6bec Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Tue, 9 Sep 2025 21:35:21 +0200 Subject: [PATCH 38/98] Fix timeout watcher Add comments Update actions --- pyproject.toml | 4 +- src/mqt/predictor/ml/predictor.py | 54 ++++++++------------- src/mqt/predictor/rl/actions.py | 41 ++++++++++++---- src/mqt/predictor/rl/predictorenv.py | 71 +++++++++++++--------------- src/mqt/predictor/utils.py | 3 +- 5 files changed, 87 insertions(+), 86 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 262e5d5a0..1fbb96977 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 "torch>=2.8.0,<2.9.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler==0.13.1; python_version < '3.13'", + "qiskit-ibm-transpiler==0.13.1; python_version < '3.13'", # Do not support python 3.13 yet "qiskit-ibm-ai-local-transpiler==0.4.2; python_version < '3.13'", ] @@ -256,5 +256,5 @@ ignore = ["GH200"] [tool.uv] override-dependencies = [ - "networkx==2.8.5", + "networkx==2.8.5", # Required by `qiskit-ibm-transpiler` ] diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index b05c51efd..c1d6f1b15 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -231,18 +231,13 @@ def compile_training_circuits( # On Windows + Python 3.13, joblib's default "loky" process backend is broken # (missing `_posixsubprocess`). Fall back to no multiprocessing. - if NO_PARALLEL: - for device in self.devices: - self._compile_all_circuits_devicewise( - device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level - ) - else: - Parallel(n_jobs=num_workers, verbose=100)( - delayed(self._compile_all_circuits_devicewise)( - device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level - ) - for device in self.devices + num_jobs = 1 if NO_PARALLEL else num_workers + Parallel(n_jobs=num_jobs, verbose=100)( + delayed(self._compile_all_circuits_devicewise)( + device, timeout, path_uncompiled_circuits, path_compiled_circuits, logger.level ) + for device in self.devices + ) def generate_training_data( self, @@ -277,26 +272,16 @@ def generate_training_data( names_list = [] scores_list = [] - if NO_PARALLEL: - results = Parallel(n_jobs=1, verbose=100)( - delayed(self._generate_training_sample)( - filename.name, - path_uncompiled_circuits, - path_compiled_circuits, - logger.level, - ) - for filename in path_uncompiled_circuits.glob("*.qasm") - ) - else: - results = Parallel(n_jobs=num_workers, verbose=100)( - delayed(self._generate_training_sample)( - filename.name, - path_uncompiled_circuits, - path_compiled_circuits, - logger.level, - ) - for filename in path_uncompiled_circuits.glob("*.qasm") + num_jobs = 1 if NO_PARALLEL else num_workers + results = Parallel(n_jobs=num_jobs, verbose=100)( + delayed(self._generate_training_sample)( + filename.name, + path_uncompiled_circuits, + path_compiled_circuits, + logger.level, ) + for filename in path_uncompiled_circuits.glob("*.qasm") + ) for sample in results: training_sample, circuit_name, scores = sample @@ -427,11 +412,10 @@ def train_random_forest_model( if not training_data: training_data = self._get_prepared_training_data() num_cv = min(len(training_data.y_train), 5) - if NO_PARALLEL: - mdl = GridSearchCV(mdl, tree_param, cv=num_cv, n_jobs=1).fit(training_data.X_train, training_data.y_train) - else: - mdl = GridSearchCV(mdl, tree_param, cv=num_cv, n_jobs=8).fit(training_data.X_train, training_data.y_train) - + num_jobs = 1 if NO_PARALLEL else 8 + mdl = GridSearchCV(mdl, tree_param, cv=num_cv, n_jobs=num_jobs).fit( + training_data.X_train, training_data.y_train + ) joblib_dump(mdl, save_mdl_path) logger.info("Random Forest model is trained and saved.") diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 510653781..c83bcf766 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -135,7 +135,7 @@ class Action: ] ) stochastic: bool | None = False - preserve: bool | None = False + preserve_layout: bool | None = False @dataclass @@ -188,11 +188,22 @@ def remove_action(name: str) -> None: register_action( - DeviceDependentAction( + DeviceIndependentAction( "Optimize1qGatesDecomposition", CompilationOrigin.QISKIT, PassType.OPT, - preserve=True, + # If no basis_gates are passed, fallback 1q Euler gates: + # https://github.com/Qiskit/qiskit/blob/main/qiskit/synthesis/one_qubit/one_qubit_decompose.py#L46 + [Optimize1qGatesDecomposition()], + ) +) + +register_action( + DeviceDependentAction( + "Optimize1qGatesDecomposition_preserve", + CompilationOrigin.QISKIT, + PassType.OPT, + preserve_layout=True, transpile_pass=lambda device: [Optimize1qGatesDecomposition(basis=device.operation_names)], ) ) @@ -203,7 +214,7 @@ def remove_action(name: str) -> None: CompilationOrigin.QISKIT, PassType.OPT, [CommutativeCancellation()], - preserve=True, + preserve_layout=True, ) ) @@ -213,7 +224,7 @@ def remove_action(name: str) -> None: CompilationOrigin.QISKIT, PassType.OPT, [CommutativeInverseCancellation()], - preserve=True, + preserve_layout=True, ) ) @@ -223,7 +234,7 @@ def remove_action(name: str) -> None: CompilationOrigin.QISKIT, PassType.OPT, [RemoveDiagonalGatesBeforeMeasure()], - preserve=True, + preserve_layout=True, ) ) @@ -248,7 +259,7 @@ def remove_action(name: str) -> None: (SXGate(), SXdgGate()), ]) ], - preserve=True, + preserve_layout=True, ) ) @@ -262,16 +273,27 @@ def remove_action(name: str) -> None: ) register_action( - DeviceDependentAction( + DeviceIndependentAction( "Opt2qBlocks", CompilationOrigin.QISKIT, PassType.OPT, + # If no arguments is passed, decompose to U(θ, φ, λ) and CX + # https://github.com/Qiskit/qiskit/blob/stable/2.1/qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py + [Collect2qBlocks(), ConsolidateBlocks(), UnitarySynthesis()], + ) +) + +register_action( + DeviceDependentAction( + "Opt2qBlocks_preserve", + CompilationOrigin.QISKIT, + PassType.OPT, transpile_pass=lambda native_gate, coupling_map: [ Collect2qBlocks(), ConsolidateBlocks(basis_gates=native_gate), UnitarySynthesis(basis_gates=native_gate, coupling_map=coupling_map), ], - preserve=True, + preserve_layout=True, ) ) @@ -336,6 +358,7 @@ def remove_action(name: str) -> None: MinimumPoint(["depth", "size"], "optimization_loop"), ], do_while=lambda property_set: not property_set["optimization_loop_minimum_point"], + preserve_layout=True, ) ) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 01ae26ee1..830a85293 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -113,7 +113,7 @@ def __init__( self.actions_mapping_indices = [] self.actions_opt_indices = [] self.actions_final_optimization_indices = [] - self.actions_preserving_indices = [] + self.actions_mapping_preserving_indices = [] self.used_actions: list[str] = [] self.device = device @@ -134,7 +134,7 @@ def __init__( self.action_set[index] = elem self.actions_opt_indices.append(index) if getattr(elem, "preserve", False): - self.actions_preserving_indices.append(index) + self.actions_mapping_preserving_indices.append(index) index += 1 for elem in action_dict[PassType.LAYOUT]: self.action_set[index] = elem @@ -241,26 +241,16 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any def calculate_reward(self, qc: QuantumCircuit | None = None) -> float: """Calculates and returns the reward for the current state.""" - if qc is None: - if self.reward_function == "expected_fidelity": - return expected_fidelity(self.state, self.device) - if self.reward_function == "estimated_success_probability": - return estimated_success_probability(self.state, self.device) - if self.reward_function == "estimated_hellinger_distance": - return estimated_hellinger_distance(self.state, self.device, self.hellinger_model) - if self.reward_function == "critical_depth": - return crit_depth(self.state) - assert_never(self.state) - else: - if self.reward_function == "expected_fidelity": - return expected_fidelity(qc, self.device) - if self.reward_function == "estimated_success_probability": - return estimated_success_probability(qc, self.device) - if self.reward_function == "estimated_hellinger_distance": - return estimated_hellinger_distance(qc, self.device, self.hellinger_model) - if self.reward_function == "critical_depth": - return crit_depth(qc) - assert_never(self.state) + circuit = self.state if qc is None else qc + if self.reward_function == "expected_fidelity": + return expected_fidelity(circuit, self.device) + if self.reward_function == "estimated_success_probability": + return estimated_success_probability(circuit, self.device) + if self.reward_function == "estimated_hellinger_distance": + return estimated_hellinger_distance(circuit, self.device, self.hellinger_model) + if self.reward_function == "critical_depth": + return crit_depth(circuit) + assert_never(circuit) def render(self) -> None: """Renders the current state.""" @@ -310,7 +300,7 @@ def action_masks(self) -> list[bool]: """Returns a list of valid actions for the current state.""" action_mask = [action in self.valid_actions for action in self.action_set] - # # it is not clear how tket will handle the layout, so we remove all actions that are from "origin"=="tket" if a layout is set + # it is not clear how tket will handle the layout, so we remove all actions that are from "origin"=="tket" if a layout is set if self.layout is not None: action_mask = [ action_mask[i] and self.action_set[i].origin != CompilationOrigin.TKET for i in range(len(action_mask)) @@ -620,30 +610,35 @@ def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCirc def determine_valid_actions_for_state(self) -> list[int]: """Determines and returns the valid actions for the current state.""" + # Check if all gates are native to the device check_nat_gates = GatesInBasis(basis_gates=self.device.operation_names) check_nat_gates(self.state) only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] - + # Check if the circuit is mapped to the device coupling graph check_mapping = CheckMap(coupling_map=CouplingMap(self.device.build_coupling_map())) check_mapping(self.state) mapped = check_mapping.property_set["is_swap_mapped"] - if not only_nat_gates: # not native gates yet + if not only_nat_gates: + # Circuit still has non-native gates if not mapped: + # Allow synthesis and optimization actions return self.actions_synthesis_indices + self.actions_opt_indices - return self.actions_synthesis_indices + self.actions_preserving_indices - - if mapped and self.layout is not None: # The circuit is correctly mapped - return [ - self.action_terminate_index, - *self.actions_preserving_indices, - *self.actions_final_optimization_indices, - ] - + # Allow synthesis and mapping-preserving actions (to not ) + return self.actions_synthesis_indices + self.actions_mapping_preserving_indices + # Circuit has only native gates + if mapped: + if self.layout is not None: + # The circuits is correctly compiled, terminate or do further mapping-preserving optimizations + return [ + self.action_terminate_index, + *self.actions_mapping_preserving_indices, + *self.actions_final_optimization_indices, + ] + # No layout is assigned, assign a valid layout + return self.actions_mapping_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices if self.layout is not None: - # The circuit is not yet mapped but a layout is set. + # Not mapped yet but a layout is assigned in the last step, do routing return self.actions_routing_indices - # The circuit already fulfils coupling map but no layout is assigned, could explore better layout options - if mapped: - return self.actions_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices + # Not mapped yet, do general optimizations/layout/mapping return self.actions_opt_indices + self.actions_layout_indices + self.actions_mapping_indices diff --git a/src/mqt/predictor/utils.py b/src/mqt/predictor/utils.py index faf3d0596..4112dfb13 100644 --- a/src/mqt/predictor/utils.py +++ b/src/mqt/predictor/utils.py @@ -15,7 +15,6 @@ import sys from dataclasses import dataclass from typing import TYPE_CHECKING, Any -from warnings import warn import networkx as nx import numpy as np @@ -52,7 +51,7 @@ def timeout_watcher( TimeoutExceptionError: If the function call exceeds the timeout limit. """ if sys.platform == "win32": - warn("Timeout is not supported on Windows.", category=RuntimeWarning, stacklevel=2) + logger.info("Timeout is not supported on Windows; running without timeout.") return func(*args) if isinstance(args, tuple | list) else func(args) class TimeoutExceptionError(Exception): # Custom exception class From 97c81bb3bf08beb8c66e276f21bfb6392e1b2f7e Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 15 Sep 2025 15:52:16 +0200 Subject: [PATCH 39/98] Update comments and restructure Adjust comments --- src/mqt/predictor/rl/parsing.py | 28 +++++++++++++++ src/mqt/predictor/rl/predictorenv.py | 53 +++++++++------------------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/mqt/predictor/rl/parsing.py b/src/mqt/predictor/rl/parsing.py index 552817556..816e7aa48 100644 --- a/src/mqt/predictor/rl/parsing.py +++ b/src/mqt/predictor/rl/parsing.py @@ -241,3 +241,31 @@ def postprocess_vf2postlayout( altered_qc = apply_layout(qc) return altered_qc, apply_layout + + +def prepare_noise_data(device: Target) -> tuple[dict[Node, float], dict[tuple[Node, Node], float], dict[Node, float]]: + """Extract node, edge, and readout errors from the device target.""" + node_err: dict[Node, float] = {} + edge_err: dict[tuple[Node, Node], float] = {} + readout_err: dict[Node, float] = {} + + # Collect errors from operation properties + for op_name in device.operation_names: + inst_props = device[op_name] + for qtuple, props in inst_props.items(): + if props is None or not hasattr(props, "error") or props.error is None: + continue + if len(qtuple) == 1: # single-qubit op + q = qtuple[0] + node_err[Node(q)] = props.error + elif len(qtuple) == 2: # two-qubit op + q1, q2 = qtuple + edge_err[Node(q1), Node(q2)] = props.error + + # Collect readout errors + if "measure" in device: + for (q,), props in device["measure"].items(): + if props is not None and hasattr(props, "error") and props.error is not None: + readout_err[Node(q)] = props.error + + return node_err, edge_err, readout_err diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 830a85293..8e2b5e1d4 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -78,6 +78,7 @@ final_layout_bqskit_to_qiskit, final_layout_pytket_to_qiskit, postprocess_vf2postlayout, + prepare_noise_data, ) logger = logging.getLogger("mqt-predictor") @@ -430,7 +431,7 @@ def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCirc max_iteration=self.max_iter, ) else: - if action.name in ["QiskitO3", "Opt2qBlocks"] and isinstance(action, DeviceDependentAction): + if action.name in ["QiskitO3", "Opt2qBlocks_preserve"] and isinstance(action, DeviceDependentAction): passes = action.transpile_pass( self.device.operation_names, CouplingMap(self.device.build_coupling_map()) if self.layout else None, @@ -494,32 +495,9 @@ def _handle_qiskit_layout_postprocessing( def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircuit: tket_qc = qiskit_to_tk(self.state, preserve_param_uuid=True) if action.name == "NoiseAwarePlacement": + # Handle NoiseAwarePlacement separately (requires error data) if self.node_err is None or self.edge_err is None or self.readout_err is None: - node_err: dict[Node, float] = {} - edge_err: dict[tuple[Node, Node], float] = {} - readout_err: dict[Node, float] = {} - - # Calculate avg node, edge and readout error - for op_name in self.device.operation_names: - inst_props = self.device[op_name] # this is a dict-like object - for qtuple, props in inst_props.items(): - if props is None or not hasattr(props, "error") or props.error is None: - continue - if len(qtuple) == 1: # single-qubit op - q = qtuple[0] - node_err[Node(q)] = props.error - elif len(qtuple) == 2: # two-qubit op - q1, q2 = qtuple - edge_err[Node(q1), Node(q2)] = props.error - - # Readout errors (they are in the Target under "measure") - if "measure" in self.device: - for (q,), props in self.device["measure"].items(): - if props is not None and hasattr(props, "error") and props.error is not None: - readout_err[Node(q)] = props.error - self.node_err = node_err - self.edge_err = edge_err - self.readout_err = readout_err + self.node_err, self.edge_err, self.readout_err = prepare_noise_data(self.device) assert callable(action.transpile_pass) transpile_pass = action.transpile_pass(self.device, self.node_err, self.edge_err, self.readout_err) else: @@ -527,6 +505,7 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass ) assert isinstance(transpile_pass, list) + # Map TKET placement into a Qiskit layout if action_index in self.actions_layout_indices: try: placement = transpile_pass[0].get_placement_map(tket_qc) @@ -609,36 +588,36 @@ def _apply_bqskit_action(self, action: Action, action_index: int) -> QuantumCirc return bqskit_to_qiskit(bqskit_compiled_qc) def determine_valid_actions_for_state(self) -> list[int]: - """Determines and returns the valid actions for the current state.""" - # Check if all gates are native to the device + """Determine the valid actions for the current circuit state.""" + # Check if circuit uses only native gates check_nat_gates = GatesInBasis(basis_gates=self.device.operation_names) check_nat_gates(self.state) only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] - # Check if the circuit is mapped to the device coupling graph + + # Check if circuit is mapped to the device coupling map check_mapping = CheckMap(coupling_map=CouplingMap(self.device.build_coupling_map())) check_mapping(self.state) mapped = check_mapping.property_set["is_swap_mapped"] if not only_nat_gates: - # Circuit still has non-native gates if not mapped: - # Allow synthesis and optimization actions + # Non-native + unmapped → synthesis or optimization return self.actions_synthesis_indices + self.actions_opt_indices - # Allow synthesis and mapping-preserving actions (to not ) + # Non-native + mapped → synthesis or mapping-preserving return self.actions_synthesis_indices + self.actions_mapping_preserving_indices - # Circuit has only native gates + if mapped: if self.layout is not None: - # The circuits is correctly compiled, terminate or do further mapping-preserving optimizations + # Native + fully mapped & layout assigned → terminate or fine-tune return [ self.action_terminate_index, *self.actions_mapping_preserving_indices, *self.actions_final_optimization_indices, ] - # No layout is assigned, assign a valid layout + # Mapped but no explicit layout yet → explore layout/mapping improvements return self.actions_mapping_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices if self.layout is not None: - # Not mapped yet but a layout is assigned in the last step, do routing + # Layout chosen but not mapped → must do routing return self.actions_routing_indices - # Not mapped yet, do general optimizations/layout/mapping + # Not mapped and without layout → explore layout/mapping/optimizations return self.actions_opt_indices + self.actions_layout_indices + self.actions_mapping_indices From 470365d9451202e6db2f0e34488ebb66be5947c5 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 15 Sep 2025 17:23:25 +0200 Subject: [PATCH 40/98] Adjust test circuits from ALG to INDEP For test purpose --- noxfile.py | 1 + src/mqt/predictor/rl/predictorenv.py | 1 + tests/device_selection/test_predictor_ml.py | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/noxfile.py b/noxfile.py index 3b1876a5c..83ff540c3 100644 --- a/noxfile.py +++ b/noxfile.py @@ -67,6 +67,7 @@ def _run_tests( "--frozen", *install_args, "pytest", + "--log-cli-level=INFO", *pytest_run_args, *session.posargs, "--cov-config=pyproject.toml", diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 8e2b5e1d4..a0ebd5b75 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -204,6 +204,7 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any RuntimeError: If no valid actions are left. """ self.used_actions.append(str(self.action_set[action].name)) + logger.info(f"{self.action_set[action].name!s}") altered_qc = self.apply_action(action) if not altered_qc: return ( diff --git a/tests/device_selection/test_predictor_ml.py b/tests/device_selection/test_predictor_ml.py index 0b2f1485f..803c822a6 100644 --- a/tests/device_selection/test_predictor_ml.py +++ b/tests/device_selection/test_predictor_ml.py @@ -43,7 +43,7 @@ def test_setup_device_predictor_with_prediction(path_uncompiled_circuits: Path, path_compiled_circuits.mkdir() for i in range(2, 8): - qc = get_benchmark("ghz", BenchmarkLevel.ALG, i) + qc = get_benchmark("ghz", BenchmarkLevel.INDEP, i) path = path_uncompiled_circuits / f"qc{i}.qasm" with path.open("w", encoding="utf-8") as f: dump(qc, f) @@ -63,7 +63,7 @@ def test_setup_device_predictor_with_prediction(path_uncompiled_circuits: Path, assert (data_path / "names_list_expected_fidelity.npy").exists() assert (data_path / "scores_list_expected_fidelity.npy").exists() - test_qc = get_benchmark("ghz", BenchmarkLevel.ALG, 3) + test_qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 3) predicted = predict_device_for_figure_of_merit(test_qc, figure_of_merit="expected_fidelity") assert predicted.description == "ibm_falcon_127" @@ -93,7 +93,7 @@ def test_remove_files(path_uncompiled_circuits: Path, path_compiled_circuits: Pa def test_predict_device_for_figure_of_merit_no_suitable_device() -> None: """Test the prediction of the device for a given figure of merit with a wrong device name.""" num_qubits = 130 - qc = get_benchmark("ghz", BenchmarkLevel.ALG, num_qubits) + qc = get_benchmark("ghz", BenchmarkLevel.INDEP, num_qubits) with pytest.raises( ValueError, match=re.escape(f"No suitable device found for the given quantum circuit with {num_qubits} qubits.") ): From caaf2248bf612d2a30e083e85fd33c2496155c47 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 15 Sep 2025 18:18:53 +0200 Subject: [PATCH 41/98] Update max synthesis size for bqskit --- noxfile.py | 1 - src/mqt/predictor/rl/actions.py | 2 +- src/mqt/predictor/rl/predictorenv.py | 5 +---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/noxfile.py b/noxfile.py index 83ff540c3..3b1876a5c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -67,7 +67,6 @@ def _run_tests( "--frozen", *install_args, "pytest", - "--log-cli-level=INFO", *pytest_run_args, *session.posargs, "--cov-config=pyproject.toml", diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index c83bcf766..a2f775bed 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -563,7 +563,7 @@ def remove_action(name: str) -> None: model=MachineModel(bqskit_circuit.num_qudits, gate_set=get_bqskit_native_gates(device)), optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, - max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, + max_synthesis_size=3, seed=10, num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, ), diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index a0ebd5b75..eb6b35cfd 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -204,7 +204,6 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any RuntimeError: If no valid actions are left. """ self.used_actions.append(str(self.action_set[action].name)) - logger.info(f"{self.action_set[action].name!s}") altered_qc = self.apply_action(action) if not altered_qc: return ( @@ -393,14 +392,12 @@ def fom_aware_compile( fom = self.calculate_reward(synth_circ) if fom > best_fom: - print(f"New best {self.reward_function}: {fom}") best_fom = fom best_result = out_circ best_property_set = prop_set else: fom = self.calculate_reward(out_circ) if fom < best_fom: - print(f"New best {self.reward_function}: {fom}") best_fom = fom best_result = out_circ best_property_set = prop_set @@ -511,7 +508,7 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui try: placement = transpile_pass[0].get_placement_map(tket_qc) except Exception as e: - print(f"[Warning] Placement failed ({action.name}): {e}. Falling back to original circuit.") + logger.warning(f"Placement failed ({action.name}): {e}. Falling back to original circuit.") return tk_to_qiskit(tket_qc, replace_implicit_swaps=True) else: qc_tmp = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) From 468da2e2961251bd831bdb6571758667c2572c94 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 17 Sep 2025 16:03:16 +0200 Subject: [PATCH 42/98] Add tests for more coverage --- src/mqt/predictor/reward.py | 11 +-- src/mqt/predictor/rl/actions.py | 27 ++---- tests/compilation/test_predictor_rl.py | 124 ++++++++++++++++++------- 3 files changed, 101 insertions(+), 61 deletions(-) diff --git a/src/mqt/predictor/reward.py b/src/mqt/predictor/reward.py index 8394d6eee..c97485cd3 100644 --- a/src/mqt/predictor/reward.py +++ b/src/mqt/predictor/reward.py @@ -67,11 +67,7 @@ def expected_fidelity(qc: QuantumCircuit, device: Target, precision: int = 10) - specific_fidelity = 1 - device[gate_type][first_qubit_idx,].error else: second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) - try: - specific_fidelity = 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error - except KeyError: - # try flipped orientation (for uni-directional devices) - specific_fidelity = 1 - device[gate_type][second_qubit_idx, first_qubit_idx].error + specific_fidelity = 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error res *= specific_fidelity @@ -145,10 +141,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: else: # multi-qubit gate second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) active_qubits.add(second_qubit_idx) - try: - duration = device[gate_type][first_qubit_idx, second_qubit_idx].duration - except KeyError: - duration = device[gate_type][second_qubit_idx, first_qubit_idx].duration + duration = device[gate_type][first_qubit_idx, second_qubit_idx].duration op_times.append((gate_type, [first_qubit_idx, second_qubit_idx], duration, "s")) exec_time_per_qubit[first_qubit_idx] += duration exec_time_per_qubit[second_qubit_idx] += duration diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index a2f775bed..d979ca5ca 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -676,31 +676,18 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: qc_routed = dag_to_circuit(dag_routed) # Build mapping from original qubits to qubits in routed circuit final_layout = getattr(self, "property_set", {}).get("final_layout", None) - if final_layout is None and hasattr(dag_routed, "property_set"): - final_layout = dag_routed.property_set.get("final_layout", None) - assert final_layout is not None, "final_layout is None — cannot map virtual qubits" qubit_map = {} for virt in qc_orig.qubits: - try: - phys = final_layout[virt] - except KeyError as err: - msg = f"Virtual qubit {virt} not found in final layout!" - raise RuntimeError(msg) from err + assert virt in final_layout, f"Virtual qubit {virt} not found in final layout!" + phys = final_layout[virt] if isinstance(phys, int): - try: - qubit_map[virt] = qc_routed.qubits[phys] - except IndexError as err: - msg = f"Physical index {phys} is out of range in routed circuit!" - raise RuntimeError(msg) from err + assert 0 <= phys < len(qc_routed.qubits), f"Physical index {phys} out of range in routed circuit!" + qubit_map[virt] = qc_routed.qubits[phys] else: - try: - idx = qc_routed.qubits.index(phys) - except ValueError as err: - msg = f"Physical qubit {phys} not found in output circuit!" - raise RuntimeError(msg) from err - qubit_map[virt] = qc_routed.qubits[idx] - # Restore classical registers and measurement instructions + assert phys in qc_routed.qubits, f"Physical qubit {phys} not found in output circuit!" + qubit_map[virt] = qc_routed.qubits[qc_routed.qubits.index(phys)] + # Restore classical registers and measurement instructions qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) # Return as dag return circuit_to_dag(qc_final) diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index ebb8f8e34..7577cb7a9 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -12,10 +12,12 @@ import re from pathlib import Path +from typing import TYPE_CHECKING import pytest from mqt.bench import BenchmarkLevel, get_benchmark from mqt.bench.targets import get_device +from qiskit import QuantumCircuit from qiskit.circuit.library import CXGate from qiskit.qasm2 import dump from qiskit.transpiler import CouplingMap, InstructionProperties, Target @@ -23,6 +25,7 @@ from mqt.predictor.rl import Predictor, rl_compile from mqt.predictor.rl.actions import ( + Action, CompilationOrigin, DeviceIndependentAction, PassType, @@ -32,6 +35,9 @@ ) from mqt.predictor.rl.helper import create_feature_dict, get_path_trained_model +if TYPE_CHECKING: + from _pytest.monkeypatch import MonkeyPatch + def test_predictor_env_reset_from_string() -> None: """Test the reset function of the predictor environment with a quantum circuit given as a string as input.""" @@ -68,40 +74,41 @@ def test_qcompile_with_newly_trained_models() -> None: Important: Those trained models are used in later tests and must not be deleted. To test ESP as well, training must be done with a device that provides all relevant information (i.e. T1, T2 and gate times). """ - figure_of_merit = "expected_fidelity" + figure_of_merits = ["expected_fidelity", "critical_depth"] device = get_device("ibm_falcon_127") qc = get_benchmark("ghz", BenchmarkLevel.ALG, 3) - predictor = Predictor(figure_of_merit=figure_of_merit, device=device) - - model_name = "model_" + figure_of_merit + "_" + device.description - model_path = Path(get_path_trained_model() / (model_name + ".zip")) - if not model_path.exists(): - with pytest.raises( - FileNotFoundError, - match=re.escape( - "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." - ), - ): - rl_compile(qc, device=device, figure_of_merit=figure_of_merit) - - predictor.train_model( - timesteps=100, - test=True, - ) - - qc_compiled, compilation_information = rl_compile(qc, device=device, figure_of_merit=figure_of_merit) - - check_nat_gates = GatesInBasis(basis_gates=device.operation_names) - check_nat_gates(qc_compiled) - only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] - check_mapping = CheckMap(coupling_map=CouplingMap(device.build_coupling_map())) - check_mapping(qc_compiled) - mapped = check_mapping.property_set["is_swap_mapped"] - - assert qc_compiled.layout is not None - assert compilation_information is not None - assert only_nat_gates, "Circuit should only contain native gates but was not detected as such." - assert mapped, "Circuit should be mapped to the device's coupling map." + for figure_of_merit in figure_of_merits: + predictor = Predictor(figure_of_merit=figure_of_merit, device=device) + + model_name = "model_" + figure_of_merit + "_" + device.description + model_path = Path(get_path_trained_model() / (model_name + ".zip")) + if not model_path.exists(): + with pytest.raises( + FileNotFoundError, + match=re.escape( + "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." + ), + ): + rl_compile(qc, device=device, figure_of_merit=figure_of_merit) + + predictor.train_model( + timesteps=100, + test=True, + ) + + qc_compiled, compilation_information = rl_compile(qc, device=device, figure_of_merit=figure_of_merit) + + check_nat_gates = GatesInBasis(basis_gates=device.operation_names) + check_nat_gates(qc_compiled) + only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] + check_mapping = CheckMap(coupling_map=CouplingMap(device.build_coupling_map())) + check_mapping(qc_compiled) + mapped = check_mapping.property_set["is_swap_mapped"] + + assert qc_compiled.layout is not None + assert compilation_information is not None + assert only_nat_gates, "Circuit should only contain native gates but was not detected as such." + assert mapped, "Circuit should be mapped to the device's coupling map." def test_qcompile_with_false_input() -> None: @@ -124,6 +131,59 @@ def test_warning_for_unidirectional_device() -> None: Predictor(figure_of_merit="expected_fidelity", device=target) +def test_fom_aware_compile_fallback(monkeypatch: MonkeyPatch) -> None: + """Force calculate_reward to fail so the swap-count fallback is triggered.""" + # A simple circuit with 2 qubits and a swap to test swap-count fallback + qc = QuantumCircuit(2) + qc.swap(0, 1) + + dummy_action = Action( + name="DummyAction", + origin=CompilationOrigin.QISKIT, + pass_type=PassType.MAPPING, + transpile_pass=lambda _device: [], # no passes applied + ) + + predictor = Predictor(figure_of_merit="estimated_success_probability", device=get_device("ibm_eagle_127")) + monkeypatch.setattr( + predictor.env, "calculate_reward", lambda _circ: (_ for _ in ()).throw(RuntimeError("fake error")) + ) + compiled_qc, prop_set = predictor.env.fom_aware_compile(dummy_action, None, qc, max_iteration=1) + + assert isinstance(compiled_qc, QuantumCircuit) + assert isinstance(prop_set, dict) + assert "swap" in compiled_qc.count_ops() + + +def test_tket_action_layout_failure() -> None: + """Force TKET layout placement to fail to hit the except branch.""" + qc = QuantumCircuit(1) + + class FakePass: + def get_placement_map(self, _: object) -> None: + msg = "fake placement failure" + raise RuntimeError(msg) + + def apply(self, _: object) -> None: + pass + + dummy_action = Action( + name="DummyLayout", + origin=CompilationOrigin.TKET, + pass_type=PassType.LAYOUT, + transpile_pass=lambda _device: [FakePass()], + ) + + predictor = Predictor(figure_of_merit="estimated_success_probability", device=get_device("ibm_eagle_127")) + predictor.env.actions_layout_indices.append(0) + predictor.env.state = qc + apply_tket = predictor.env._apply_tket_action # noqa: SLF001 + result_qc = apply_tket(dummy_action, 0) + + assert isinstance(result_qc, QuantumCircuit) + assert result_qc.num_qubits == 1 + + def test_register_action() -> None: """Test the register_action function.""" action = DeviceIndependentAction( From 737a9f24b0822dce45a1f587327f61d38ba8b071 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Sep 2025 11:10:18 +0200 Subject: [PATCH 43/98] Update tests --- tests/compilation/test_predictor_rl.py | 68 +++++++++++++------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index 7577cb7a9..e0891a38d 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -74,41 +74,41 @@ def test_qcompile_with_newly_trained_models() -> None: Important: Those trained models are used in later tests and must not be deleted. To test ESP as well, training must be done with a device that provides all relevant information (i.e. T1, T2 and gate times). """ - figure_of_merits = ["expected_fidelity", "critical_depth"] + figure_of_merit = "expected_fidelity" device = get_device("ibm_falcon_127") qc = get_benchmark("ghz", BenchmarkLevel.ALG, 3) - for figure_of_merit in figure_of_merits: - predictor = Predictor(figure_of_merit=figure_of_merit, device=device) - - model_name = "model_" + figure_of_merit + "_" + device.description - model_path = Path(get_path_trained_model() / (model_name + ".zip")) - if not model_path.exists(): - with pytest.raises( - FileNotFoundError, - match=re.escape( - "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." - ), - ): - rl_compile(qc, device=device, figure_of_merit=figure_of_merit) - - predictor.train_model( - timesteps=100, - test=True, - ) - - qc_compiled, compilation_information = rl_compile(qc, device=device, figure_of_merit=figure_of_merit) - - check_nat_gates = GatesInBasis(basis_gates=device.operation_names) - check_nat_gates(qc_compiled) - only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] - check_mapping = CheckMap(coupling_map=CouplingMap(device.build_coupling_map())) - check_mapping(qc_compiled) - mapped = check_mapping.property_set["is_swap_mapped"] - - assert qc_compiled.layout is not None - assert compilation_information is not None - assert only_nat_gates, "Circuit should only contain native gates but was not detected as such." - assert mapped, "Circuit should be mapped to the device's coupling map." + + predictor = Predictor(figure_of_merit=figure_of_merit, device=device) + + model_name = "model_" + figure_of_merit + "_" + device.description + model_path = Path(get_path_trained_model() / (model_name + ".zip")) + if not model_path.exists(): + with pytest.raises( + FileNotFoundError, + match=re.escape( + "The RL model 'model_expected_fidelity_ibm_falcon_127' is not trained yet. Please train the model before using it." + ), + ): + rl_compile(qc, device=device, figure_of_merit=figure_of_merit) + + predictor.train_model( + timesteps=100, + test=True, + ) + + qc_compiled, compilation_information = rl_compile(qc, device=device, figure_of_merit=figure_of_merit) + + check_nat_gates = GatesInBasis(basis_gates=device.operation_names) + check_nat_gates(qc_compiled) + only_nat_gates = check_nat_gates.property_set["all_gates_in_basis"] + check_mapping = CheckMap(coupling_map=CouplingMap(device.build_coupling_map())) + check_mapping(qc_compiled) + mapped = check_mapping.property_set["is_swap_mapped"] + + assert qc_compiled.layout is not None + assert compilation_information is not None + assert only_nat_gates, "Circuit should only contain native gates but was not detected as such." + assert mapped, "Circuit should be mapped to the device's coupling map." def test_qcompile_with_false_input() -> None: @@ -144,7 +144,7 @@ def test_fom_aware_compile_fallback(monkeypatch: MonkeyPatch) -> None: transpile_pass=lambda _device: [], # no passes applied ) - predictor = Predictor(figure_of_merit="estimated_success_probability", device=get_device("ibm_eagle_127")) + predictor = Predictor(figure_of_merit="critical_depth", device=get_device("ibm_eagle_127")) monkeypatch.setattr( predictor.env, "calculate_reward", lambda _circ: (_ for _ in ()).throw(RuntimeError("fake error")) ) From 94c25ab0212686fcadd9c74b7906ef77380d8ca7 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Sep 2025 13:45:26 +0200 Subject: [PATCH 44/98] Update override --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1fbb96977..7eb9e2bd5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -256,5 +256,5 @@ ignore = ["GH200"] [tool.uv] override-dependencies = [ - "networkx==2.8.5", # Required by `qiskit-ibm-transpiler` + "networkx==2.8.5; python_version < '3.13'", # Required by `qiskit-ibm-transpiler` ] From 3ff922e3383313dfc3baa835bb0b21d68838cfaa Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Sep 2025 14:09:54 +0200 Subject: [PATCH 45/98] Update comments Update --- pyproject.toml | 2 +- tests/compilation/test_predictor_rl.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7eb9e2bd5..1fbb96977 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -256,5 +256,5 @@ ignore = ["GH200"] [tool.uv] override-dependencies = [ - "networkx==2.8.5; python_version < '3.13'", # Required by `qiskit-ibm-transpiler` + "networkx==2.8.5", # Required by `qiskit-ibm-transpiler` ] diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index e0891a38d..96f0a6d58 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -132,8 +132,7 @@ def test_warning_for_unidirectional_device() -> None: def test_fom_aware_compile_fallback(monkeypatch: MonkeyPatch) -> None: - """Force calculate_reward to fail so the swap-count fallback is triggered.""" - # A simple circuit with 2 qubits and a swap to test swap-count fallback + """Test fallback of the fom_aware_compile function in case of a compilation failure.""" qc = QuantumCircuit(2) qc.swap(0, 1) @@ -156,7 +155,7 @@ def test_fom_aware_compile_fallback(monkeypatch: MonkeyPatch) -> None: def test_tket_action_layout_failure() -> None: - """Force TKET layout placement to fail to hit the except branch.""" + """Test fallback in case of TKET layout placement failure.""" qc = QuantumCircuit(1) class FakePass: From 782caf8f8f0ff98b1044ddc78679b741050dd200 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Mon, 22 Sep 2025 22:09:38 +0200 Subject: [PATCH 46/98] Update noxfile.py and CHANGELOG.md --- CHANGELOG.md | 1 + noxfile.py | 32 ++++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be86348b8..0648923b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Changed +- 🔧 Changed test circuit level for RL predictor from ALG to INDEP - 🔥 Drop support for x86 macOS systems ([#421]) ([**@denialhaag**]) ## [2.3.0] - 2025-07-29 diff --git a/noxfile.py b/noxfile.py index 3b1876a5c..439bc8d0d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -11,14 +11,16 @@ from __future__ import annotations import argparse +import contextlib import os import shutil +import tempfile from typing import TYPE_CHECKING import nox if TYPE_CHECKING: - from collections.abc import Sequence + from collections.abc import Generator, Sequence nox.needs_version = ">=2024.3.2" @@ -35,6 +37,17 @@ nox.options.error_on_missing_interpreters = True +@contextlib.contextmanager +def preserve_lockfile() -> Generator[None]: + """Preserve the lockfile by moving it to a temporary directory.""" + with tempfile.TemporaryDirectory() as temp_dir_name: + shutil.move("uv.lock", f"{temp_dir_name}/uv.lock") + try: + yield + finally: + shutil.move(f"{temp_dir_name}/uv.lock", "uv.lock") + + @nox.session(reuse_venv=True) def lint(session: nox.Session) -> None: """Run the linter.""" @@ -64,7 +77,6 @@ def _run_tests( "--no-dev", "--group", "test", - "--frozen", *install_args, "pytest", *pytest_run_args, @@ -83,14 +95,14 @@ def tests(session: nox.Session) -> None: @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) def minimums(session: nox.Session) -> None: """Test the minimum versions of dependencies.""" - _run_tests( - session, - install_args=["--resolution=lowest-direct"], - pytest_run_args=["-Wdefault"], - ) - env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} - session.run("uv", "tree", "--frozen", env=env) - session.run("uv", "lock", "--refresh", env=env) + with preserve_lockfile(): + _run_tests( + session, + install_args=["--resolution=lowest-direct"], + pytest_run_args=["-Wdefault"], + ) + env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} + session.run("uv", "tree", "--frozen", env=env) @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) From 44e0e4047af48a56a5c264e0e891a689ffda345e Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Tue, 23 Sep 2025 13:45:42 +0200 Subject: [PATCH 47/98] Clean up venv after each session to free up space --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 439bc8d0d..d1f98ac60 100644 --- a/noxfile.py +++ b/noxfile.py @@ -86,7 +86,7 @@ def _run_tests( ) -@nox.session(reuse_venv=True, python=PYTHON_ALL_VERSIONS) +@nox.session(reuse_venv=not os.environ.get("CI"), python=PYTHON_ALL_VERSIONS) def tests(session: nox.Session) -> None: """Run the test suite.""" _run_tests(session) From 350bae5a82b9f36b34e0051af3419864101ae0f5 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Tue, 23 Sep 2025 20:40:24 +0200 Subject: [PATCH 48/98] Clean up venv after each session to free up space --- noxfile.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/noxfile.py b/noxfile.py index d1f98ac60..c1bc0fb43 100644 --- a/noxfile.py +++ b/noxfile.py @@ -13,6 +13,7 @@ import argparse import contextlib import os +import pathlib import shutil import tempfile from typing import TYPE_CHECKING @@ -57,6 +58,16 @@ def lint(session: nox.Session) -> None: session.run("pre-commit", "run", "--all-files", *session.posargs, external=True) +def _cleanup(session: nox.Session) -> None: + """Remove this session's virtualenv to save disk space in CI.""" + venv_dir = session.virtualenv.location + if venv_dir and pathlib.Path(venv_dir).exists(): + shutil.rmtree(venv_dir, ignore_errors=True) + session.log(f"Cleaned up {venv_dir}") + shutil.rmtree(pathlib.Path("~/.cache").expanduser(), ignore_errors=True) + session.run("uv", "cache", "clean", "--all", external=True) + + def _run_tests( session: nox.Session, *, @@ -90,6 +101,8 @@ def _run_tests( def tests(session: nox.Session) -> None: """Run the test suite.""" _run_tests(session) + if os.environ.get("CI"): + _cleanup(session) @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) @@ -103,6 +116,8 @@ def minimums(session: nox.Session) -> None: ) env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} session.run("uv", "tree", "--frozen", env=env) + if os.environ.get("CI"): + _cleanup(session) @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) From 91208d194d353ab47d884f9f46b54ee04849a21e Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Tue, 23 Sep 2025 22:46:12 +0200 Subject: [PATCH 49/98] Clean up venv after each session to free up space --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index c1bc0fb43..bde534424 100644 --- a/noxfile.py +++ b/noxfile.py @@ -65,7 +65,7 @@ def _cleanup(session: nox.Session) -> None: shutil.rmtree(venv_dir, ignore_errors=True) session.log(f"Cleaned up {venv_dir}") shutil.rmtree(pathlib.Path("~/.cache").expanduser(), ignore_errors=True) - session.run("uv", "cache", "clean", "--all", external=True) + session.run("uv", "cache", "clean", external=True) def _run_tests( From 622d409ad00078e51c1f7c55a3e7598d2096a6a7 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 24 Sep 2025 01:40:00 +0200 Subject: [PATCH 50/98] Clean up venv after each session to free up space --- noxfile.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index bde534424..f2093b742 100644 --- a/noxfile.py +++ b/noxfile.py @@ -65,7 +65,11 @@ def _cleanup(session: nox.Session) -> None: shutil.rmtree(venv_dir, ignore_errors=True) session.log(f"Cleaned up {venv_dir}") shutil.rmtree(pathlib.Path("~/.cache").expanduser(), ignore_errors=True) - session.run("uv", "cache", "clean", external=True) + # Clean GitHub Actions temp cache + gha_temp = pathlib.Path("/home/runner/work/_temp/setup-uv-cache") + if gha_temp.exists(): + shutil.rmtree(gha_temp, ignore_errors=True) + session.log(f"Cleaned GitHub Actions uv temp cache at {gha_temp}") def _run_tests( From fa008a61bb986fa47f46940f21097904a3d56dbc Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 25 Sep 2025 20:11:30 +0200 Subject: [PATCH 51/98] Update noxfile --- noxfile.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/noxfile.py b/noxfile.py index f2093b742..beb069798 100644 --- a/noxfile.py +++ b/noxfile.py @@ -124,17 +124,6 @@ def minimums(session: nox.Session) -> None: _cleanup(session) -@nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) -def qiskit(session: nox.Session) -> None: - """Tests against the latest version of Qiskit.""" - _run_tests( - session, - extra_command=["uv", "pip", "install", "qiskit[qasm3-import] @ git+https://github.com/Qiskit/qiskit.git"], - ) - env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} - session.run("uv", "pip", "show", "qiskit", env=env) - - @nox.session(reuse_venv=True) def docs(session: nox.Session) -> None: """Build the docs. Use "--non-interactive" to avoid serving. Pass "-b linkcheck" to check links.""" From 0c98e5656853617892812cdfcd33416c4c60cdc9 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 25 Sep 2025 21:13:29 +0200 Subject: [PATCH 52/98] Update ibm runtime dependency --- pyproject.toml | 1 + uv.lock | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 1fbb96977..0d81d676d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ dependencies = [ "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 "torch>=2.8.0,<2.9.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` + "qiskit_ibm_runtime>=0.40.0,<0.42.0", "qiskit-ibm-transpiler==0.13.1; python_version < '3.13'", # Do not support python 3.13 yet "qiskit-ibm-ai-local-transpiler==0.4.2; python_version < '3.13'", ] diff --git a/uv.lock b/uv.lock index 9c915f7fe..b33cf00e2 100644 --- a/uv.lock +++ b/uv.lock @@ -1548,6 +1548,7 @@ dependencies = [ { name = "pytket-qiskit" }, { name = "qiskit" }, { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'" }, + { name = "qiskit-ibm-runtime" }, { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'" }, { name = "rich" }, { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, @@ -1607,6 +1608,7 @@ requires-dist = [ { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = "!=1.3.2" }, { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.4.2" }, + { name = "qiskit-ibm-runtime", specifier = ">=0.40.0,<0.42.0" }, { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.13.1" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, @@ -3683,6 +3685,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/cb/9bce97ad8135a32b47e90b3f57084bdc0bb844aa866b3ca0bc88987a2ac4/symengine-0.14.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a010412317d93e37fbee3f4bc04886408653e863997993424e7b9e4d8c85c150", size = 90826835, upload-time = "2025-04-21T04:00:55.849Z" }, { url = "https://files.pythonhosted.org/packages/5e/8f/3c335e44db300f4d91f7b098661a2add403367833cc27d26dc235520661a/symengine-0.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb14724ab6a6844d04adbd48d7aadcadfe4974193e87eedac93963a6e88bf53", size = 50356243, upload-time = "2025-04-21T04:01:00.867Z" }, { url = "https://files.pythonhosted.org/packages/fc/fd/d9f33b8a08bdfc07fff733c7f869deb5a0e8c93f5cb95ed4cb9d16294dfb/symengine-0.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:4635fa8855fcadae8c60f27f498388699b7ee88c6be7c3e23564eb0907f6b397", size = 18755307, upload-time = "2025-04-21T04:01:04.187Z" }, + { url = "https://files.pythonhosted.org/packages/65/eb/875243e2856ef203f102cfefe54b81f4a08daed2c7b2ad929e8b82282d93/symengine-0.14.1-cp311-abi3-macosx_10_13_x86_64.whl", hash = "sha256:182d7ca746622764e50af4f926eb9733bd4d1fddb9526faa67bc6ca88b333e23", size = 26038565, upload-time = "2025-09-14T15:23:14.361Z" }, + { url = "https://files.pythonhosted.org/packages/13/85/58acf0f28ae556205044bce9228a4e0e3bb532e0d4a81f3af84e0c45d95b/symengine-0.14.1-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:6fbe25be42ba2040f09d464c06a7812f8e8d04c8087abbad914be561deac2141", size = 23108837, upload-time = "2025-09-14T15:23:17.395Z" }, + { url = "https://files.pythonhosted.org/packages/a2/00/0355f1a261d608b1eaa972071e73070bc415cd1932e90574354e98f46254/symengine-0.14.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:78ac61effb97f63eca70bb4ececb2cb329b09f1d587cfab51768bd3c04543010", size = 61943252, upload-time = "2025-09-14T15:23:21.076Z" }, + { url = "https://files.pythonhosted.org/packages/47/b4/41374adf5f7e60576862e4b4df1519225001fe2f230a3d15c67aa273ea48/symengine-0.14.1-cp311-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5ee52a0aaacafc032dbe5ca57c0b3d87a228e9ef6e88676a4ecc0111fb647b9e", size = 94027577, upload-time = "2025-09-14T15:23:26.165Z" }, + { url = "https://files.pythonhosted.org/packages/52/af/0de548738de262f2288cdefc02df35aaa8c398369643619f59a9c2b5a0b0/symengine-0.14.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577dd78b33f29e7713443588c576013ede4757cb8aedc36bcc405cf85844d7f9", size = 51085045, upload-time = "2025-09-14T15:23:30.185Z" }, + { url = "https://files.pythonhosted.org/packages/e2/d3/fb148c2a2fdefa8f1630f3a0da0170d77ee8e1ac3baf7804504ddc9baacd/symengine-0.14.1-cp311-abi3-win_amd64.whl", hash = "sha256:c1142fd44cc952025185521c1f8a756af8625955f41ad7b947df2b81a14ce7f3", size = 18739305, upload-time = "2025-09-14T15:23:33.031Z" }, { url = "https://files.pythonhosted.org/packages/ee/f8/689900a258a68b121d7c61a6705b5332969dd95517f9be1d66a4937a17e1/symengine-0.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:43a394acef2355bbcbed089c8f83a7dbdac28f4f979e094b549f571fc411dea6", size = 25992552, upload-time = "2025-04-21T04:01:07.102Z" }, { url = "https://files.pythonhosted.org/packages/6e/10/82291c78d6dbc17b2e4371559a3945920ecc536ec36b6c8dde28165064f9/symengine-0.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7eb37cd5a9eb0c1c5e35c515139fd1221d937b269aef3569b92c7bb4e251be4", size = 23052876, upload-time = "2025-04-21T04:01:09.679Z" }, { url = "https://files.pythonhosted.org/packages/30/1a/2199515b7d4f3aa74262e3eb31916a593c4daa7da53bb2c9cbd2cc13fad8/symengine-0.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7657663cfb0d87d66848f7cacda0b2447e127584bc9ec65120e75ce68b21b809", size = 60873086, upload-time = "2025-04-21T04:01:14.285Z" }, @@ -3706,6 +3714,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/be/28/9ae2ee8c3a6e5b35b25a42625de4cd8ef432121dd4ff75bca6809b9e61ac/symengine-0.14.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58f8e1756c9f8cdb7f6cdf189b3752f20cb464f82bf1c7a3873156b12c567896", size = 60604042, upload-time = "2025-04-21T04:02:25.915Z" }, { url = "https://files.pythonhosted.org/packages/7d/c0/233806912e5515505a058d2527a53117e0e6cd8e59525f1c7cb870805a47/symengine-0.14.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a96f1adfed8cfad62a4f58fe2f32b42718e0938afef0bffeb8131d862ca71a9b", size = 90280432, upload-time = "2025-04-21T04:02:31.02Z" }, { url = "https://files.pythonhosted.org/packages/bd/93/a6f379c6bd9554efc4cd5475e75fc164d6c44e69d98ddf6553f12a2532aa/symengine-0.14.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c4f500fdd09cbd3cde34a027a964e47b4fc7bfcd5ec8b9a4e654a37036d364b", size = 50183106, upload-time = "2025-04-21T04:02:35.537Z" }, + { url = "https://files.pythonhosted.org/packages/e7/92/31a04faad202197006ad91166a5cb8b513b3238ab4796faabaacece56665/symengine-0.14.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4b85100df4b0e1f6bd2f036539f55961f1e95e77d73fa7beefddbf43359dfda0", size = 26129364, upload-time = "2025-09-14T15:23:35.883Z" }, + { url = "https://files.pythonhosted.org/packages/f7/35/5811158a9a9121f4acc219dd1d1e2c0efec8746d0ddef73890b8348f5e47/symengine-0.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a5938a252c3516f77654689a3e858becc20effce8d34832d1d293ce23ca0d27", size = 23188595, upload-time = "2025-09-14T15:23:38.981Z" }, + { url = "https://files.pythonhosted.org/packages/03/05/c327964f2aeb73a85f5fba80e5357b637794c886389af05718915dd390d8/symengine-0.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:744b01250d15ecdfad63fa7d590a251598794bd977d35d0fab6cb18e8742a493", size = 61923804, upload-time = "2025-09-14T15:23:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/98/f0/f7d488b93081d25a47e974335808cbb6ece96aaaf15abbb72d5d35ee5eab/symengine-0.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:9fd6465d3a797d44e5e4d3b540c4416f18ddccb77768267f0f1e783c44d97bbc", size = 94038098, upload-time = "2025-09-14T15:23:48.45Z" }, + { url = "https://files.pythonhosted.org/packages/22/45/45e84f7f3154d61df6de21b5e38912f9ce91bd7422072a575fe9a3b2ed43/symengine-0.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d1fe80abee5ad6f53bd64c38e25737bb526eff6d24d8428df0f92283e592799", size = 51127881, upload-time = "2025-09-14T15:23:52.894Z" }, + { url = "https://files.pythonhosted.org/packages/ce/30/6b63d1dc9047587cee5cb9d3a4d75041e8173d839eb4c962ad357730a928/symengine-0.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:faf659b9436dcc5ade7f6085d17d42181c18d78ddcaf91de16cd9a412fc77357", size = 18878832, upload-time = "2025-09-14T15:23:55.911Z" }, ] [[package]] From 34a1c7cb992d8afea493b42b543227c775a88928 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 25 Sep 2025 23:02:18 +0200 Subject: [PATCH 53/98] Update noxfile --- noxfile.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/noxfile.py b/noxfile.py index beb069798..76b997ad9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -105,8 +105,6 @@ def _run_tests( def tests(session: nox.Session) -> None: """Run the test suite.""" _run_tests(session) - if os.environ.get("CI"): - _cleanup(session) @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) @@ -120,8 +118,6 @@ def minimums(session: nox.Session) -> None: ) env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} session.run("uv", "tree", "--frozen", env=env) - if os.environ.get("CI"): - _cleanup(session) @nox.session(reuse_venv=True) From a8d069af09b21ce5c60920267a2623aa1070e5d0 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 26 Sep 2025 00:25:24 +0200 Subject: [PATCH 54/98] Update noxfile --- noxfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/noxfile.py b/noxfile.py index 76b997ad9..c57689799 100644 --- a/noxfile.py +++ b/noxfile.py @@ -90,6 +90,7 @@ def _run_tests( "uv", "run", "--no-dev", + "--no-cache", "--group", "test", *install_args, From 114b79bf9887eb2dfa92eff49bb4121ddb568367 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 26 Sep 2025 01:57:07 +0200 Subject: [PATCH 55/98] Update noxfile --- noxfile.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/noxfile.py b/noxfile.py index c57689799..b5a748558 100644 --- a/noxfile.py +++ b/noxfile.py @@ -60,16 +60,17 @@ def lint(session: nox.Session) -> None: def _cleanup(session: nox.Session) -> None: """Remove this session's virtualenv to save disk space in CI.""" - venv_dir = session.virtualenv.location - if venv_dir and pathlib.Path(venv_dir).exists(): - shutil.rmtree(venv_dir, ignore_errors=True) - session.log(f"Cleaned up {venv_dir}") - shutil.rmtree(pathlib.Path("~/.cache").expanduser(), ignore_errors=True) - # Clean GitHub Actions temp cache - gha_temp = pathlib.Path("/home/runner/work/_temp/setup-uv-cache") - if gha_temp.exists(): - shutil.rmtree(gha_temp, ignore_errors=True) - session.log(f"Cleaned GitHub Actions uv temp cache at {gha_temp}") + version = session.python + if version != "3.13": # keep cache for last run + venv_dir = session.virtualenv.location + if venv_dir and pathlib.Path(venv_dir).exists(): + shutil.rmtree(venv_dir, ignore_errors=True) + session.log(f"Cleaned up {venv_dir}") + shutil.rmtree(pathlib.Path("~/.cache").expanduser(), ignore_errors=True) + gha_temp = pathlib.Path("/home/runner/work/_temp/setup-uv-cache") + if gha_temp.exists(): + shutil.rmtree(gha_temp, ignore_errors=True) + session.log(f"Cleaned GitHub Actions uv temp cache at {gha_temp}") def _run_tests( @@ -90,7 +91,6 @@ def _run_tests( "uv", "run", "--no-dev", - "--no-cache", "--group", "test", *install_args, @@ -106,6 +106,8 @@ def _run_tests( def tests(session: nox.Session) -> None: """Run the test suite.""" _run_tests(session) + if os.environ.get("CI"): + _cleanup(session) @nox.session(reuse_venv=True, venv_backend="uv", python=PYTHON_ALL_VERSIONS) @@ -119,6 +121,8 @@ def minimums(session: nox.Session) -> None: ) env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} session.run("uv", "tree", "--frozen", env=env) + if os.environ.get("CI"): + _cleanup(session) @nox.session(reuse_venv=True) From aaf14b1b550557c08930ff4c2a1094ac2121849f Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 26 Sep 2025 15:37:34 +0200 Subject: [PATCH 56/98] Fetch update from main --- pyproject.toml | 6 ++++-- src/mqt/predictor/rl/parsing.py | 5 +++-- uv.lock | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0d81d676d..889016b3c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,9 +30,12 @@ dynamic = ["version"] dependencies = [ "mqt.bench>=2.0.0", - "qiskit!=1.3.2", # 1.3.2 causes a Qiskit error when using the CommutativeInverseCancellation pass, see https://github.com/Qiskit/qiskit/issues/13742 + "qiskit>=1.3.3", "pytket>=1.29.0", # lowest version that supports the used pytket AutoRebase pass instead of auto_rebase "pytket_qiskit>=0.71.0", + # TODO(denialhaag): Remove once pytket_qiskit is updated + # https://github.com/munich-quantum-toolkit/predictor/issues/471 + "qiskit-ibm-runtime>=0.30.0,<0.42.0", "sb3_contrib>=2.0.0", "stable-baselines3>=2.7.0", "tqdm>=4.66.0", @@ -47,7 +50,6 @@ dependencies = [ "numpy>=1.22,<2; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict numpy v2 for macOS x86 since it is not supported anymore since torch v2.3.0 "torch>=2.8.0,<2.9.0; sys_platform == 'darwin' and 'x86_64' in platform_machine and python_version < '3.13'", # Restrict torch v2.3.0 for macOS x86 since it is not supported anymore. "typing-extensions>=4.1", # for `assert_never` - "qiskit_ibm_runtime>=0.40.0,<0.42.0", "qiskit-ibm-transpiler==0.13.1; python_version < '3.13'", # Do not support python 3.13 yet "qiskit-ibm-ai-local-transpiler==0.4.2; python_version < '3.13'", ] diff --git a/src/mqt/predictor/rl/parsing.py b/src/mqt/predictor/rl/parsing.py index 816e7aa48..6f35152d3 100644 --- a/src/mqt/predictor/rl/parsing.py +++ b/src/mqt/predictor/rl/parsing.py @@ -18,6 +18,7 @@ from pytket.circuit import Node from pytket.placement import place_with_map from qiskit import QuantumCircuit, QuantumRegister +from qiskit.converters import circuit_to_dag, dag_to_circuit from qiskit.transpiler import Layout, PassManager, Target, TranspileLayout from qiskit.transpiler.passes import ApplyLayout @@ -239,8 +240,8 @@ def postprocess_vf2postlayout( apply_layout.property_set["final_layout"] = layout_before.final_layout apply_layout.property_set["post_layout"] = post_layout - altered_qc = apply_layout(qc) - return altered_qc, apply_layout + altered_qc = apply_layout.run(circuit_to_dag(qc)) + return dag_to_circuit(altered_qc), apply_layout def prepare_noise_data(device: Target) -> tuple[dict[Node, float], dict[tuple[Node, Node], float], dict[Node, float]]: diff --git a/uv.lock b/uv.lock index b33cf00e2..db59b3577 100644 --- a/uv.lock +++ b/uv.lock @@ -1606,9 +1606,9 @@ requires-dist = [ { name = "numpy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=1.22,<2" }, { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, - { name = "qiskit", specifier = "!=1.3.2" }, + { name = "qiskit", specifier = ">=1.3.3" }, { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.4.2" }, - { name = "qiskit-ibm-runtime", specifier = ">=0.40.0,<0.42.0" }, + { name = "qiskit-ibm-runtime", specifier = ">=0.30.0,<0.42.0" }, { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.13.1" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, From e7b4174348d21d5c4cf2aa2ef15678f43d1f9097 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 20 Nov 2025 15:56:46 +0100 Subject: [PATCH 57/98] Fix ruff checks --- src/mqt/predictor/rl/actions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index d979ca5ca..a48ac83b1 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -29,7 +29,7 @@ ) from pytket.placement import GraphPlacement, NoiseAwarePlacement from qiskit import QuantumCircuit -from qiskit.circuit import ClassicalRegister, Instruction, QuantumRegister, Qubit, StandardEquivalenceLibrary +from qiskit.circuit import ClassicalRegister, QuantumRegister, StandardEquivalenceLibrary from qiskit.circuit.library import ( CXGate, CYGate, @@ -93,6 +93,7 @@ from bqskit import Circuit from pytket._tket.passes import BasePass as tket_BasePass + from qiskit.circuit import Instruction, Qubit from qiskit.dagcircuit import DAGCircuit from qiskit.transpiler.basepasses import BasePass as qiskit_BasePass From fcab4faacb7107e65d3afad0187b31056708ab2c Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 20 Nov 2025 16:31:17 +0100 Subject: [PATCH 58/98] Update action space and add normalized gate counts as RL features --- noxfile.py | 0 src/mqt/predictor/rl/actions.py | 20 +++++++++++++ src/mqt/predictor/rl/helper.py | 20 ++++++++++++- src/mqt/predictor/rl/predictorenv.py | 5 ++++ src/mqt/predictor/utils.py | 42 ++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 1 deletion(-) mode change 100644 => 100755 noxfile.py diff --git a/noxfile.py b/noxfile.py old mode 100644 new mode 100755 diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index a48ac83b1..513984be0 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -23,6 +23,7 @@ from pytket.passes import ( CliffordSimp, FullPeepholeOptimise, + KAKDecomposition, PeepholeOptimise2Q, RemoveRedundancies, RoutingPass, @@ -60,6 +61,7 @@ ConsolidateBlocks, DenseLayout, Depth, + ElidePermutations, EnlargeWithAncilla, FixedPoint, FullAncillaAllocation, @@ -239,6 +241,15 @@ def remove_action(name: str) -> None: ) ) +register_action( + DeviceIndependentAction( + "ElidePermutations", + CompilationOrigin.QISKIT, + PassType.OPT, + [ElidePermutations()], + ) +) + register_action( DeviceIndependentAction( "InverseCancellation", @@ -316,6 +327,15 @@ def remove_action(name: str) -> None: ) ) +register_action( + DeviceIndependentAction( + "KAKDecomposition", + CompilationOrigin.TKET, + PassType.OPT, + [KAKDecomposition(allow_swaps=False)], + ) +) + register_action( DeviceIndependentAction( "FullPeepholeOptimiseCX", diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index e5fe95d52..4c2cebddf 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -17,7 +17,7 @@ import numpy as np from qiskit import QuantumCircuit -from mqt.predictor.utils import calc_supermarq_features +from mqt.predictor.utils import calc_supermarq_features, get_openqasm_gates if TYPE_CHECKING: from numpy.random import Generator @@ -69,6 +69,18 @@ def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generat return qc, str(file_list[random_index]) +def dict_to_featurevector(gate_dict: dict[str, int]) -> dict[str, float]: + """Calculates and returns a normalized feature vector of a given quantum circuit gate dictionary.""" + res_dct = dict.fromkeys(get_openqasm_gates(), 0.0) + exclude_from_total = {"barrier"} + total = sum(val for key, val in gate_dict.items() if key not in exclude_from_total) + + for key, val in gate_dict.items(): + if key in res_dct: + res_dct[key] = val / total if total > 0 else 0.0 + return res_dct + + def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float64]]: """Creates a feature dictionary for a given quantum circuit. @@ -78,7 +90,13 @@ def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float6 Returns: The feature dictionary for the given quantum circuit. """ + ops_list = qc.count_ops() + total = sum(val for key, val in ops_list.items() if key != "barrier") + ops_list_dict = dict_to_featurevector(ops_list) + feature_dict = { + **{key: np.array([val], dtype=np.float32) for key, val in ops_list_dict.items()}, + "measure": np.array([ops_list.get("measure", 0) / total if total > 0 else 0.0], dtype=np.float32), "num_qubits": qc.num_qubits, "depth": qc.depth(), } diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 53d2c9df2..68dd47330 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -82,6 +82,7 @@ postprocess_vf2postlayout, prepare_noise_data, ) +from mqt.predictor.utils import get_openqasm_gates logger = logging.getLogger("mqt-predictor") @@ -177,6 +178,8 @@ def __init__( self.has_parameterized_gates = False self.rng = np.random.default_rng(10) + gate_spaces = {g: Box(low=0, high=1, shape=(1,), dtype=np.float32) for g in get_openqasm_gates()} + spaces = { "num_qubits": Discrete(self.device.num_qubits + 1), "depth": Discrete(1000000), @@ -185,6 +188,8 @@ def __init__( "entanglement_ratio": Box(low=0, high=1, shape=(1,), dtype=np.float32), "parallelism": Box(low=0, high=1, shape=(1,), dtype=np.float32), "liveness": Box(low=0, high=1, shape=(1,), dtype=np.float32), + "measure": Box(low=0, high=1, shape=(1,), dtype=np.float32), + **gate_spaces, } self.observation_space = Dict(spaces) self.filename = "" diff --git a/src/mqt/predictor/utils.py b/src/mqt/predictor/utils.py index 4112dfb13..42c24d424 100644 --- a/src/mqt/predictor/utils.py +++ b/src/mqt/predictor/utils.py @@ -143,3 +143,45 @@ def calc_supermarq_features( parallelism, liveness, ) + + +def get_openqasm_gates() -> list[str]: + """Returns a list of all quantum gates within the openQASM 2.0 standard header.""" + # according to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc + # u,u0,u1,u2,u3 gates are excluded as they are not meaningful as RL features + # Drop multi-qubit gates with more than two qubits, since Qiskit's `basis_gates` argument does not support them. + return [ + "cx", + "id", + "p", + "x", + "y", + "z", + "h", + "s", + "sdg", + "t", + "tdg", + "r", + "rx", + "ry", + "rz", + "sx", + "sxdg", + "cz", + "cy", + "swap", + "ch", + "ccx", + "cswap", + "crx", + "cry", + "crz", + "cu1", + "cp", + "cu3", + "csx", + "cu", + "rxx", + "rzz", + ] From cb4d0fb08182787eccafc909e4c826caa61df099 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 20 Nov 2025 16:46:51 +0100 Subject: [PATCH 59/98] Fix FOM comparison logic --- src/mqt/predictor/rl/predictorenv.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 68dd47330..5e7c8ff11 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -137,7 +137,7 @@ def __init__( for elem in action_dict[PassType.OPT]: self.action_set[index] = elem self.actions_opt_indices.append(index) - if getattr(elem, "preserve", False): + if getattr(elem, "preserve_layout", False): self.actions_mapping_preserving_indices.append(index) index += 1 for elem in action_dict[PassType.LAYOUT]: @@ -375,7 +375,13 @@ def fom_aware_compile( """ best_result = None best_property_set = None - best_fom = -1.0 + maximize = self.reward_function in [ + "expected_fidelity", + "estimated_success_probability", + "estimated_hellinger_distance", + "critical_depth", + ] + best_fom = -1.0 if maximize else float("inf") best_swap_count = float("inf") # for fallback assert callable(action.transpile_pass), "Mapping action should be callable" @@ -387,11 +393,7 @@ def fom_aware_compile( try: # Synthesize for lookahead fidelity (Mapping could insert non-local SWAP gates) - if self.reward_function in [ - "expected_fidelity", - "estimated_success_probability", - "estimated_hellinger_distance", - ]: + if maximize: synth_pass = PassManager([ BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names) ]) @@ -412,7 +414,7 @@ def fom_aware_compile( except Exception as e: logger.warning(f"[Fallback to SWAP counts] Synthesis or fidelity computation failed: {e}") swap_count = out_circ.count_ops().get("swap", 0) - if best_result is None or (best_fom == -1.0 and swap_count < best_swap_count): + if best_result is None or swap_count < best_swap_count: best_swap_count = swap_count best_result = out_circ best_property_set = prop_set @@ -424,7 +426,7 @@ def fom_aware_compile( if best_result is not None: return best_result, best_property_set logger.error("All attempts failed.") - return qc, {} + return qc, None def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: pm_property_set: PropertySet | None = {} From 988a8f77785a0083bffa790667b17f861b37b4c9 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 21 Nov 2025 17:00:09 +0100 Subject: [PATCH 60/98] Remove 3-qubit gates from dict --- src/mqt/predictor/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mqt/predictor/utils.py b/src/mqt/predictor/utils.py index 42c24d424..08da658ab 100644 --- a/src/mqt/predictor/utils.py +++ b/src/mqt/predictor/utils.py @@ -172,8 +172,6 @@ def get_openqasm_gates() -> list[str]: "cy", "swap", "ch", - "ccx", - "cswap", "crx", "cry", "crz", From a3d4baae64d0b890b7ed787cb08497879b37b85e Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 27 Nov 2025 15:15:45 +0100 Subject: [PATCH 61/98] Update docs and comments --- CHANGELOG.md | 2 +- noxfile.py | 18 ------------------ src/mqt/predictor/rl/helper.py | 4 ++-- src/mqt/predictor/rl/predictorenv.py | 14 +++++++++++--- src/mqt/predictor/utils.py | 2 +- 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dba76d455..39c1d6e61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Changed -- 🔧 Changed test circuit level for RL predictor from ALG to INDEP +- 🔧 Changed test circuit level for RL predictor from ALG to INDEP ([#449]) ([**@Shaobo-Zhou**]) - ✨ Remove support for custom names of trained models ([#489]) ([**@bachase**]) - 🔥 Drop support for x86 macOS systems ([#421]) ([**@denialhaag**]) diff --git a/noxfile.py b/noxfile.py index a1fcce546..e5602a3a4 100755 --- a/noxfile.py +++ b/noxfile.py @@ -18,7 +18,6 @@ import argparse import contextlib import os -import pathlib import shutil import tempfile from typing import TYPE_CHECKING @@ -61,21 +60,6 @@ def lint(session: nox.Session) -> None: session.run("pre-commit", "run", "--all-files", *session.posargs, external=True) -def _cleanup(session: nox.Session) -> None: - """Remove this session's virtualenv to save disk space in CI.""" - version = session.python - if version != "3.13": # keep cache for last run - venv_dir = session.virtualenv.location - if venv_dir and pathlib.Path(venv_dir).exists(): - shutil.rmtree(venv_dir, ignore_errors=True) - session.log(f"Cleaned up {venv_dir}") - shutil.rmtree(pathlib.Path("~/.cache").expanduser(), ignore_errors=True) - gha_temp = pathlib.Path("/home/runner/work/_temp/setup-uv-cache") - if gha_temp.exists(): - shutil.rmtree(gha_temp, ignore_errors=True) - session.log(f"Cleaned GitHub Actions uv temp cache at {gha_temp}") - - def _run_tests( session: nox.Session, *, @@ -109,8 +93,6 @@ def _run_tests( def tests(session: nox.Session) -> None: """Run the test suite.""" _run_tests(session) - if os.environ.get("CI"): - _cleanup(session) @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True) diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 4c2cebddf..7f5da72de 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -17,7 +17,7 @@ import numpy as np from qiskit import QuantumCircuit -from mqt.predictor.utils import calc_supermarq_features, get_openqasm_gates +from mqt.predictor.utils import calc_supermarq_features, get_rl_openqasm_gates if TYPE_CHECKING: from numpy.random import Generator @@ -71,7 +71,7 @@ def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generat def dict_to_featurevector(gate_dict: dict[str, int]) -> dict[str, float]: """Calculates and returns a normalized feature vector of a given quantum circuit gate dictionary.""" - res_dct = dict.fromkeys(get_openqasm_gates(), 0.0) + res_dct = dict.fromkeys(get_rl_openqasm_gates(), 0.0) exclude_from_total = {"barrier"} total = sum(val for key, val in gate_dict.items() if key not in exclude_from_total) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 5e7c8ff11..5bef727c2 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -82,7 +82,7 @@ postprocess_vf2postlayout, prepare_noise_data, ) -from mqt.predictor.utils import get_openqasm_gates +from mqt.predictor.utils import get_rl_openqasm_gates logger = logging.getLogger("mqt-predictor") @@ -178,7 +178,7 @@ def __init__( self.has_parameterized_gates = False self.rng = np.random.default_rng(10) - gate_spaces = {g: Box(low=0, high=1, shape=(1,), dtype=np.float32) for g in get_openqasm_gates()} + gate_spaces = {g: Box(low=0, high=1, shape=(1,), dtype=np.float32) for g in get_rl_openqasm_gates()} spaces = { "num_qubits": Discrete(self.device.num_qubits + 1), @@ -392,7 +392,15 @@ def fom_aware_compile( prop_set = dict(pm.property_set) try: - # Synthesize for lookahead fidelity (Mapping could insert non-local SWAP gates) + # For fidelity-based metrics, do a cheap "lookahead" synthesis step: + # routing may have introduced non-native SWAPs, so we translate the + # circuit into the device's native basis before evaluating the metric. + # + # Note: + # - BasisTranslator *only* performs basis conversion; it does not optimize. + # - This isolates the effect of mapping (inserted SWAPs) on fidelity + # without conflating it with further optimizations. + if maximize: synth_pass = PassManager([ BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names) diff --git a/src/mqt/predictor/utils.py b/src/mqt/predictor/utils.py index 08da658ab..027be0423 100644 --- a/src/mqt/predictor/utils.py +++ b/src/mqt/predictor/utils.py @@ -145,7 +145,7 @@ def calc_supermarq_features( ) -def get_openqasm_gates() -> list[str]: +def get_rl_openqasm_gates() -> list[str]: """Returns a list of all quantum gates within the openQASM 2.0 standard header.""" # according to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc # u,u0,u1,u2,u3 gates are excluded as they are not meaningful as RL features From ea40f6a3ee06128f5bd05eec98b24b4ae9571e45 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 27 Nov 2025 15:30:52 +0100 Subject: [PATCH 62/98] Minor Fixes --- src/mqt/predictor/rl/predictorenv.py | 37 +++++++++------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 5bef727c2..ee3577e2e 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -375,13 +375,7 @@ def fom_aware_compile( """ best_result = None best_property_set = None - maximize = self.reward_function in [ - "expected_fidelity", - "estimated_success_probability", - "estimated_hellinger_distance", - "critical_depth", - ] - best_fom = -1.0 if maximize else float("inf") + best_fom = -1.0 best_swap_count = float("inf") # for fallback assert callable(action.transpile_pass), "Mapping action should be callable" @@ -401,23 +395,16 @@ def fom_aware_compile( # - This isolates the effect of mapping (inserted SWAPs) on fidelity # without conflating it with further optimizations. - if maximize: - synth_pass = PassManager([ - BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names) - ]) - synth_circ = synth_pass.run(out_circ.copy()) - fom = self.calculate_reward(synth_circ) - - if fom > best_fom: - best_fom = fom - best_result = out_circ - best_property_set = prop_set - else: - fom = self.calculate_reward(out_circ) - if fom < best_fom: - best_fom = fom - best_result = out_circ - best_property_set = prop_set + synth_pass = PassManager([ + BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names) + ]) + synth_circ = synth_pass.run(out_circ.copy()) + fom = self.calculate_reward(synth_circ) + + if fom > best_fom: + best_fom = fom + best_result = out_circ + best_property_set = prop_set except Exception as e: logger.warning(f"[Fallback to SWAP counts] Synthesis or fidelity computation failed: {e}") @@ -525,7 +512,7 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui try: placement = transpile_pass[0].get_placement_map(tket_qc) except Exception as e: - logger.warning(f"Placement failed ({action.name}): {e}. Falling back to original circuit.") + logger.warning("Placement failed (%s): %s. Falling back to original circuit.", action.name, e) return tk_to_qiskit(tket_qc, replace_implicit_swaps=True) else: qc_tmp = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) From 914192c1176b30de6a1cbf40c4880a69d62a8f78 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:34:24 +0000 Subject: [PATCH 63/98] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index 9f8bb8cc7..db59b3577 100644 --- a/uv.lock +++ b/uv.lock @@ -4027,4 +4027,4 @@ source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, -] \ No newline at end of file +] From a4ec1c7c21d3237bf1b5ae629c61cf8aae16feca Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 3 Dec 2025 16:12:43 +0100 Subject: [PATCH 64/98] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c1d6e61..baf8733e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Changed +- ✨ Improved the MDP for RL ([#449]) ([**@Shaobo-Zhou**]) - 🔧 Changed test circuit level for RL predictor from ALG to INDEP ([#449]) ([**@Shaobo-Zhou**]) - ✨ Remove support for custom names of trained models ([#489]) ([**@bachase**]) - 🔥 Drop support for x86 macOS systems ([#421]) ([**@denialhaag**]) @@ -45,6 +46,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool +[#449]: https://github.com/munich-quantum-toolkit/predictor/pull/449 [#489]: https://github.com/munich-quantum-toolkit/predictor/pull/489 [#421]: https://github.com/munich-quantum-toolkit/predictor/pull/421 [#406]: https://github.com/munich-quantum-toolkit/predictor/pull/406 @@ -62,6 +64,7 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool [**@flowerthrower**]: https://github.com/flowerthrower [**@denialhaag**]: https://github.com/denialhaag [**@bachase**]: https://github.com/bachase +[**@Shaobo-Zhou**]: https://github.com/Shaobo-Zhou From 0f5f6361b93e66a73d3d2c3b7e620830c346d702 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:23:38 +0000 Subject: [PATCH 65/98] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index 9f8bb8cc7..db59b3577 100644 --- a/uv.lock +++ b/uv.lock @@ -4027,4 +4027,4 @@ source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, -] \ No newline at end of file +] From 283345bce63b4bbedb1e721295425a0acc956e8e Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 3 Dec 2025 16:30:14 +0100 Subject: [PATCH 66/98] Small fixes --- src/mqt/predictor/rl/actions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 513984be0..a762dd559 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -195,8 +195,6 @@ def remove_action(name: str) -> None: "Optimize1qGatesDecomposition", CompilationOrigin.QISKIT, PassType.OPT, - # If no basis_gates are passed, fallback 1q Euler gates: - # https://github.com/Qiskit/qiskit/blob/main/qiskit/synthesis/one_qubit/one_qubit_decompose.py#L46 [Optimize1qGatesDecomposition()], ) ) From 108a3269afbd6f1961ae9e7d7760e4181d682057 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 3 Dec 2025 16:34:23 +0100 Subject: [PATCH 67/98] Update uv.lock --- uv.lock | 339 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 207 insertions(+), 132 deletions(-) diff --git a/uv.lock b/uv.lock index db59b3577..9e805fe20 100644 --- a/uv.lock +++ b/uv.lock @@ -71,6 +71,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + [[package]] name = "astroid" version = "3.3.11" @@ -319,6 +328,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + [[package]] name = "comm" version = "0.2.3" @@ -491,87 +512,101 @@ wheels = [ [[package]] name = "coverage" -version = "7.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/76/17780846fc7aade1e66712e1e27dd28faa0a5d987a1f433610974959eaa8/coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055", size = 820754, upload-time = "2025-08-04T00:35:17.511Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/5f/5ce748ab3f142593698aff5f8a0cf020775aa4e24b9d8748b5a56b64d3f8/coverage-7.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:79f0283ab5e6499fd5fe382ca3d62afa40fb50ff227676a3125d18af70eabf65", size = 215003, upload-time = "2025-08-04T00:33:02.977Z" }, - { url = "https://files.pythonhosted.org/packages/f4/ed/507088561217b000109552139802fa99c33c16ad19999c687b601b3790d0/coverage-7.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4545e906f595ee8ab8e03e21be20d899bfc06647925bc5b224ad7e8c40e08b8", size = 215391, upload-time = "2025-08-04T00:33:05.645Z" }, - { url = "https://files.pythonhosted.org/packages/79/1b/0f496259fe137c4c5e1e8eaff496fb95af88b71700f5e57725a4ddbe742b/coverage-7.10.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ae385e1d58fbc6a9b1c315e5510ac52281e271478b45f92ca9b5ad42cf39643f", size = 242367, upload-time = "2025-08-04T00:33:07.189Z" }, - { url = "https://files.pythonhosted.org/packages/b9/8e/5a8835fb0122a2e2a108bf3527931693c4625fdc4d953950a480b9625852/coverage-7.10.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f0cbe5f7dd19f3a32bac2251b95d51c3b89621ac88a2648096ce40f9a5aa1e7", size = 243627, upload-time = "2025-08-04T00:33:08.809Z" }, - { url = "https://files.pythonhosted.org/packages/c3/96/6a528429c2e0e8d85261764d0cd42e51a429510509bcc14676ee5d1bb212/coverage-7.10.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd17f427f041f6b116dc90b4049c6f3e1230524407d00daa2d8c7915037b5947", size = 245485, upload-time = "2025-08-04T00:33:10.29Z" }, - { url = "https://files.pythonhosted.org/packages/bf/82/1fba935c4d02c33275aca319deabf1f22c0f95f2c0000bf7c5f276d6f7b4/coverage-7.10.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7f10ca4cde7b466405cce0a0e9971a13eb22e57a5ecc8b5f93a81090cc9c7eb9", size = 243429, upload-time = "2025-08-04T00:33:11.909Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a8/c8dc0a57a729fc93be33ab78f187a8f52d455fa8f79bfb379fe23b45868d/coverage-7.10.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b990df23dd51dccce26d18fb09fd85a77ebe46368f387b0ffba7a74e470b31b", size = 242104, upload-time = "2025-08-04T00:33:13.467Z" }, - { url = "https://files.pythonhosted.org/packages/b9/6f/0b7da1682e2557caeed299a00897b42afde99a241a01eba0197eb982b90f/coverage-7.10.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc3902584d25c7eef57fb38f440aa849a26a3a9f761a029a72b69acfca4e31f8", size = 242397, upload-time = "2025-08-04T00:33:14.682Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e4/54dc833dadccd519c04a28852f39a37e522bad35d70cfe038817cdb8f168/coverage-7.10.2-cp310-cp310-win32.whl", hash = "sha256:9dd37e9ac00d5eb72f38ed93e3cdf2280b1dbda3bb9b48c6941805f265ad8d87", size = 217502, upload-time = "2025-08-04T00:33:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e7/2f78159c4c127549172f427dff15b02176329327bf6a6a1fcf1f603b5456/coverage-7.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:99d16f15cb5baf0729354c5bd3080ae53847a4072b9ba1e10957522fb290417f", size = 218388, upload-time = "2025-08-04T00:33:17.4Z" }, - { url = "https://files.pythonhosted.org/packages/6e/53/0125a6fc0af4f2687b4e08b0fb332cd0d5e60f3ca849e7456f995d022656/coverage-7.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c3b210d79925a476dfc8d74c7d53224888421edebf3a611f3adae923e212b27", size = 215119, upload-time = "2025-08-04T00:33:19.101Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2e/960d9871de9152dbc9ff950913c6a6e9cf2eb4cc80d5bc8f93029f9f2f9f/coverage-7.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf67d1787cd317c3f8b2e4c6ed1ae93497be7e30605a0d32237ac37a37a8a322", size = 215511, upload-time = "2025-08-04T00:33:20.32Z" }, - { url = "https://files.pythonhosted.org/packages/3f/34/68509e44995b9cad806d81b76c22bc5181f3535bca7cd9c15791bfd8951e/coverage-7.10.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:069b779d03d458602bc0e27189876e7d8bdf6b24ac0f12900de22dd2154e6ad7", size = 245513, upload-time = "2025-08-04T00:33:21.896Z" }, - { url = "https://files.pythonhosted.org/packages/ef/d4/9b12f357413248ce40804b0f58030b55a25b28a5c02db95fb0aa50c5d62c/coverage-7.10.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c2de4cb80b9990e71c62c2d3e9f3ec71b804b1f9ca4784ec7e74127e0f42468", size = 247350, upload-time = "2025-08-04T00:33:23.917Z" }, - { url = "https://files.pythonhosted.org/packages/b6/40/257945eda1f72098e4a3c350b1d68fdc5d7d032684a0aeb6c2391153ecf4/coverage-7.10.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75bf7ab2374a7eb107602f1e07310cda164016cd60968abf817b7a0b5703e288", size = 249516, upload-time = "2025-08-04T00:33:25.5Z" }, - { url = "https://files.pythonhosted.org/packages/ff/55/8987f852ece378cecbf39a367f3f7ec53351e39a9151b130af3a3045b83f/coverage-7.10.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3f37516458ec1550815134937f73d6d15b434059cd10f64678a2068f65c62406", size = 247241, upload-time = "2025-08-04T00:33:26.767Z" }, - { url = "https://files.pythonhosted.org/packages/df/ae/da397de7a42a18cea6062ed9c3b72c50b39e0b9e7b2893d7172d3333a9a1/coverage-7.10.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:de3c6271c482c250d3303fb5c6bdb8ca025fff20a67245e1425df04dc990ece9", size = 245274, upload-time = "2025-08-04T00:33:28.494Z" }, - { url = "https://files.pythonhosted.org/packages/4e/64/7baa895eb55ec0e1ec35b988687ecd5d4475ababb0d7ae5ca3874dd90ee7/coverage-7.10.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:98a838101321ac3089c9bb1d4bfa967e8afed58021fda72d7880dc1997f20ae1", size = 245882, upload-time = "2025-08-04T00:33:30.048Z" }, - { url = "https://files.pythonhosted.org/packages/24/6c/1fd76a0bd09ae75220ae9775a8290416d726f0e5ba26ea72346747161240/coverage-7.10.2-cp311-cp311-win32.whl", hash = "sha256:f2a79145a531a0e42df32d37be5af069b4a914845b6f686590739b786f2f7bce", size = 217541, upload-time = "2025-08-04T00:33:31.376Z" }, - { url = "https://files.pythonhosted.org/packages/5f/2d/8c18fb7a6e74c79fd4661e82535bc8c68aee12f46c204eabf910b097ccc9/coverage-7.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:e4f5f1320f8ee0d7cfa421ceb257bef9d39fd614dd3ddcfcacd284d4824ed2c2", size = 218426, upload-time = "2025-08-04T00:33:32.976Z" }, - { url = "https://files.pythonhosted.org/packages/da/40/425bb35e4ff7c7af177edf5dffd4154bc2a677b27696afe6526d75c77fec/coverage-7.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:d8f2d83118f25328552c728b8e91babf93217db259ca5c2cd4dd4220b8926293", size = 217116, upload-time = "2025-08-04T00:33:34.302Z" }, - { url = "https://files.pythonhosted.org/packages/4e/1e/2c752bdbbf6f1199c59b1a10557fbb6fb3dc96b3c0077b30bd41a5922c1f/coverage-7.10.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:890ad3a26da9ec7bf69255b9371800e2a8da9bc223ae5d86daeb940b42247c83", size = 215311, upload-time = "2025-08-04T00:33:35.524Z" }, - { url = "https://files.pythonhosted.org/packages/68/6a/84277d73a2cafb96e24be81b7169372ba7ff28768ebbf98e55c85a491b0f/coverage-7.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38fd1ccfca7838c031d7a7874d4353e2f1b98eb5d2a80a2fe5732d542ae25e9c", size = 215550, upload-time = "2025-08-04T00:33:37.109Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e7/5358b73b46ac76f56cc2de921eeabd44fabd0b7ff82ea4f6b8c159c4d5dc/coverage-7.10.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76c1ffaaf4f6f0f6e8e9ca06f24bb6454a7a5d4ced97a1bc466f0d6baf4bd518", size = 246564, upload-time = "2025-08-04T00:33:38.33Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0e/b0c901dd411cb7fc0cfcb28ef0dc6f3049030f616bfe9fc4143aecd95901/coverage-7.10.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86da8a3a84b79ead5c7d0e960c34f580bc3b231bb546627773a3f53c532c2f21", size = 248993, upload-time = "2025-08-04T00:33:39.555Z" }, - { url = "https://files.pythonhosted.org/packages/0e/4e/a876db272072a9e0df93f311e187ccdd5f39a190c6d1c1f0b6e255a0d08e/coverage-7.10.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cef9731c8a39801830a604cc53c93c9e57ea8b44953d26589499eded9576e0", size = 250454, upload-time = "2025-08-04T00:33:41.023Z" }, - { url = "https://files.pythonhosted.org/packages/64/d6/1222dc69f8dd1be208d55708a9f4a450ad582bf4fa05320617fea1eaa6d8/coverage-7.10.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea58b112f2966a8b91eb13f5d3b1f8bb43c180d624cd3283fb33b1cedcc2dd75", size = 248365, upload-time = "2025-08-04T00:33:42.376Z" }, - { url = "https://files.pythonhosted.org/packages/62/e3/40fd71151064fc315c922dd9a35e15b30616f00146db1d6a0b590553a75a/coverage-7.10.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:20f405188d28da9522b7232e51154e1b884fc18d0b3a10f382d54784715bbe01", size = 246562, upload-time = "2025-08-04T00:33:43.663Z" }, - { url = "https://files.pythonhosted.org/packages/fc/14/8aa93ddcd6623ddaef5d8966268ac9545b145bce4fe7b1738fd1c3f0d957/coverage-7.10.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:64586ce42bbe0da4d9f76f97235c545d1abb9b25985a8791857690f96e23dc3b", size = 247772, upload-time = "2025-08-04T00:33:45.068Z" }, - { url = "https://files.pythonhosted.org/packages/07/4e/dcb1c01490623c61e2f2ea85cb185fa6a524265bb70eeb897d3c193efeb9/coverage-7.10.2-cp312-cp312-win32.whl", hash = "sha256:bc2e69b795d97ee6d126e7e22e78a509438b46be6ff44f4dccbb5230f550d340", size = 217710, upload-time = "2025-08-04T00:33:46.378Z" }, - { url = "https://files.pythonhosted.org/packages/79/16/e8aab4162b5f80ad2e5e1f54b1826e2053aa2f4db508b864af647f00c239/coverage-7.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:adda2268b8cf0d11f160fad3743b4dfe9813cd6ecf02c1d6397eceaa5b45b388", size = 218499, upload-time = "2025-08-04T00:33:48.048Z" }, - { url = "https://files.pythonhosted.org/packages/06/7f/c112ec766e8f1131ce8ce26254be028772757b2d1e63e4f6a4b0ad9a526c/coverage-7.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:164429decd0d6b39a0582eaa30c67bf482612c0330572343042d0ed9e7f15c20", size = 217154, upload-time = "2025-08-04T00:33:49.299Z" }, - { url = "https://files.pythonhosted.org/packages/8d/04/9b7a741557f93c0ed791b854d27aa8d9fe0b0ce7bb7c52ca1b0f2619cb74/coverage-7.10.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aca7b5645afa688de6d4f8e89d30c577f62956fefb1bad021490d63173874186", size = 215337, upload-time = "2025-08-04T00:33:50.61Z" }, - { url = "https://files.pythonhosted.org/packages/02/a4/8d1088cd644750c94bc305d3cf56082b4cdf7fb854a25abb23359e74892f/coverage-7.10.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96e5921342574a14303dfdb73de0019e1ac041c863743c8fe1aa6c2b4a257226", size = 215596, upload-time = "2025-08-04T00:33:52.33Z" }, - { url = "https://files.pythonhosted.org/packages/01/2f/643a8d73343f70e162d8177a3972b76e306b96239026bc0c12cfde4f7c7a/coverage-7.10.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11333094c1bff621aa811b67ed794865cbcaa99984dedea4bd9cf780ad64ecba", size = 246145, upload-time = "2025-08-04T00:33:53.641Z" }, - { url = "https://files.pythonhosted.org/packages/1f/4a/722098d1848db4072cda71b69ede1e55730d9063bf868375264d0d302bc9/coverage-7.10.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6eb586fa7d2aee8d65d5ae1dd71414020b2f447435c57ee8de8abea0a77d5074", size = 248492, upload-time = "2025-08-04T00:33:55.366Z" }, - { url = "https://files.pythonhosted.org/packages/3f/b0/8a6d7f326f6e3e6ed398cde27f9055e860a1e858317001835c521673fb60/coverage-7.10.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d358f259d8019d4ef25d8c5b78aca4c7af25e28bd4231312911c22a0e824a57", size = 249927, upload-time = "2025-08-04T00:33:57.042Z" }, - { url = "https://files.pythonhosted.org/packages/bb/21/1aaadd3197b54d1e61794475379ecd0f68d8fc5c2ebd352964dc6f698a3d/coverage-7.10.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5250bda76e30382e0a2dcd68d961afcab92c3a7613606e6269855c6979a1b0bb", size = 248138, upload-time = "2025-08-04T00:33:58.329Z" }, - { url = "https://files.pythonhosted.org/packages/48/65/be75bafb2bdd22fd8bf9bf63cd5873b91bb26ec0d68f02d4b8b09c02decb/coverage-7.10.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a91e027d66eff214d88d9afbe528e21c9ef1ecdf4956c46e366c50f3094696d0", size = 246111, upload-time = "2025-08-04T00:33:59.899Z" }, - { url = "https://files.pythonhosted.org/packages/5e/30/a4f0c5e249c3cc60e6c6f30d8368e372f2d380eda40e0434c192ac27ccf5/coverage-7.10.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:228946da741558904e2c03ce870ba5efd9cd6e48cbc004d9a27abee08100a15a", size = 247493, upload-time = "2025-08-04T00:34:01.619Z" }, - { url = "https://files.pythonhosted.org/packages/85/99/f09b9493e44a75cf99ca834394c12f8cb70da6c1711ee296534f97b52729/coverage-7.10.2-cp313-cp313-win32.whl", hash = "sha256:95e23987b52d02e7c413bf2d6dc6288bd5721beb518052109a13bfdc62c8033b", size = 217756, upload-time = "2025-08-04T00:34:03.277Z" }, - { url = "https://files.pythonhosted.org/packages/2d/bb/cbcb09103be330c7d26ff0ab05c4a8861dd2e254656fdbd3eb7600af4336/coverage-7.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:f35481d42c6d146d48ec92d4e239c23f97b53a3f1fbd2302e7c64336f28641fe", size = 218526, upload-time = "2025-08-04T00:34:04.635Z" }, - { url = "https://files.pythonhosted.org/packages/37/8f/8bfb4e0bca52c00ab680767c0dd8cfd928a2a72d69897d9b2d5d8b5f63f5/coverage-7.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:65b451949cb789c346f9f9002441fc934d8ccedcc9ec09daabc2139ad13853f7", size = 217176, upload-time = "2025-08-04T00:34:05.973Z" }, - { url = "https://files.pythonhosted.org/packages/1e/25/d458ba0bf16a8204a88d74dbb7ec5520f29937ffcbbc12371f931c11efd2/coverage-7.10.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8415918856a3e7d57a4e0ad94651b761317de459eb74d34cc1bb51aad80f07e", size = 216058, upload-time = "2025-08-04T00:34:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1c/af4dfd2d7244dc7610fed6d59d57a23ea165681cd764445dc58d71ed01a6/coverage-7.10.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f287a25a8ca53901c613498e4a40885b19361a2fe8fbfdbb7f8ef2cad2a23f03", size = 216273, upload-time = "2025-08-04T00:34:09.073Z" }, - { url = "https://files.pythonhosted.org/packages/8e/67/ec5095d4035c6e16368226fa9cb15f77f891194c7e3725aeefd08e7a3e5a/coverage-7.10.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:75cc1a3f8c88c69bf16a871dab1fe5a7303fdb1e9f285f204b60f1ee539b8fc0", size = 257513, upload-time = "2025-08-04T00:34:10.403Z" }, - { url = "https://files.pythonhosted.org/packages/1c/47/be5550b57a3a8ba797de4236b0fd31031f88397b2afc84ab3c2d4cf265f6/coverage-7.10.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca07fa78cc9d26bc8c4740de1abd3489cf9c47cc06d9a8ab3d552ff5101af4c0", size = 259377, upload-time = "2025-08-04T00:34:12.138Z" }, - { url = "https://files.pythonhosted.org/packages/37/50/b12a4da1382e672305c2d17cd3029dc16b8a0470de2191dbf26b91431378/coverage-7.10.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2e117e64c26300032755d4520cd769f2623cde1a1d1c3515b05a3b8add0ade1", size = 261516, upload-time = "2025-08-04T00:34:13.608Z" }, - { url = "https://files.pythonhosted.org/packages/db/41/4d3296dbd33dd8da178171540ca3391af7c0184c0870fd4d4574ac290290/coverage-7.10.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:daaf98009977f577b71f8800208f4d40d4dcf5c2db53d4d822787cdc198d76e1", size = 259110, upload-time = "2025-08-04T00:34:15.089Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f1/b409959ecbc0cec0e61e65683b22bacaa4a3b11512f834e16dd8ffbc37db/coverage-7.10.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ea8d8fe546c528535c761ba424410bbeb36ba8a0f24be653e94b70c93fd8a8ca", size = 257248, upload-time = "2025-08-04T00:34:16.501Z" }, - { url = "https://files.pythonhosted.org/packages/48/ab/7076dc1c240412e9267d36ec93e9e299d7659f6a5c1e958f87e998b0fb6d/coverage-7.10.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fe024d40ac31eb8d5aae70215b41dafa264676caa4404ae155f77d2fa95c37bb", size = 258063, upload-time = "2025-08-04T00:34:18.338Z" }, - { url = "https://files.pythonhosted.org/packages/1e/77/f6b51a0288f8f5f7dcc7c89abdd22cf514f3bc5151284f5cd628917f8e10/coverage-7.10.2-cp313-cp313t-win32.whl", hash = "sha256:8f34b09f68bdadec122ffad312154eda965ade433559cc1eadd96cca3de5c824", size = 218433, upload-time = "2025-08-04T00:34:19.71Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6d/547a86493e25270ce8481543e77f3a0aa3aa872c1374246b7b76273d66eb/coverage-7.10.2-cp313-cp313t-win_amd64.whl", hash = "sha256:71d40b3ac0f26fa9ffa6ee16219a714fed5c6ec197cdcd2018904ab5e75bcfa3", size = 219523, upload-time = "2025-08-04T00:34:21.171Z" }, - { url = "https://files.pythonhosted.org/packages/ff/d5/3c711e38eaf9ab587edc9bed232c0298aed84e751a9f54aaa556ceaf7da6/coverage-7.10.2-cp313-cp313t-win_arm64.whl", hash = "sha256:abb57fdd38bf6f7dcc66b38dafb7af7c5fdc31ac6029ce373a6f7f5331d6f60f", size = 217739, upload-time = "2025-08-04T00:34:22.514Z" }, - { url = "https://files.pythonhosted.org/packages/71/53/83bafa669bb9d06d4c8c6a055d8d05677216f9480c4698fb183ba7ec5e47/coverage-7.10.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a3e853cc04987c85ec410905667eed4bf08b1d84d80dfab2684bb250ac8da4f6", size = 215328, upload-time = "2025-08-04T00:34:23.991Z" }, - { url = "https://files.pythonhosted.org/packages/1d/6c/30827a9c5a48a813e865fbaf91e2db25cce990bd223a022650ef2293fe11/coverage-7.10.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0100b19f230df72c90fdb36db59d3f39232391e8d89616a7de30f677da4f532b", size = 215608, upload-time = "2025-08-04T00:34:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a0/c92d85948056ddc397b72a3d79d36d9579c53cb25393ed3c40db7d33b193/coverage-7.10.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9c1cd71483ea78331bdfadb8dcec4f4edfb73c7002c1206d8e0af6797853f5be", size = 246111, upload-time = "2025-08-04T00:34:26.857Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/d695cf86b2559aadd072c91720a7844be4fb82cb4a3b642a2c6ce075692d/coverage-7.10.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f75dbf4899e29a37d74f48342f29279391668ef625fdac6d2f67363518056a1", size = 248419, upload-time = "2025-08-04T00:34:28.726Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0a/03206aec4a05986e039418c038470d874045f6e00426b0c3879adc1f9251/coverage-7.10.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7df481e7508de1c38b9b8043da48d94931aefa3e32b47dd20277e4978ed5b95", size = 250038, upload-time = "2025-08-04T00:34:30.061Z" }, - { url = "https://files.pythonhosted.org/packages/ab/9b/b3bd6bd52118c12bc4cf319f5baba65009c9beea84e665b6b9f03fa3f180/coverage-7.10.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:835f39e618099325e7612b3406f57af30ab0a0af350490eff6421e2e5f608e46", size = 248066, upload-time = "2025-08-04T00:34:31.53Z" }, - { url = "https://files.pythonhosted.org/packages/80/cc/bfa92e261d3e055c851a073e87ba6a3bff12a1f7134233e48a8f7d855875/coverage-7.10.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:12e52b5aa00aa720097d6947d2eb9e404e7c1101ad775f9661ba165ed0a28303", size = 245909, upload-time = "2025-08-04T00:34:32.943Z" }, - { url = "https://files.pythonhosted.org/packages/12/80/c8df15db4847710c72084164f615ae900af1ec380dce7f74a5678ccdf5e1/coverage-7.10.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:718044729bf1fe3e9eb9f31b52e44ddae07e434ec050c8c628bf5adc56fe4bdd", size = 247329, upload-time = "2025-08-04T00:34:34.388Z" }, - { url = "https://files.pythonhosted.org/packages/04/6f/cb66e1f7124d5dd9ced69f889f02931419cb448125e44a89a13f4e036124/coverage-7.10.2-cp314-cp314-win32.whl", hash = "sha256:f256173b48cc68486299d510a3e729a96e62c889703807482dbf56946befb5c8", size = 218007, upload-time = "2025-08-04T00:34:35.846Z" }, - { url = "https://files.pythonhosted.org/packages/8c/e1/3d4be307278ce32c1b9d95cc02ee60d54ddab784036101d053ec9e4fe7f5/coverage-7.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:2e980e4179f33d9b65ac4acb86c9c0dde904098853f27f289766657ed16e07b3", size = 218802, upload-time = "2025-08-04T00:34:37.35Z" }, - { url = "https://files.pythonhosted.org/packages/ec/66/1e43bbeb66c55a5a5efec70f1c153cf90cfc7f1662ab4ebe2d844de9122c/coverage-7.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:14fb5b6641ab5b3c4161572579f0f2ea8834f9d3af2f7dd8fbaecd58ef9175cc", size = 217397, upload-time = "2025-08-04T00:34:39.15Z" }, - { url = "https://files.pythonhosted.org/packages/81/01/ae29c129217f6110dc694a217475b8aecbb1b075d8073401f868c825fa99/coverage-7.10.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e96649ac34a3d0e6491e82a2af71098e43be2874b619547c3282fc11d3840a4b", size = 216068, upload-time = "2025-08-04T00:34:40.648Z" }, - { url = "https://files.pythonhosted.org/packages/a2/50/6e9221d4139f357258f36dfa1d8cac4ec56d9d5acf5fdcc909bb016954d7/coverage-7.10.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a2e934e9da26341d342d30bfe91422bbfdb3f1f069ec87f19b2909d10d8dcc4", size = 216285, upload-time = "2025-08-04T00:34:42.441Z" }, - { url = "https://files.pythonhosted.org/packages/eb/ec/89d1d0c0ece0d296b4588e0ef4df185200456d42a47f1141335f482c2fc5/coverage-7.10.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:651015dcd5fd9b5a51ca79ece60d353cacc5beaf304db750407b29c89f72fe2b", size = 257603, upload-time = "2025-08-04T00:34:43.899Z" }, - { url = "https://files.pythonhosted.org/packages/82/06/c830af66734671c778fc49d35b58339e8f0687fbd2ae285c3f96c94da092/coverage-7.10.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81bf6a32212f9f66da03d63ecb9cd9bd48e662050a937db7199dbf47d19831de", size = 259568, upload-time = "2025-08-04T00:34:45.519Z" }, - { url = "https://files.pythonhosted.org/packages/60/57/f280dd6f1c556ecc744fbf39e835c33d3ae987d040d64d61c6f821e87829/coverage-7.10.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d800705f6951f75a905ea6feb03fff8f3ea3468b81e7563373ddc29aa3e5d1ca", size = 261691, upload-time = "2025-08-04T00:34:47.019Z" }, - { url = "https://files.pythonhosted.org/packages/54/2b/c63a0acbd19d99ec32326164c23df3a4e18984fb86e902afdd66ff7b3d83/coverage-7.10.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:248b5394718e10d067354448dc406d651709c6765669679311170da18e0e9af8", size = 259166, upload-time = "2025-08-04T00:34:48.792Z" }, - { url = "https://files.pythonhosted.org/packages/fd/c5/cd2997dcfcbf0683634da9df52d3967bc1f1741c1475dd0e4722012ba9ef/coverage-7.10.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5c61675a922b569137cf943770d7ad3edd0202d992ce53ac328c5ff68213ccf4", size = 257241, upload-time = "2025-08-04T00:34:51.038Z" }, - { url = "https://files.pythonhosted.org/packages/16/26/c9e30f82fdad8d47aee90af4978b18c88fa74369ae0f0ba0dbf08cee3a80/coverage-7.10.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:52d708b5fd65589461381fa442d9905f5903d76c086c6a4108e8e9efdca7a7ed", size = 258139, upload-time = "2025-08-04T00:34:52.533Z" }, - { url = "https://files.pythonhosted.org/packages/c9/99/bdb7bd00bebcd3dedfb895fa9af8e46b91422993e4a37ac634a5f1113790/coverage-7.10.2-cp314-cp314t-win32.whl", hash = "sha256:916369b3b914186b2c5e5ad2f7264b02cff5df96cdd7cdad65dccd39aa5fd9f0", size = 218809, upload-time = "2025-08-04T00:34:54.075Z" }, - { url = "https://files.pythonhosted.org/packages/eb/5e/56a7852e38a04d1520dda4dfbfbf74a3d6dec932c20526968f7444763567/coverage-7.10.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5b9d538e8e04916a5df63052d698b30c74eb0174f2ca9cd942c981f274a18eaf", size = 219926, upload-time = "2025-08-04T00:34:55.643Z" }, - { url = "https://files.pythonhosted.org/packages/e0/12/7fbe6b9c52bb9d627e9556f9f2edfdbe88b315e084cdecc9afead0c3b36a/coverage-7.10.2-cp314-cp314t-win_arm64.whl", hash = "sha256:04c74f9ef1f925456a9fd23a7eef1103126186d0500ef9a0acb0bd2514bdc7cc", size = 217925, upload-time = "2025-08-04T00:34:57.564Z" }, - { url = "https://files.pythonhosted.org/packages/18/d8/9b768ac73a8ac2d10c080af23937212434a958c8d2a1c84e89b450237942/coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f", size = 206973, upload-time = "2025-08-04T00:35:15.918Z" }, +version = "7.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c", size = 819341, upload-time = "2025-11-18T13:34:20.766Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/4a/0dc3de1c172d35abe512332cfdcc43211b6ebce629e4cc42e6cd25ed8f4d/coverage-7.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:32b75c2ba3f324ee37af3ccee5b30458038c50b349ad9b88cee85096132a575b", size = 217409, upload-time = "2025-11-18T13:31:53.122Z" }, + { url = "https://files.pythonhosted.org/packages/01/c3/086198b98db0109ad4f84241e8e9ea7e5fb2db8c8ffb787162d40c26cc76/coverage-7.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cb2a1b6ab9fe833714a483a915de350abc624a37149649297624c8d57add089c", size = 217927, upload-time = "2025-11-18T13:31:54.458Z" }, + { url = "https://files.pythonhosted.org/packages/5d/5f/34614dbf5ce0420828fc6c6f915126a0fcb01e25d16cf141bf5361e6aea6/coverage-7.12.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5734b5d913c3755e72f70bf6cc37a0518d4f4745cde760c5d8e12005e62f9832", size = 244678, upload-time = "2025-11-18T13:31:55.805Z" }, + { url = "https://files.pythonhosted.org/packages/55/7b/6b26fb32e8e4a6989ac1d40c4e132b14556131493b1d06bc0f2be169c357/coverage-7.12.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b527a08cdf15753279b7afb2339a12073620b761d79b81cbe2cdebdb43d90daa", size = 246507, upload-time = "2025-11-18T13:31:57.05Z" }, + { url = "https://files.pythonhosted.org/packages/06/42/7d70e6603d3260199b90fb48b537ca29ac183d524a65cc31366b2e905fad/coverage-7.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb44c889fb68004e94cab71f6a021ec83eac9aeabdbb5a5a88821ec46e1da73", size = 248366, upload-time = "2025-11-18T13:31:58.362Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4a/d86b837923878424c72458c5b25e899a3c5ca73e663082a915f5b3c4d749/coverage-7.12.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b59b501455535e2e5dde5881739897967b272ba25988c89145c12d772810ccb", size = 245366, upload-time = "2025-11-18T13:31:59.572Z" }, + { url = "https://files.pythonhosted.org/packages/e6/c2/2adec557e0aa9721875f06ced19730fdb7fc58e31b02b5aa56f2ebe4944d/coverage-7.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8842f17095b9868a05837b7b1b73495293091bed870e099521ada176aa3e00e", size = 246408, upload-time = "2025-11-18T13:32:00.784Z" }, + { url = "https://files.pythonhosted.org/packages/5a/4b/8bd1f1148260df11c618e535fdccd1e5aaf646e55b50759006a4f41d8a26/coverage-7.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5a6f20bf48b8866095c6820641e7ffbe23f2ac84a2efc218d91235e404c7777", size = 244416, upload-time = "2025-11-18T13:32:01.963Z" }, + { url = "https://files.pythonhosted.org/packages/0e/13/3a248dd6a83df90414c54a4e121fd081fb20602ca43955fbe1d60e2312a9/coverage-7.12.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5f3738279524e988d9da2893f307c2093815c623f8d05a8f79e3eff3a7a9e553", size = 244681, upload-time = "2025-11-18T13:32:03.408Z" }, + { url = "https://files.pythonhosted.org/packages/76/30/aa833827465a5e8c938935f5d91ba055f70516941078a703740aaf1aa41f/coverage-7.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0d68c1f7eabbc8abe582d11fa393ea483caf4f44b0af86881174769f185c94d", size = 245300, upload-time = "2025-11-18T13:32:04.686Z" }, + { url = "https://files.pythonhosted.org/packages/38/24/f85b3843af1370fb3739fa7571819b71243daa311289b31214fe3e8c9d68/coverage-7.12.0-cp310-cp310-win32.whl", hash = "sha256:7670d860e18b1e3ee5930b17a7d55ae6287ec6e55d9799982aa103a2cc1fa2ef", size = 220008, upload-time = "2025-11-18T13:32:05.806Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a2/c7da5b9566f7164db9eefa133d17761ecb2c2fde9385d754e5b5c80f710d/coverage-7.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:f999813dddeb2a56aab5841e687b68169da0d3f6fc78ccf50952fa2463746022", size = 220943, upload-time = "2025-11-18T13:32:07.166Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0c/0dfe7f0487477d96432e4815537263363fb6dd7289743a796e8e51eabdf2/coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f", size = 217535, upload-time = "2025-11-18T13:32:08.812Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f5/f9a4a053a5bbff023d3bec259faac8f11a1e5a6479c2ccf586f910d8dac7/coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3", size = 218044, upload-time = "2025-11-18T13:32:10.329Z" }, + { url = "https://files.pythonhosted.org/packages/95/c5/84fc3697c1fa10cd8571919bf9693f693b7373278daaf3b73e328d502bc8/coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e", size = 248440, upload-time = "2025-11-18T13:32:12.536Z" }, + { url = "https://files.pythonhosted.org/packages/f4/36/2d93fbf6a04670f3874aed397d5a5371948a076e3249244a9e84fb0e02d6/coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7", size = 250361, upload-time = "2025-11-18T13:32:13.852Z" }, + { url = "https://files.pythonhosted.org/packages/5d/49/66dc65cc456a6bfc41ea3d0758c4afeaa4068a2b2931bf83be6894cf1058/coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245", size = 252472, upload-time = "2025-11-18T13:32:15.068Z" }, + { url = "https://files.pythonhosted.org/packages/35/1f/ebb8a18dffd406db9fcd4b3ae42254aedcaf612470e8712f12041325930f/coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b", size = 248592, upload-time = "2025-11-18T13:32:16.328Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/67f213c06e5ea3b3d4980df7dc344d7fea88240b5fe878a5dcbdfe0e2315/coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64", size = 250167, upload-time = "2025-11-18T13:32:17.687Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/e52aef68154164ea40cc8389c120c314c747fe63a04b013a5782e989b77f/coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742", size = 248238, upload-time = "2025-11-18T13:32:19.2Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a4/4d88750bcf9d6d66f77865e5a05a20e14db44074c25fd22519777cb69025/coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c", size = 247964, upload-time = "2025-11-18T13:32:21.027Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6b/b74693158899d5b47b0bf6238d2c6722e20ba749f86b74454fac0696bb00/coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984", size = 248862, upload-time = "2025-11-18T13:32:22.304Z" }, + { url = "https://files.pythonhosted.org/packages/18/de/6af6730227ce0e8ade307b1cc4a08e7f51b419a78d02083a86c04ccceb29/coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6", size = 220033, upload-time = "2025-11-18T13:32:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/e7f63021a7c4fe20994359fcdeae43cbef4a4d0ca36a5a1639feeea5d9e1/coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4", size = 220966, upload-time = "2025-11-18T13:32:25.599Z" }, + { url = "https://files.pythonhosted.org/packages/77/e8/deae26453f37c20c3aa0c4433a1e32cdc169bf415cce223a693117aa3ddd/coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc", size = 219637, upload-time = "2025-11-18T13:32:27.265Z" }, + { url = "https://files.pythonhosted.org/packages/02/bf/638c0427c0f0d47638242e2438127f3c8ee3cfc06c7fdeb16778ed47f836/coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647", size = 217704, upload-time = "2025-11-18T13:32:28.906Z" }, + { url = "https://files.pythonhosted.org/packages/08/e1/706fae6692a66c2d6b871a608bbde0da6281903fa0e9f53a39ed441da36a/coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736", size = 218064, upload-time = "2025-11-18T13:32:30.161Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8b/eb0231d0540f8af3ffda39720ff43cb91926489d01524e68f60e961366e4/coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60", size = 249560, upload-time = "2025-11-18T13:32:31.835Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a1/67fb52af642e974d159b5b379e4d4c59d0ebe1288677fbd04bbffe665a82/coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8", size = 252318, upload-time = "2025-11-18T13:32:33.178Z" }, + { url = "https://files.pythonhosted.org/packages/41/e5/38228f31b2c7665ebf9bdfdddd7a184d56450755c7e43ac721c11a4b8dab/coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f", size = 253403, upload-time = "2025-11-18T13:32:34.45Z" }, + { url = "https://files.pythonhosted.org/packages/ec/4b/df78e4c8188f9960684267c5a4897836f3f0f20a20c51606ee778a1d9749/coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70", size = 249984, upload-time = "2025-11-18T13:32:35.747Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/bb163933d195a345c6f63eab9e55743413d064c291b6220df754075c2769/coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0", size = 251339, upload-time = "2025-11-18T13:32:37.352Z" }, + { url = "https://files.pythonhosted.org/packages/15/40/c9b29cdb8412c837cdcbc2cfa054547dd83affe6cbbd4ce4fdb92b6ba7d1/coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068", size = 249489, upload-time = "2025-11-18T13:32:39.212Z" }, + { url = "https://files.pythonhosted.org/packages/c8/da/b3131e20ba07a0de4437a50ef3b47840dfabf9293675b0cd5c2c7f66dd61/coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b", size = 249070, upload-time = "2025-11-18T13:32:40.598Z" }, + { url = "https://files.pythonhosted.org/packages/70/81/b653329b5f6302c08d683ceff6785bc60a34be9ae92a5c7b63ee7ee7acec/coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937", size = 250929, upload-time = "2025-11-18T13:32:42.915Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/250ac3bca9f252a5fb1338b5ad01331ebb7b40223f72bef5b1b2cb03aa64/coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa", size = 220241, upload-time = "2025-11-18T13:32:44.665Z" }, + { url = "https://files.pythonhosted.org/packages/64/1c/77e79e76d37ce83302f6c21980b45e09f8aa4551965213a10e62d71ce0ab/coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a", size = 221051, upload-time = "2025-11-18T13:32:46.008Z" }, + { url = "https://files.pythonhosted.org/packages/31/f5/641b8a25baae564f9e52cac0e2667b123de961985709a004e287ee7663cc/coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c", size = 219692, upload-time = "2025-11-18T13:32:47.372Z" }, + { url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941", size = 217725, upload-time = "2025-11-18T13:32:49.22Z" }, + { url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a", size = 218098, upload-time = "2025-11-18T13:32:50.78Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d", size = 249093, upload-time = "2025-11-18T13:32:52.554Z" }, + { url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211", size = 251686, upload-time = "2025-11-18T13:32:54.862Z" }, + { url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d", size = 252930, upload-time = "2025-11-18T13:32:56.417Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c", size = 249296, upload-time = "2025-11-18T13:32:58.074Z" }, + { url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9", size = 251068, upload-time = "2025-11-18T13:32:59.646Z" }, + { url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0", size = 249034, upload-time = "2025-11-18T13:33:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508", size = 248853, upload-time = "2025-11-18T13:33:02.935Z" }, + { url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc", size = 250619, upload-time = "2025-11-18T13:33:04.336Z" }, + { url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8", size = 220261, upload-time = "2025-11-18T13:33:06.493Z" }, + { url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07", size = 221072, upload-time = "2025-11-18T13:33:07.926Z" }, + { url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc", size = 219702, upload-time = "2025-11-18T13:33:09.631Z" }, + { url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87", size = 218420, upload-time = "2025-11-18T13:33:11.153Z" }, + { url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6", size = 218773, upload-time = "2025-11-18T13:33:12.569Z" }, + { url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7", size = 260078, upload-time = "2025-11-18T13:33:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560", size = 262144, upload-time = "2025-11-18T13:33:15.601Z" }, + { url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12", size = 264574, upload-time = "2025-11-18T13:33:17.354Z" }, + { url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296", size = 259298, upload-time = "2025-11-18T13:33:18.958Z" }, + { url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507", size = 262150, upload-time = "2025-11-18T13:33:20.644Z" }, + { url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d", size = 259763, upload-time = "2025-11-18T13:33:22.189Z" }, + { url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2", size = 258653, upload-time = "2025-11-18T13:33:24.239Z" }, + { url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455", size = 260856, upload-time = "2025-11-18T13:33:26.365Z" }, + { url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d", size = 220936, upload-time = "2025-11-18T13:33:28.165Z" }, + { url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c", size = 222001, upload-time = "2025-11-18T13:33:29.656Z" }, + { url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d", size = 220273, upload-time = "2025-11-18T13:33:31.415Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92", size = 217777, upload-time = "2025-11-18T13:33:32.86Z" }, + { url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360", size = 218100, upload-time = "2025-11-18T13:33:34.532Z" }, + { url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac", size = 249151, upload-time = "2025-11-18T13:33:36.135Z" }, + { url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d", size = 251667, upload-time = "2025-11-18T13:33:37.996Z" }, + { url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c", size = 253003, upload-time = "2025-11-18T13:33:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434", size = 249185, upload-time = "2025-11-18T13:33:42.086Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc", size = 251025, upload-time = "2025-11-18T13:33:43.634Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc", size = 248979, upload-time = "2025-11-18T13:33:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e", size = 248800, upload-time = "2025-11-18T13:33:47.546Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17", size = 250460, upload-time = "2025-11-18T13:33:49.537Z" }, + { url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933", size = 220533, upload-time = "2025-11-18T13:33:51.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe", size = 221348, upload-time = "2025-11-18T13:33:52.776Z" }, + { url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d", size = 219922, upload-time = "2025-11-18T13:33:54.316Z" }, + { url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d", size = 218511, upload-time = "2025-11-18T13:33:56.343Z" }, + { url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03", size = 218771, upload-time = "2025-11-18T13:33:57.966Z" }, + { url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9", size = 260151, upload-time = "2025-11-18T13:33:59.597Z" }, + { url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6", size = 262257, upload-time = "2025-11-18T13:34:01.166Z" }, + { url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339", size = 264671, upload-time = "2025-11-18T13:34:02.795Z" }, + { url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e", size = 259231, upload-time = "2025-11-18T13:34:04.397Z" }, + { url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13", size = 262137, upload-time = "2025-11-18T13:34:06.068Z" }, + { url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f", size = 259745, upload-time = "2025-11-18T13:34:08.04Z" }, + { url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1", size = 258570, upload-time = "2025-11-18T13:34:09.676Z" }, + { url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b", size = 260899, upload-time = "2025-11-18T13:34:11.259Z" }, + { url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a", size = 221313, upload-time = "2025-11-18T13:34:12.863Z" }, + { url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291", size = 222423, upload-time = "2025-11-18T13:34:15.14Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384", size = 220459, upload-time = "2025-11-18T13:34:17.222Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" }, ] [package.optional-dependencies] @@ -669,6 +704,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] +[[package]] +name = "dependency-groups" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/55/f054de99871e7beb81935dea8a10b90cd5ce42122b1c3081d5282fdb3621/dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd", size = 10093, upload-time = "2025-05-02T00:34:29.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" }, +] + [[package]] name = "dill" version = "0.4.0" @@ -678,6 +726,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, ] +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + [[package]] name = "docutils" version = "0.21.2" @@ -787,7 +844,7 @@ wheels = [ [[package]] name = "furo" -version = "2025.7.19" +version = "2025.9.25" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "accessible-pygments" }, @@ -797,9 +854,9 @@ dependencies = [ { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-basic-ng" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d0/69/312cd100fa45ddaea5a588334d2defa331ff427bcb61f5fe2ae61bdc3762/furo-2025.7.19.tar.gz", hash = "sha256:4164b2cafcf4023a59bb3c594e935e2516f6b9d35e9a5ea83d8f6b43808fe91f", size = 1662054, upload-time = "2025-07-19T10:52:09.754Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/29/ff3b83a1ffce74676043ab3e7540d398e0b1ce7660917a00d7c4958b93da/furo-2025.9.25.tar.gz", hash = "sha256:3eac05582768fdbbc2bdfa1cdbcdd5d33cfc8b4bd2051729ff4e026a1d7e0a98", size = 1662007, upload-time = "2025-09-25T21:37:19.221Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/34/2b07b72bee02a63241d654f5d8af87a2de977c59638eec41ca356ab915cd/furo-2025.7.19-py3-none-any.whl", hash = "sha256:bdea869822dfd2b494ea84c0973937e35d1575af088b6721a29c7f7878adc9e3", size = 342175, upload-time = "2025-07-19T10:52:02.399Z" }, + { url = "https://files.pythonhosted.org/packages/ba/69/964b55f389c289e16ba2a5dfe587c3c462aac09e24123f09ddf703889584/furo-2025.9.25-py3-none-any.whl", hash = "sha256:2937f68e823b8e37b410c972c371bc2b1d88026709534927158e0cb3fac95afe", size = 340409, upload-time = "2025-09-25T21:37:17.244Z" }, ] [[package]] @@ -952,6 +1009,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/e2/a111dbb8625af467ea4760a1373d6ef27aac3137931219902406ccc05423/gymnasium-1.2.0-py3-none-any.whl", hash = "sha256:fc4a1e4121a9464c29b4d7dc6ade3fbeaa36dea448682f5f71a6d2c17489ea76", size = 944301, upload-time = "2025-06-27T08:21:18.83Z" }, ] +[[package]] +name = "humanize" +version = "4.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/43/50033d25ad96a7f3845f40999b4778f753c3901a11808a584fed7c00d9f5/humanize-4.14.0.tar.gz", hash = "sha256:2fa092705ea640d605c435b1ca82b2866a1b601cdf96f076d70b79a855eba90d", size = 82939, upload-time = "2025-10-15T13:04:51.214Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/5b/9512c5fb6c8218332b530f13500c6ff5f3ce3342f35e0dd7be9ac3856fd3/humanize-4.14.0-py3-none-any.whl", hash = "sha256:d57701248d040ad456092820e6fde56c930f17749956ac47f4f655c0c547bfff", size = 132092, upload-time = "2025-10-15T13:04:49.404Z" }, +] + [[package]] name = "ibm-cloud-sdk-core" version = "3.24.2" @@ -1556,26 +1622,15 @@ dependencies = [ { name = "scikit-learn" }, { name = "stable-baselines3" }, { name = "tensorboard" }, - { name = "torch", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "tqdm" }, { name = "typing-extensions" }, ] [package.dev-dependencies] dev = [ - { name = "furo" }, - { name = "myst-nb" }, + { name = "nox" }, { name = "pytest" }, { name = "pytest-cov" }, - { name = "setuptools-scm" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "sphinx-autoapi" }, - { name = "sphinx-copybutton" }, - { name = "sphinx-design" }, - { name = "sphinxcontrib-bibtex" }, - { name = "sphinxcontrib-svg2pdfconverter" }, - { name = "sphinxext-opengraph" }, ] docs = [ { name = "furo" }, @@ -1603,7 +1658,6 @@ requires-dist = [ { name = "numpy", marker = "python_full_version >= '3.11'", specifier = ">=1.24" }, { name = "numpy", marker = "python_full_version >= '3.12'", specifier = ">=1.26" }, { name = "numpy", marker = "python_full_version >= '3.13'", specifier = ">=2.1" }, - { name = "numpy", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=1.22,<2" }, { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = ">=1.3.3" }, @@ -1615,45 +1669,32 @@ requires-dist = [ { name = "scikit-learn", specifier = ">=1.5.1" }, { name = "stable-baselines3", specifier = ">=2.7.0" }, { name = "tensorboard", specifier = ">=2.17.0" }, - { name = "torch", marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'", specifier = ">=2.8.0,<2.9.0" }, { name = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, ] [package.metadata.requires-dev] dev = [ - { name = "furo", specifier = ">=2024.8.6" }, - { name = "myst-nb", specifier = ">=1.2.0" }, - { name = "pytest", specifier = ">=8.4.1" }, - { name = "pytest-cov", specifier = ">=6.2.1" }, - { name = "setuptools-scm", specifier = ">=8.3.1" }, - { name = "sphinx", specifier = ">=7.4.7" }, - { name = "sphinx", marker = "python_full_version >= '3.10'", specifier = ">=8.1.3" }, - { name = "sphinx", marker = "python_full_version >= '3.11'", specifier = ">=8.2.3" }, - { name = "sphinx-autoapi", specifier = ">=3.6.0" }, - { name = "sphinx-copybutton", specifier = ">=0.5.2" }, - { name = "sphinx-design", specifier = ">=0.6.1" }, - { name = "sphinxcontrib-bibtex", specifier = ">=2.6.5" }, - { name = "sphinxcontrib-svg2pdfconverter", specifier = ">=1.3.0" }, - { name = "sphinxext-opengraph", specifier = ">=0.10.0" }, + { name = "nox", specifier = ">=2025.11.12" }, + { name = "pytest", specifier = ">=9.0.1" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, ] docs = [ - { name = "furo", specifier = ">=2024.8.6" }, - { name = "myst-nb", specifier = ">=1.2.0" }, - { name = "setuptools-scm", specifier = ">=8.3.1" }, - { name = "sphinx", specifier = ">=7.4.7" }, - { name = "sphinx", marker = "python_full_version >= '3.10'", specifier = ">=8.1.3" }, + { name = "furo", specifier = ">=2025.9.25" }, + { name = "myst-nb", specifier = ">=1.3.0" }, + { name = "setuptools-scm", specifier = ">=9.2.2" }, + { name = "sphinx", specifier = ">=8.1.3" }, { name = "sphinx", marker = "python_full_version >= '3.11'", specifier = ">=8.2.3" }, { name = "sphinx-autoapi", specifier = ">=3.6.0" }, { name = "sphinx-copybutton", specifier = ">=0.5.2" }, { name = "sphinx-design", specifier = ">=0.6.1" }, { name = "sphinxcontrib-bibtex", specifier = ">=2.6.5" }, { name = "sphinxcontrib-svg2pdfconverter", specifier = ">=1.3.0" }, - { name = "sphinxext-opengraph", specifier = ">=0.10.0" }, + { name = "sphinxext-opengraph", specifier = ">=0.13.0" }, ] test = [ - { name = "pytest", specifier = ">=8.4.1" }, - { name = "pytest-cov", specifier = ">=6.2.1" }, + { name = "pytest", specifier = ">=9.0.1" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, ] [[package]] @@ -1745,6 +1786,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/95/1b/14b5b17c52f7329b875e4ad2dcad23c808778b42ef6d250a7223d4dc378a/networkx-2.8.5-py3-none-any.whl", hash = "sha256:a762f4b385692d9c3a6f2912d058d76d29a827deaedf9e63ed14d397b8030687", size = 2020253, upload-time = "2022-07-18T21:24:59.008Z" }, ] +[[package]] +name = "nox" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "attrs" }, + { name = "colorlog" }, + { name = "dependency-groups" }, + { name = "humanize" }, + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/a8/e169497599266d176832e2232c08557ffba97eef87bf8a18f9f918e0c6aa/nox-2025.11.12.tar.gz", hash = "sha256:3d317f9e61f49d6bde39cf2f59695bb4e1722960457eee3ae19dacfe03c07259", size = 4030561, upload-time = "2025-11-12T18:39:03.319Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/34/434c594e0125a16b05a7bedaea33e63c90abbfbe47e5729a735a8a8a90ea/nox-2025.11.12-py3-none-any.whl", hash = "sha256:707171f9f63bc685da9d00edd8c2ceec8405b8e38b5fb4e46114a860070ef0ff", size = 74447, upload-time = "2025-11-12T18:39:01.575Z" }, +] + [[package]] name = "numpy" version = "1.26.4" @@ -2465,7 +2525,7 @@ wheels = [ [[package]] name = "pytest" -version = "8.4.1" +version = "9.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -2476,23 +2536,23 @@ dependencies = [ { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, ] [[package]] name = "pytest-cov" -version = "6.2.1" +version = "7.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage", extra = ["toml"] }, { name = "pluggy" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" }, + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, ] [[package]] @@ -3305,16 +3365,16 @@ wheels = [ [[package]] name = "setuptools-scm" -version = "8.3.1" +version = "9.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, { name = "setuptools" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/19/7ae64b70b2429c48c3a7a4ed36f50f94687d3bfcd0ae2f152367b6410dff/setuptools_scm-8.3.1.tar.gz", hash = "sha256:3d555e92b75dacd037d32bafdf94f97af51ea29ae8c7b234cf94b7a5bd242a63", size = 78088, upload-time = "2025-04-23T11:53:19.739Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/b1/19587742aad604f1988a8a362e660e8c3ac03adccdb71c96d86526e5eb62/setuptools_scm-9.2.2.tar.gz", hash = "sha256:1c674ab4665686a0887d7e24c03ab25f24201c213e82ea689d2f3e169ef7ef57", size = 203385, upload-time = "2025-10-19T22:08:05.608Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/ac/8f96ba9b4cfe3e4ea201f23f4f97165862395e9331a424ed325ae37024a8/setuptools_scm-8.3.1-py3-none-any.whl", hash = "sha256:332ca0d43791b818b841213e76b1971b7711a960761c5bea5fc5cdb5196fbce3", size = 43935, upload-time = "2025-04-23T11:53:17.922Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ea/ac2bf868899d0d2e82ef72d350d97a846110c709bacf2d968431576ca915/setuptools_scm-9.2.2-py3-none-any.whl", hash = "sha256:30e8f84d2ab1ba7cb0e653429b179395d0c33775d54807fc5f1dd6671801aef7", size = 62975, upload-time = "2025-10-19T22:08:04.007Z" }, ] [[package]] @@ -3551,15 +3611,15 @@ wheels = [ [[package]] name = "sphinxext-opengraph" -version = "0.12.0" +version = "0.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/8f/6c0d869ac0fd25ae90510350800312f80bd0618d19f093e70fca3d670b32/sphinxext_opengraph-0.12.0.tar.gz", hash = "sha256:38bc17addd5d8bccc148daa7c6c13845c329c2687378ee8fdfc81942cc72a79d", size = 1026784, upload-time = "2025-08-04T21:53:36.478Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/c0/eb6838e3bae624ce6c8b90b245d17e84252863150e95efdb88f92c8aa3fb/sphinxext_opengraph-0.13.0.tar.gz", hash = "sha256:103335d08567ad8468faf1425f575e3b698e9621f9323949a6c8b96d9793e80b", size = 1026875, upload-time = "2025-08-29T12:20:31.066Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/26/8388918251df75086c7fcd9cd7e231f08774e3f4ce6fc911ff105a87a300/sphinxext_opengraph-0.12.0-py3-none-any.whl", hash = "sha256:f60892d5fa4cc25889b0baa5ec1c778a8ef87aa7c1f4bb5f93f11befdb0d7b9c", size = 1004063, upload-time = "2025-08-04T21:53:34.641Z" }, + { url = "https://files.pythonhosted.org/packages/bf/a4/66c1fd4f8fab88faf71cee04a945f9806ba0fef753f2cfc8be6353f64508/sphinxext_opengraph-0.13.0-py3-none-any.whl", hash = "sha256:936c07828edc9ad9a7b07908b29596dc84ed0b3ceaa77acdf51282d232d4d80e", size = 1004152, upload-time = "2025-08-29T12:20:29.072Z" }, ] [[package]] @@ -3999,6 +4059,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] +[[package]] +name = "virtualenv" +version = "20.35.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, +] + [[package]] name = "wcwidth" version = "0.2.13" From 8c398d8286fc4ce0876879446fe8710432d35d70 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 3 Dec 2025 19:03:22 +0100 Subject: [PATCH 68/98] Fix CI issues --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d2c2c3d19..343a0f2b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,9 @@ Issues = "https://github.com/munich-quantum-toolkit/predictor/issues" Discussions = "https://github.com/munich-quantum-toolkit/predictor/discussions" Research = "https://www.cda.cit.tum.de/research/quantum/" +[tool.check-sdist] +sdist-only = ["src/mqt/predictor/_version.py"] + [tool.hatch.build.targets.wheel] packages = ["src/mqt"] From 9211aabbc07d001189ed0a93cb975fe25f3a54e6 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 3 Dec 2025 23:14:50 +0100 Subject: [PATCH 69/98] Slight Fix --- src/mqt/predictor/rl/actions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index a762dd559..5c586220c 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -459,9 +459,9 @@ def remove_action(name: str) -> None: transpile_pass=lambda device, node_err, edge_err, readout_err: [ NoiseAwarePlacement( Architecture(list(device.build_coupling_map())), - node_err, - edge_err, - readout_err, + node_errors=node_err, + link_errors=edge_err, + readout_errors=readout_err, timeout=5000, maximum_matches=5000, ) From 632656f8c5dd86a3bac9bf75307c175f1571635b Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 3 Dec 2025 23:59:13 +0100 Subject: [PATCH 70/98] Update actions.py --- src/mqt/predictor/rl/actions.py | 76 ++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 5c586220c..4f0e8cd47 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -30,7 +30,7 @@ ) from pytket.placement import GraphPlacement, NoiseAwarePlacement from qiskit import QuantumCircuit -from qiskit.circuit import ClassicalRegister, QuantumRegister, StandardEquivalenceLibrary +from qiskit.circuit import ClassicalRegister, StandardEquivalenceLibrary from qiskit.circuit.library import ( CXGate, CYGate, @@ -95,7 +95,7 @@ from bqskit import Circuit from pytket._tket.passes import BasePass as tket_BasePass - from qiskit.circuit import Instruction, Qubit + from qiskit.circuit import ClassicalRegister, Clbit, Instruction, Qubit from qiskit.dagcircuit import DAGCircuit from qiskit.transpiler.basepasses import BasePass as qiskit_BasePass @@ -609,22 +609,40 @@ def get_actions_by_pass_type() -> dict[PassType, list[Action]]: def extract_cregs_and_measurements( qc: QuantumCircuit, -) -> tuple[list[ClassicalRegister], list[tuple[Instruction, list[Qubit], list[ClassicalRegister]]]]: - """Extracts classical registers and measurement operations from a quantum circuit. +) -> tuple[list[ClassicalRegister], list[tuple[Instruction, list[Qubit], list[Clbit]]]]: + """Extract classical registers and measurement operations from a quantum circuit. Args: qc: The input QuantumCircuit. Returns: - A tuple containing a list of classical registers and a list of measurement operations. + A tuple ``(cregs, measurements)`` where: + - ``cregs`` is a list of the circuit's ClassicalRegister objects. + - ``measurements`` is a list of tuples ``(instr, qargs, cargs)`` for each + measurement, where: + * ``instr`` is the measurement Instruction, + * ``qargs`` is the list of Qubit objects measured, + * ``cargs`` is the list of Clbit objects written to. """ - cregs = [ClassicalRegister(cr.size, name=cr.name) for cr in qc.cregs] - measurements = [(item.operation, item.qubits, item.clbits) for item in qc.data if item.operation.name == "measure"] + # IMPORTANT: reuse the original registers, do NOT clone them + cregs = list(qc.cregs) + + measurements: list[tuple[Instruction, list[Qubit], list[Clbit]]] = [] + for item in qc.data: + if item.operation.name == "measure": + instr = item.operation + qargs = list(item.qubits) + cargs = list(item.clbits) # these are Clbit, not ClassicalRegister + measurements.append((instr, qargs, cargs)) + return cregs, measurements def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: - """Removes classical registers and measurement operations from the circuit. + """Return a copy of ``qc`` without classical registers and measurements. + + Classical registers and measurement operations are removed, but quantum + registers and qubit *identity* are preserved. Args: qc: The input QuantumCircuit. @@ -632,42 +650,52 @@ def remove_cregs(qc: QuantumCircuit) -> QuantumCircuit: Returns: A new QuantumCircuit with only quantum operations (no cregs or measurements). """ - qregs = [QuantumRegister(qr.size, name=qr.name) for qr in qc.qregs] - new_qc = QuantumCircuit(*qregs) - old_to_new = {} - for orig_qr, new_qr in zip(qc.qregs, new_qc.qregs, strict=False): - for idx in range(orig_qr.size): - old_to_new[orig_qr[idx]] = new_qr[idx] + # Reuse the original QuantumRegister objects to preserve Qubit identity + new_qc = QuantumCircuit(*qc.qregs) + for item in qc.data: instr = item.operation - qargs = [old_to_new[q] for q in item.qubits] - if instr.name not in ("measure", "barrier"): - new_qc.append(instr, qargs) + if instr.name in ("measure", "barrier"): + continue + # Use the original Qubit objects directly; no remapping + qargs = list(item.qubits) + new_qc.append(instr, qargs) + return new_qc def add_cregs_and_measurements( qc: QuantumCircuit, cregs: list[ClassicalRegister], - measurements: list[tuple[Instruction, list[Qubit], list[ClassicalRegister]]], + measurements: list[tuple[Instruction, list[Qubit], list[Clbit]]], qubit_map: dict[Qubit, Qubit] | None = None, ) -> QuantumCircuit: - """Adds classical registers and measurement operations back to the quantum circuit. + """Add classical registers and measurement operations back to a circuit. Args: - qc: The quantum circuit to which cregs and measurements are added. - cregs: List of ClassicalRegister to add. - measurements: List of measurement instructions as tuples (Instruction, qubits, clbits). - qubit_map: Optional dictionary mapping original qubits to new qubits. + qc: + The quantum circuit to which cregs and measurements are added. + cregs: + List of ClassicalRegister objects to add (typically taken from + :func:`extract_cregs_and_measurements`). + measurements: + List of measurement tuples ``(instr, qargs, cargs)`` as returned by + :func:`extract_cregs_and_measurements`. + qubit_map: + Optional mapping from original Qubit objects to new Qubit objects. + If provided, measurement qubits are remapped via this dictionary. Returns: The modified QuantumCircuit with cregs and measurements added. """ + # Attach the original ClassicalRegister objects so their Clbits are valid in this circuit for cr in cregs: qc.add_register(cr) + for instr, qargs, cargs in measurements: - new_qargs = [qubit_map[q] for q in qargs] if qubit_map else qargs + new_qargs = [qubit_map[q] for q in qargs] if qubit_map is not None else qargs qc.append(instr, new_qargs, cargs) + return qc From a32571bd4f6eeb2d0dc082f3a602d1b0f64a1084 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 4 Dec 2025 11:01:47 +0100 Subject: [PATCH 71/98] Update predictorenv.py --- src/mqt/predictor/rl/predictorenv.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index ee3577e2e..e76ecd43f 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -193,7 +193,7 @@ def __init__( } self.observation_space = Dict(spaces) self.filename = "" - self.max_iter = 10 + self.max_iter = 20 self.node_err: dict[Node, float] | None = None self.edge_err: dict[tuple[Node, Node], float] | None = None self.readout_err: dict[Node, float] | None = None @@ -237,7 +237,7 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any reward_val = 0 done = False - # in case the Qiskit.QuantumCircuit has unitary or u gates or clifford in it, decompose them (because otherwise qiskit will throw an error when applying the BasisTranslator + # in case the Qiskit.QuantumCircuit has unitary or u gates or clifford in it, decompose them (because otherwise qiskit will throw an error when applying the BasisTranslator) if self.state.count_ops().get("unitary"): self.state = self.state.decompose(gates_to_decompose="unitary") elif self.state.count_ops().get("clifford"): @@ -360,7 +360,7 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: raise ValueError(msg) def fom_aware_compile( - self, action: Action, device: Target, qc: QuantumCircuit, max_iteration: int = 4 + self, action: Action, device: Target, qc: QuantumCircuit, max_iteration: int = 20 ) -> tuple[QuantumCircuit, PropertySet | None]: """Run a stochastic pass multiple times optimizing for the given figure of merit. @@ -368,7 +368,7 @@ def fom_aware_compile( action: The action containing the transpile pass. device: The compilation target device. qc: The input quantum circuit. - max_iteration: Maximum number of attempts to run the pass. + max_iteration: Number of iterations to run the pass. Returns: A tuple of the best circuit found and its property set (if available). From 323938bf5ed76a064b0ffe0502a35cb61b53c78f Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 4 Dec 2025 12:11:15 +0100 Subject: [PATCH 72/98] Fix typos --- src/mqt/predictor/rl/actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 4f0e8cd47..d896e8e97 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -517,7 +517,7 @@ def remove_action(name: str) -> None: PassType.MAPPING, stochastic=True, transpile_pass=lambda device: [ - ### Requires a initial layout, but "optimize" mode overwrites it + ### Requires an initial layout, but "optimize" mode overwrites it SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=True, max_iterations=1), FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), EnlargeWithAncilla(), From 1c70b55d254047fe12edd3a51043c462b0c24e21 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 4 Dec 2025 16:30:50 +0100 Subject: [PATCH 73/98] Fix typos --- src/mqt/predictor/rl/actions.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index d896e8e97..84c2d0aef 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -287,8 +287,6 @@ def remove_action(name: str) -> None: "Opt2qBlocks", CompilationOrigin.QISKIT, PassType.OPT, - # If no arguments is passed, decompose to U(θ, φ, λ) and CX - # https://github.com/Qiskit/qiskit/blob/stable/2.1/qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py [Collect2qBlocks(), ConsolidateBlocks(), UnitarySynthesis()], ) ) @@ -632,7 +630,7 @@ def extract_cregs_and_measurements( if item.operation.name == "measure": instr = item.operation qargs = list(item.qubits) - cargs = list(item.clbits) # these are Clbit, not ClassicalRegister + cargs = list(item.clbits) measurements.append((instr, qargs, cargs)) return cregs, measurements From 21539676a4b716bb547db063b4120a20607e46ac Mon Sep 17 00:00:00 2001 From: Patrick Hopf <81010725+flowerthrower@users.noreply.github.com> Date: Fri, 5 Dec 2025 15:11:32 +0100 Subject: [PATCH 74/98] Update src/mqt/predictor/rl/predictorenv.py Signed-off-by: Patrick Hopf <81010725+flowerthrower@users.noreply.github.com> --- src/mqt/predictor/rl/predictorenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index e76ecd43f..76db4e79a 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -248,7 +248,7 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any return create_feature_dict(self.state), reward_val, done, False, {} def calculate_reward(self, qc: QuantumCircuit | None = None) -> float: - """Calculates and returns the reward for the current state.""" + """Calculates and returns the reward for either the current state or a quantum circuit (if provided).""" circuit = self.state if qc is None else qc if self.reward_function == "expected_fidelity": return expected_fidelity(circuit, self.device) From ea1e1179f63fddd8226fbd600ff8ae5bedb2d633 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 5 Dec 2025 15:50:12 +0100 Subject: [PATCH 75/98] Fixes --- CHANGELOG.md | 5 +-- src/mqt/predictor/ml/helper.py | 51 +--------------------------- src/mqt/predictor/rl/actions.py | 2 +- src/mqt/predictor/rl/helper.py | 4 +-- src/mqt/predictor/rl/predictorenv.py | 18 +++++----- src/mqt/predictor/utils.py | 50 ++++++++++++++++++++++++++- 6 files changed, 66 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baf8733e8..2f5754dab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,9 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Changed -- ✨ Improved the MDP for RL ([#449]) ([**@Shaobo-Zhou**]) -- 🔧 Changed test circuit level for RL predictor from ALG to INDEP ([#449]) ([**@Shaobo-Zhou**]) +- ✨ Improved the MDP and extended the RL predictor's action/state space (expanded observation vector, support for stochastic passes, wrapped stochastic actions). ([#449]) ([**@Shaobo-Zhou**]) +- ✨ Added AIRouting and new optimization actions (KAKDecomposition, ElidePermutations) to the RL action set. ([#449]) ([**@Shaobo-Zhou**]) +- 🔧 Changed test circuit level for RL predictor from ALG to INDEP. ([#449]) ([**@Shaobo-Zhou**]) - ✨ Remove support for custom names of trained models ([#489]) ([**@bachase**]) - 🔥 Drop support for x86 macOS systems ([#421]) ([**@denialhaag**]) diff --git a/src/mqt/predictor/ml/helper.py b/src/mqt/predictor/ml/helper.py index 4550cf015..04716132e 100644 --- a/src/mqt/predictor/ml/helper.py +++ b/src/mqt/predictor/ml/helper.py @@ -15,7 +15,7 @@ from pathlib import Path from typing import TYPE_CHECKING -from mqt.predictor.utils import calc_supermarq_features +from mqt.predictor.utils import calc_supermarq_features, get_openqasm_gates if TYPE_CHECKING: import numpy as np @@ -50,55 +50,6 @@ def get_path_training_circuits_compiled() -> Path: return get_path_training_data() / "training_circuits_compiled" -def get_openqasm_gates() -> list[str]: - """Returns a list of all quantum gates within the openQASM 2.0 standard header.""" - # according to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc - return [ - "u3", - "u2", - "u1", - "cx", - "id", - "u0", - "u", - "p", - "x", - "y", - "z", - "h", - "s", - "sdg", - "t", - "tdg", - "rx", - "ry", - "rz", - "sx", - "sxdg", - "cz", - "cy", - "swap", - "ch", - "ccx", - "cswap", - "crx", - "cry", - "crz", - "cu1", - "cp", - "cu3", - "csx", - "cu", - "rxx", - "rzz", - "rccx", - "rc3x", - "c3x", - "c3sqrtx", - "c4x", - ] - - def dict_to_featurevector(gate_dict: dict[str, int]) -> dict[str, int]: """Calculates and returns the feature vector of a given quantum circuit gate dictionary.""" res_dct = dict.fromkeys(get_openqasm_gates(), 0) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 84c2d0aef..e6f67a0fd 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -580,7 +580,7 @@ def remove_action(name: str) -> None: model=MachineModel(bqskit_circuit.num_qudits, gate_set=get_bqskit_native_gates(device)), optimization_level=1 if os.getenv("GITHUB_ACTIONS") == "true" else 2, synthesis_epsilon=1e-1 if os.getenv("GITHUB_ACTIONS") == "true" else 1e-8, - max_synthesis_size=3, + max_synthesis_size=2 if os.getenv("GITHUB_ACTIONS") == "true" else 3, seed=10, num_workers=1 if os.getenv("GITHUB_ACTIONS") == "true" else -1, ), diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index 7f5da72de..68f42ca83 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -17,7 +17,7 @@ import numpy as np from qiskit import QuantumCircuit -from mqt.predictor.utils import calc_supermarq_features, get_rl_openqasm_gates +from mqt.predictor.utils import calc_supermarq_features, get_openqasm_gates_without_u if TYPE_CHECKING: from numpy.random import Generator @@ -71,7 +71,7 @@ def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generat def dict_to_featurevector(gate_dict: dict[str, int]) -> dict[str, float]: """Calculates and returns a normalized feature vector of a given quantum circuit gate dictionary.""" - res_dct = dict.fromkeys(get_rl_openqasm_gates(), 0.0) + res_dct = dict.fromkeys(get_openqasm_gates_without_u(), 0.0) exclude_from_total = {"barrier"} total = sum(val for key, val in gate_dict.items() if key not in exclude_from_total) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 76db4e79a..f3350b09f 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -82,7 +82,7 @@ postprocess_vf2postlayout, prepare_noise_data, ) -from mqt.predictor.utils import get_rl_openqasm_gates +from mqt.predictor.utils import get_openqasm_gates_without_u logger = logging.getLogger("mqt-predictor") @@ -117,7 +117,7 @@ def __init__( self.actions_mapping_indices = [] self.actions_opt_indices = [] self.actions_final_optimization_indices = [] - self.actions_mapping_preserving_indices = [] + self.actions_structure_preserving_indices = [] # Actions that preserves the mapping and native gates self.used_actions: list[str] = [] self.device = device @@ -138,7 +138,7 @@ def __init__( self.action_set[index] = elem self.actions_opt_indices.append(index) if getattr(elem, "preserve_layout", False): - self.actions_mapping_preserving_indices.append(index) + self.actions_structure_preserving_indices.append(index) index += 1 for elem in action_dict[PassType.LAYOUT]: self.action_set[index] = elem @@ -178,7 +178,7 @@ def __init__( self.has_parameterized_gates = False self.rng = np.random.default_rng(10) - gate_spaces = {g: Box(low=0, high=1, shape=(1,), dtype=np.float32) for g in get_rl_openqasm_gates()} + gate_spaces = {g: Box(low=0, high=1, shape=(1,), dtype=np.float32) for g in get_openqasm_gates_without_u()} spaces = { "num_qubits": Discrete(self.device.num_qubits + 1), @@ -605,19 +605,21 @@ def determine_valid_actions_for_state(self) -> list[int]: if not mapped: # Non-native + unmapped → synthesis or optimization return self.actions_synthesis_indices + self.actions_opt_indices - # Non-native + mapped → synthesis or mapping-preserving - return self.actions_synthesis_indices + self.actions_mapping_preserving_indices + # Non-native + mapped → synthesis or structure-preserving (native gates & mapping) + return self.actions_synthesis_indices + self.actions_structure_preserving_indices if mapped: if self.layout is not None: # Native + fully mapped & layout assigned → terminate or fine-tune return [ self.action_terminate_index, - *self.actions_mapping_preserving_indices, + *self.actions_structure_preserving_indices, *self.actions_final_optimization_indices, ] # Mapped but no explicit layout yet → explore layout/mapping improvements - return self.actions_mapping_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices + return ( + self.actions_structure_preserving_indices + self.actions_layout_indices + self.actions_mapping_indices + ) if self.layout is not None: # Layout chosen but not mapped → must do routing return self.actions_routing_indices diff --git a/src/mqt/predictor/utils.py b/src/mqt/predictor/utils.py index 027be0423..8b0a51835 100644 --- a/src/mqt/predictor/utils.py +++ b/src/mqt/predictor/utils.py @@ -145,9 +145,57 @@ def calc_supermarq_features( ) -def get_rl_openqasm_gates() -> list[str]: +def get_openqasm_gates() -> list[str]: """Returns a list of all quantum gates within the openQASM 2.0 standard header.""" # according to https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/qasm/libs/qelib1.inc + return [ + "u3", + "u2", + "u1", + "cx", + "id", + "u0", + "u", + "p", + "x", + "y", + "z", + "h", + "s", + "sdg", + "t", + "tdg", + "rx", + "ry", + "rz", + "sx", + "sxdg", + "cz", + "cy", + "swap", + "ch", + "ccx", + "cswap", + "crx", + "cry", + "crz", + "cu1", + "cp", + "cu3", + "csx", + "cu", + "rxx", + "rzz", + "rccx", + "rc3x", + "c3x", + "c3sqrtx", + "c4x", + ] + + +def get_openqasm_gates_without_u() -> list[str]: + """Returns a list of all quantum gates within the openQASM 2.0 standard header that are used as RL features.""" # u,u0,u1,u2,u3 gates are excluded as they are not meaningful as RL features # Drop multi-qubit gates with more than two qubits, since Qiskit's `basis_gates` argument does not support them. return [ From 8532b747b4953709a3d388021a966eaaeb02a4c6 Mon Sep 17 00:00:00 2001 From: Shaobo-Zhou <109073755+Shaobo-Zhou@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:46:19 +0100 Subject: [PATCH 76/98] Update CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Shaobo-Zhou <109073755+Shaobo-Zhou@users.noreply.github.com> --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e6287bfc..5ab090b73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,9 @@ This project adheres to [Semantic Versioning], with the exception that minor rel ### Changed -- ✨ Improved the MDP and extended the RL predictor's action/state space (expanded observation vector, support for stochastic passes, wrapped stochastic actions). ([#449]) ([**@Shaobo-Zhou**]) -- ✨ Added AIRouting and new optimization actions (KAKDecomposition, ElidePermutations) to the RL action set. ([#449]) ([**@Shaobo-Zhou**]) -- 🔧 Changed test circuit level for RL predictor from ALG to INDEP. ([#449]) ([**@Shaobo-Zhou**]) +- ✨ Improved the MDP and extended the RL predictor's action/state space (expanded observation vector, support for stochastic passes, wrapped stochastic actions) ([#449]) ([**@Shaobo-Zhou**]) +- ✨ Added AIRouting and new optimization actions (KAKDecomposition, ElidePermutations) to the RL action set ([#449]) ([**@Shaobo-Zhou**]) +- 🔧 Changed test circuit level for RL predictor from ALG to INDEP ([#449]) ([**@Shaobo-Zhou**]) - 🐛 Fix instruction duration unit in estimated success probability calculation ([#445]) ([**@Shaobo-Zhou**]) - ✨ Remove support for custom names of trained models ([#489]) ([**@bachase**]) - 🔥 Drop support for x86 macOS systems ([#421]) ([**@denialhaag**]) From d25b000f228838b04cd95e5c8642cd0982de4124 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 17 Dec 2025 15:25:04 +0100 Subject: [PATCH 77/98] Fix type mismatch --- src/mqt/predictor/rl/predictorenv.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index f3350b09f..c24aa8703 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -424,7 +424,7 @@ def fom_aware_compile( return qc, None def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCircuit: - pm_property_set: PropertySet | None = {} + pm_property_set: dict[str, Any] | None = None if getattr(action, "stochastic", False): # Wrap stochastic action to optimize for the used figure of merit altered_qc, pm_property_set = self.fom_aware_compile( action, @@ -443,14 +443,14 @@ def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCirc else: pm = PassManager(passes) altered_qc = pm.run(self.state) - pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else None else: transpile_pass = ( action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass ) pm = PassManager(transpile_pass) altered_qc = pm.run(self.state) - pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else {} + pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else None if action_index in ( self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices From 8d274f8e60288cd9a6adf236ea61087ef3f9b7b4 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 17 Dec 2025 15:26:32 +0100 Subject: [PATCH 78/98] Update qiskit-ibm-transpiler to 0.15.0 --- pyproject.toml | 4 +- uv.lock | 1507 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 1364 insertions(+), 147 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 343a0f2b7..3e90fd971 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,8 +48,8 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler==0.13.1; python_version < '3.13'", # Do not support python 3.13 yet - "qiskit-ibm-ai-local-transpiler==0.4.2; python_version < '3.13'", + "qiskit-ibm-transpiler==0.15.0", + "qiskit-ibm-ai-local-transpiler==0.5.5; python_version < '3.13'", ] classifiers = [ diff --git a/uv.lock b/uv.lock index 9e805fe20..0c05b99d3 100644 --- a/uv.lock +++ b/uv.lock @@ -35,6 +35,160 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, ] +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994, upload-time = "2025-10-28T20:59:39.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/34/939730e66b716b76046dedfe0842995842fa906ccc4964bba414ff69e429/aiohttp-3.13.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2372b15a5f62ed37789a6b383ff7344fc5b9f243999b0cd9b629d8bc5f5b4155", size = 736471, upload-time = "2025-10-28T20:55:27.924Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cf/dcbdf2df7f6ca72b0bb4c0b4509701f2d8942cf54e29ca197389c214c07f/aiohttp-3.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7f8659a48995edee7229522984bd1009c1213929c769c2daa80b40fe49a180c", size = 493985, upload-time = "2025-10-28T20:55:29.456Z" }, + { url = "https://files.pythonhosted.org/packages/9d/87/71c8867e0a1d0882dcbc94af767784c3cb381c1c4db0943ab4aae4fed65e/aiohttp-3.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:939ced4a7add92296b0ad38892ce62b98c619288a081170695c6babe4f50e636", size = 489274, upload-time = "2025-10-28T20:55:31.134Z" }, + { url = "https://files.pythonhosted.org/packages/38/0f/46c24e8dae237295eaadd113edd56dee96ef6462adf19b88592d44891dc5/aiohttp-3.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6315fb6977f1d0dd41a107c527fee2ed5ab0550b7d885bc15fee20ccb17891da", size = 1668171, upload-time = "2025-10-28T20:55:36.065Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c6/4cdfb4440d0e28483681a48f69841fa5e39366347d66ef808cbdadddb20e/aiohttp-3.13.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e7352512f763f760baaed2637055c49134fd1d35b37c2dedfac35bfe5cf8725", size = 1636036, upload-time = "2025-10-28T20:55:37.576Z" }, + { url = "https://files.pythonhosted.org/packages/84/37/8708cf678628216fb678ab327a4e1711c576d6673998f4f43e86e9ae90dd/aiohttp-3.13.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e09a0a06348a2dd73e7213353c90d709502d9786219f69b731f6caa0efeb46f5", size = 1727975, upload-time = "2025-10-28T20:55:39.457Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2e/3ebfe12fdcb9b5f66e8a0a42dffcd7636844c8a018f261efb2419f68220b/aiohttp-3.13.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a09a6d073fb5789456545bdee2474d14395792faa0527887f2f4ec1a486a59d3", size = 1815823, upload-time = "2025-10-28T20:55:40.958Z" }, + { url = "https://files.pythonhosted.org/packages/a1/4f/ca2ef819488cbb41844c6cf92ca6dd15b9441e6207c58e5ae0e0fc8d70ad/aiohttp-3.13.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b59d13c443f8e049d9e94099c7e412e34610f1f49be0f230ec656a10692a5802", size = 1669374, upload-time = "2025-10-28T20:55:42.745Z" }, + { url = "https://files.pythonhosted.org/packages/f8/fe/1fe2e1179a0d91ce09c99069684aab619bf2ccde9b20bd6ca44f8837203e/aiohttp-3.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:20db2d67985d71ca033443a1ba2001c4b5693fe09b0e29f6d9358a99d4d62a8a", size = 1555315, upload-time = "2025-10-28T20:55:44.264Z" }, + { url = "https://files.pythonhosted.org/packages/5a/2b/f3781899b81c45d7cbc7140cddb8a3481c195e7cbff8e36374759d2ab5a5/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:960c2fc686ba27b535f9fd2b52d87ecd7e4fd1cf877f6a5cba8afb5b4a8bd204", size = 1639140, upload-time = "2025-10-28T20:55:46.626Z" }, + { url = "https://files.pythonhosted.org/packages/72/27/c37e85cd3ece6f6c772e549bd5a253d0c122557b25855fb274224811e4f2/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6c00dbcf5f0d88796151e264a8eab23de2997c9303dd7c0bf622e23b24d3ce22", size = 1645496, upload-time = "2025-10-28T20:55:48.933Z" }, + { url = "https://files.pythonhosted.org/packages/66/20/3af1ab663151bd3780b123e907761cdb86ec2c4e44b2d9b195ebc91fbe37/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fed38a5edb7945f4d1bcabe2fcd05db4f6ec7e0e82560088b754f7e08d93772d", size = 1697625, upload-time = "2025-10-28T20:55:50.377Z" }, + { url = "https://files.pythonhosted.org/packages/95/eb/ae5cab15efa365e13d56b31b0d085a62600298bf398a7986f8388f73b598/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:b395bbca716c38bef3c764f187860e88c724b342c26275bc03e906142fc5964f", size = 1542025, upload-time = "2025-10-28T20:55:51.861Z" }, + { url = "https://files.pythonhosted.org/packages/e9/2d/1683e8d67ec72d911397fe4e575688d2a9b8f6a6e03c8fdc9f3fd3d4c03f/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:204ffff2426c25dfda401ba08da85f9c59525cdc42bda26660463dd1cbcfec6f", size = 1714918, upload-time = "2025-10-28T20:55:53.515Z" }, + { url = "https://files.pythonhosted.org/packages/99/a2/ffe8e0e1c57c5e542d47ffa1fcf95ef2b3ea573bf7c4d2ee877252431efc/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05c4dd3c48fb5f15db31f57eb35374cb0c09afdde532e7fb70a75aede0ed30f6", size = 1656113, upload-time = "2025-10-28T20:55:55.438Z" }, + { url = "https://files.pythonhosted.org/packages/0d/42/d511aff5c3a2b06c09d7d214f508a4ad8ac7799817f7c3d23e7336b5e896/aiohttp-3.13.2-cp310-cp310-win32.whl", hash = "sha256:e574a7d61cf10351d734bcddabbe15ede0eaa8a02070d85446875dc11189a251", size = 432290, upload-time = "2025-10-28T20:55:56.96Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ea/1c2eb7098b5bad4532994f2b7a8228d27674035c9b3234fe02c37469ef14/aiohttp-3.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:364f55663085d658b8462a1c3f17b2b84a5c2e1ba858e1b79bff7b2e24ad1514", size = 455075, upload-time = "2025-10-28T20:55:58.373Z" }, + { url = "https://files.pythonhosted.org/packages/35/74/b321e7d7ca762638cdf8cdeceb39755d9c745aff7a64c8789be96ddf6e96/aiohttp-3.13.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4647d02df098f6434bafd7f32ad14942f05a9caa06c7016fdcc816f343997dd0", size = 743409, upload-time = "2025-10-28T20:56:00.354Z" }, + { url = "https://files.pythonhosted.org/packages/99/3d/91524b905ec473beaf35158d17f82ef5a38033e5809fe8742e3657cdbb97/aiohttp-3.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e3403f24bcb9c3b29113611c3c16a2a447c3953ecf86b79775e7be06f7ae7ccb", size = 497006, upload-time = "2025-10-28T20:56:01.85Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d3/7f68bc02a67716fe80f063e19adbd80a642e30682ce74071269e17d2dba1/aiohttp-3.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:43dff14e35aba17e3d6d5ba628858fb8cb51e30f44724a2d2f0c75be492c55e9", size = 493195, upload-time = "2025-10-28T20:56:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/98/31/913f774a4708775433b7375c4f867d58ba58ead833af96c8af3621a0d243/aiohttp-3.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2a9ea08e8c58bb17655630198833109227dea914cd20be660f52215f6de5613", size = 1747759, upload-time = "2025-10-28T20:56:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/e8/63/04efe156f4326f31c7c4a97144f82132c3bb21859b7bb84748d452ccc17c/aiohttp-3.13.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53b07472f235eb80e826ad038c9d106c2f653584753f3ddab907c83f49eedead", size = 1704456, upload-time = "2025-10-28T20:56:06.986Z" }, + { url = "https://files.pythonhosted.org/packages/8e/02/4e16154d8e0a9cf4ae76f692941fd52543bbb148f02f098ca73cab9b1c1b/aiohttp-3.13.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e736c93e9c274fce6419af4aac199984d866e55f8a4cec9114671d0ea9688780", size = 1807572, upload-time = "2025-10-28T20:56:08.558Z" }, + { url = "https://files.pythonhosted.org/packages/34/58/b0583defb38689e7f06798f0285b1ffb3a6fb371f38363ce5fd772112724/aiohttp-3.13.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ff5e771f5dcbc81c64898c597a434f7682f2259e0cd666932a913d53d1341d1a", size = 1895954, upload-time = "2025-10-28T20:56:10.545Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f3/083907ee3437425b4e376aa58b2c915eb1a33703ec0dc30040f7ae3368c6/aiohttp-3.13.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3b6fb0c207cc661fa0bf8c66d8d9b657331ccc814f4719468af61034b478592", size = 1747092, upload-time = "2025-10-28T20:56:12.118Z" }, + { url = "https://files.pythonhosted.org/packages/ac/61/98a47319b4e425cc134e05e5f3fc512bf9a04bf65aafd9fdcda5d57ec693/aiohttp-3.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:97a0895a8e840ab3520e2288db7cace3a1981300d48babeb50e7425609e2e0ab", size = 1606815, upload-time = "2025-10-28T20:56:14.191Z" }, + { url = "https://files.pythonhosted.org/packages/97/4b/e78b854d82f66bb974189135d31fce265dee0f5344f64dd0d345158a5973/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9e8f8afb552297aca127c90cb840e9a1d4bfd6a10d7d8f2d9176e1acc69bad30", size = 1723789, upload-time = "2025-10-28T20:56:16.101Z" }, + { url = "https://files.pythonhosted.org/packages/ed/fc/9d2ccc794fc9b9acd1379d625c3a8c64a45508b5091c546dea273a41929e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed2f9c7216e53c3df02264f25d824b079cc5914f9e2deba94155190ef648ee40", size = 1718104, upload-time = "2025-10-28T20:56:17.655Z" }, + { url = "https://files.pythonhosted.org/packages/66/65/34564b8765ea5c7d79d23c9113135d1dd3609173da13084830f1507d56cf/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:99c5280a329d5fa18ef30fd10c793a190d996567667908bef8a7f81f8202b948", size = 1785584, upload-time = "2025-10-28T20:56:19.238Z" }, + { url = "https://files.pythonhosted.org/packages/30/be/f6a7a426e02fc82781afd62016417b3948e2207426d90a0e478790d1c8a4/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ca6ffef405fc9c09a746cb5d019c1672cd7f402542e379afc66b370833170cf", size = 1595126, upload-time = "2025-10-28T20:56:20.836Z" }, + { url = "https://files.pythonhosted.org/packages/e5/c7/8e22d5d28f94f67d2af496f14a83b3c155d915d1fe53d94b66d425ec5b42/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:47f438b1a28e926c37632bff3c44df7d27c9b57aaf4e34b1def3c07111fdb782", size = 1800665, upload-time = "2025-10-28T20:56:22.922Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/91133c8b68b1da9fc16555706aa7276fdf781ae2bb0876c838dd86b8116e/aiohttp-3.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9acda8604a57bb60544e4646a4615c1866ee6c04a8edef9b8ee6fd1d8fa2ddc8", size = 1739532, upload-time = "2025-10-28T20:56:25.924Z" }, + { url = "https://files.pythonhosted.org/packages/17/6b/3747644d26a998774b21a616016620293ddefa4d63af6286f389aedac844/aiohttp-3.13.2-cp311-cp311-win32.whl", hash = "sha256:868e195e39b24aaa930b063c08bb0c17924899c16c672a28a65afded9c46c6ec", size = 431876, upload-time = "2025-10-28T20:56:27.524Z" }, + { url = "https://files.pythonhosted.org/packages/c3/63/688462108c1a00eb9f05765331c107f95ae86f6b197b865d29e930b7e462/aiohttp-3.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:7fd19df530c292542636c2a9a85854fab93474396a52f1695e799186bbd7f24c", size = 456205, upload-time = "2025-10-28T20:56:29.062Z" }, + { url = "https://files.pythonhosted.org/packages/29/9b/01f00e9856d0a73260e86dd8ed0c2234a466c5c1712ce1c281548df39777/aiohttp-3.13.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b1e56bab2e12b2b9ed300218c351ee2a3d8c8fdab5b1ec6193e11a817767e47b", size = 737623, upload-time = "2025-10-28T20:56:30.797Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1b/4be39c445e2b2bd0aab4ba736deb649fabf14f6757f405f0c9685019b9e9/aiohttp-3.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:364e25edaabd3d37b1db1f0cbcee8c73c9a3727bfa262b83e5e4cf3489a2a9dc", size = 492664, upload-time = "2025-10-28T20:56:32.708Z" }, + { url = "https://files.pythonhosted.org/packages/28/66/d35dcfea8050e131cdd731dff36434390479b4045a8d0b9d7111b0a968f1/aiohttp-3.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c94825f744694c4b8db20b71dba9a257cd2ba8e010a803042123f3a25d50d7", size = 491808, upload-time = "2025-10-28T20:56:34.57Z" }, + { url = "https://files.pythonhosted.org/packages/00/29/8e4609b93e10a853b65f8291e64985de66d4f5848c5637cddc70e98f01f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba2715d842ffa787be87cbfce150d5e88c87a98e0b62e0f5aa489169a393dbbb", size = 1738863, upload-time = "2025-10-28T20:56:36.377Z" }, + { url = "https://files.pythonhosted.org/packages/9d/fa/4ebdf4adcc0def75ced1a0d2d227577cd7b1b85beb7edad85fcc87693c75/aiohttp-3.13.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:585542825c4bc662221fb257889e011a5aa00f1ae4d75d1d246a5225289183e3", size = 1700586, upload-time = "2025-10-28T20:56:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/da/04/73f5f02ff348a3558763ff6abe99c223381b0bace05cd4530a0258e52597/aiohttp-3.13.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39d02cb6025fe1aabca329c5632f48c9532a3dabccd859e7e2f110668972331f", size = 1768625, upload-time = "2025-10-28T20:56:39.75Z" }, + { url = "https://files.pythonhosted.org/packages/f8/49/a825b79ffec124317265ca7d2344a86bcffeb960743487cb11988ffb3494/aiohttp-3.13.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e67446b19e014d37342f7195f592a2a948141d15a312fe0e700c2fd2f03124f6", size = 1867281, upload-time = "2025-10-28T20:56:41.471Z" }, + { url = "https://files.pythonhosted.org/packages/b9/48/adf56e05f81eac31edcfae45c90928f4ad50ef2e3ea72cb8376162a368f8/aiohttp-3.13.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4356474ad6333e41ccefd39eae869ba15a6c5299c9c01dfdcfdd5c107be4363e", size = 1752431, upload-time = "2025-10-28T20:56:43.162Z" }, + { url = "https://files.pythonhosted.org/packages/30/ab/593855356eead019a74e862f21523db09c27f12fd24af72dbc3555b9bfd9/aiohttp-3.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeacf451c99b4525f700f078becff32c32ec327b10dcf31306a8a52d78166de7", size = 1562846, upload-time = "2025-10-28T20:56:44.85Z" }, + { url = "https://files.pythonhosted.org/packages/39/0f/9f3d32271aa8dc35036e9668e31870a9d3b9542dd6b3e2c8a30931cb27ae/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8a9b889aeabd7a4e9af0b7f4ab5ad94d42e7ff679aaec6d0db21e3b639ad58d", size = 1699606, upload-time = "2025-10-28T20:56:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3c/52d2658c5699b6ef7692a3f7128b2d2d4d9775f2a68093f74bca06cf01e1/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fa89cb11bc71a63b69568d5b8a25c3ca25b6d54c15f907ca1c130d72f320b76b", size = 1720663, upload-time = "2025-10-28T20:56:48.528Z" }, + { url = "https://files.pythonhosted.org/packages/9b/d4/8f8f3ff1fb7fb9e3f04fcad4e89d8a1cd8fc7d05de67e3de5b15b33008ff/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8aa7c807df234f693fed0ecd507192fc97692e61fee5702cdc11155d2e5cadc8", size = 1737939, upload-time = "2025-10-28T20:56:50.77Z" }, + { url = "https://files.pythonhosted.org/packages/03/d3/ddd348f8a27a634daae39a1b8e291ff19c77867af438af844bf8b7e3231b/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9eb3e33fdbe43f88c3c75fa608c25e7c47bbd80f48d012763cb67c47f39a7e16", size = 1555132, upload-time = "2025-10-28T20:56:52.568Z" }, + { url = "https://files.pythonhosted.org/packages/39/b8/46790692dc46218406f94374903ba47552f2f9f90dad554eed61bfb7b64c/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9434bc0d80076138ea986833156c5a48c9c7a8abb0c96039ddbb4afc93184169", size = 1764802, upload-time = "2025-10-28T20:56:54.292Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e4/19ce547b58ab2a385e5f0b8aa3db38674785085abcf79b6e0edd1632b12f/aiohttp-3.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ff15c147b2ad66da1f2cbb0622313f2242d8e6e8f9b79b5206c84523a4473248", size = 1719512, upload-time = "2025-10-28T20:56:56.428Z" }, + { url = "https://files.pythonhosted.org/packages/70/30/6355a737fed29dcb6dfdd48682d5790cb5eab050f7b4e01f49b121d3acad/aiohttp-3.13.2-cp312-cp312-win32.whl", hash = "sha256:27e569eb9d9e95dbd55c0fc3ec3a9335defbf1d8bc1d20171a49f3c4c607b93e", size = 426690, upload-time = "2025-10-28T20:56:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0d/b10ac09069973d112de6ef980c1f6bb31cb7dcd0bc363acbdad58f927873/aiohttp-3.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:8709a0f05d59a71f33fd05c17fc11fcb8c30140506e13c2f5e8ee1b8964e1b45", size = 453465, upload-time = "2025-10-28T20:57:00.795Z" }, + { url = "https://files.pythonhosted.org/packages/bf/78/7e90ca79e5aa39f9694dcfd74f4720782d3c6828113bb1f3197f7e7c4a56/aiohttp-3.13.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7519bdc7dfc1940d201651b52bf5e03f5503bda45ad6eacf64dda98be5b2b6be", size = 732139, upload-time = "2025-10-28T20:57:02.455Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/1f59215ab6853fbaa5c8495fa6cbc39edfc93553426152b75d82a5f32b76/aiohttp-3.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:088912a78b4d4f547a1f19c099d5a506df17eacec3c6f4375e2831ec1d995742", size = 490082, upload-time = "2025-10-28T20:57:04.784Z" }, + { url = "https://files.pythonhosted.org/packages/68/7b/fe0fe0f5e05e13629d893c760465173a15ad0039c0a5b0d0040995c8075e/aiohttp-3.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5276807b9de9092af38ed23ce120539ab0ac955547b38563a9ba4f5b07b95293", size = 489035, upload-time = "2025-10-28T20:57:06.894Z" }, + { url = "https://files.pythonhosted.org/packages/d2/04/db5279e38471b7ac801d7d36a57d1230feeee130bbe2a74f72731b23c2b1/aiohttp-3.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1237c1375eaef0db4dcd7c2559f42e8af7b87ea7d295b118c60c36a6e61cb811", size = 1720387, upload-time = "2025-10-28T20:57:08.685Z" }, + { url = "https://files.pythonhosted.org/packages/31/07/8ea4326bd7dae2bd59828f69d7fdc6e04523caa55e4a70f4a8725a7e4ed2/aiohttp-3.13.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:96581619c57419c3d7d78703d5b78c1e5e5fc0172d60f555bdebaced82ded19a", size = 1688314, upload-time = "2025-10-28T20:57:10.693Z" }, + { url = "https://files.pythonhosted.org/packages/48/ab/3d98007b5b87ffd519d065225438cc3b668b2f245572a8cb53da5dd2b1bc/aiohttp-3.13.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2713a95b47374169409d18103366de1050fe0ea73db358fc7a7acb2880422d4", size = 1756317, upload-time = "2025-10-28T20:57:12.563Z" }, + { url = "https://files.pythonhosted.org/packages/97/3d/801ca172b3d857fafb7b50c7c03f91b72b867a13abca982ed6b3081774ef/aiohttp-3.13.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:228a1cd556b3caca590e9511a89444925da87d35219a49ab5da0c36d2d943a6a", size = 1858539, upload-time = "2025-10-28T20:57:14.623Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0d/4764669bdf47bd472899b3d3db91fffbe925c8e3038ec591a2fd2ad6a14d/aiohttp-3.13.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac6cde5fba8d7d8c6ac963dbb0256a9854e9fafff52fbcc58fdf819357892c3e", size = 1739597, upload-time = "2025-10-28T20:57:16.399Z" }, + { url = "https://files.pythonhosted.org/packages/c4/52/7bd3c6693da58ba16e657eb904a5b6decfc48ecd06e9ac098591653b1566/aiohttp-3.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2bef8237544f4e42878c61cef4e2839fee6346dc60f5739f876a9c50be7fcdb", size = 1555006, upload-time = "2025-10-28T20:57:18.288Z" }, + { url = "https://files.pythonhosted.org/packages/48/30/9586667acec5993b6f41d2ebcf96e97a1255a85f62f3c653110a5de4d346/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:16f15a4eac3bc2d76c45f7ebdd48a65d41b242eb6c31c2245463b40b34584ded", size = 1683220, upload-time = "2025-10-28T20:57:20.241Z" }, + { url = "https://files.pythonhosted.org/packages/71/01/3afe4c96854cfd7b30d78333852e8e851dceaec1c40fd00fec90c6402dd2/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:bb7fb776645af5cc58ab804c58d7eba545a97e047254a52ce89c157b5af6cd0b", size = 1712570, upload-time = "2025-10-28T20:57:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/11/2c/22799d8e720f4697a9e66fd9c02479e40a49de3de2f0bbe7f9f78a987808/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1b4951125ec10c70802f2cb09736c895861cd39fd9dcb35107b4dc8ae6220b8", size = 1733407, upload-time = "2025-10-28T20:57:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/34/cb/90f15dd029f07cebbd91f8238a8b363978b530cd128488085b5703683594/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:550bf765101ae721ee1d37d8095f47b1f220650f85fe1af37a90ce75bab89d04", size = 1550093, upload-time = "2025-10-28T20:57:26.257Z" }, + { url = "https://files.pythonhosted.org/packages/69/46/12dce9be9d3303ecbf4d30ad45a7683dc63d90733c2d9fe512be6716cd40/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fe91b87fc295973096251e2d25a811388e7d8adf3bd2b97ef6ae78bc4ac6c476", size = 1758084, upload-time = "2025-10-28T20:57:28.349Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c8/0932b558da0c302ffd639fc6362a313b98fdf235dc417bc2493da8394df7/aiohttp-3.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0c8e31cfcc4592cb200160344b2fb6ae0f9e4effe06c644b5a125d4ae5ebe23", size = 1716987, upload-time = "2025-10-28T20:57:30.233Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8b/f5bd1a75003daed099baec373aed678f2e9b34f2ad40d85baa1368556396/aiohttp-3.13.2-cp313-cp313-win32.whl", hash = "sha256:0740f31a60848d6edb296a0df827473eede90c689b8f9f2a4cdde74889eb2254", size = 425859, upload-time = "2025-10-28T20:57:32.105Z" }, + { url = "https://files.pythonhosted.org/packages/5d/28/a8a9fc6957b2cee8902414e41816b5ab5536ecf43c3b1843c10e82c559b2/aiohttp-3.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:a88d13e7ca367394908f8a276b89d04a3652044612b9a408a0bb22a5ed976a1a", size = 452192, upload-time = "2025-10-28T20:57:34.166Z" }, + { url = "https://files.pythonhosted.org/packages/9b/36/e2abae1bd815f01c957cbf7be817b3043304e1c87bad526292a0410fdcf9/aiohttp-3.13.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:2475391c29230e063ef53a66669b7b691c9bfc3f1426a0f7bcdf1216bdbac38b", size = 735234, upload-time = "2025-10-28T20:57:36.415Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e3/1ee62dde9b335e4ed41db6bba02613295a0d5b41f74a783c142745a12763/aiohttp-3.13.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f33c8748abef4d8717bb20e8fb1b3e07c6adacb7fd6beaae971a764cf5f30d61", size = 490733, upload-time = "2025-10-28T20:57:38.205Z" }, + { url = "https://files.pythonhosted.org/packages/1a/aa/7a451b1d6a04e8d15a362af3e9b897de71d86feac3babf8894545d08d537/aiohttp-3.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ae32f24bbfb7dbb485a24b30b1149e2f200be94777232aeadba3eecece4d0aa4", size = 491303, upload-time = "2025-10-28T20:57:40.122Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/209958dbb9b01174870f6a7538cd1f3f28274fdbc88a750c238e2c456295/aiohttp-3.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7f02042c1f009ffb70067326ef183a047425bb2ff3bc434ead4dd4a4a66a2b", size = 1717965, upload-time = "2025-10-28T20:57:42.28Z" }, + { url = "https://files.pythonhosted.org/packages/08/aa/6a01848d6432f241416bc4866cae8dc03f05a5a884d2311280f6a09c73d6/aiohttp-3.13.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93655083005d71cd6c072cdab54c886e6570ad2c4592139c3fb967bfc19e4694", size = 1667221, upload-time = "2025-10-28T20:57:44.869Z" }, + { url = "https://files.pythonhosted.org/packages/87/4f/36c1992432d31bbc789fa0b93c768d2e9047ec8c7177e5cd84ea85155f36/aiohttp-3.13.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0db1e24b852f5f664cd728db140cf11ea0e82450471232a394b3d1a540b0f906", size = 1757178, upload-time = "2025-10-28T20:57:47.216Z" }, + { url = "https://files.pythonhosted.org/packages/ac/b4/8e940dfb03b7e0f68a82b88fd182b9be0a65cb3f35612fe38c038c3112cf/aiohttp-3.13.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b009194665bcd128e23eaddef362e745601afa4641930848af4c8559e88f18f9", size = 1838001, upload-time = "2025-10-28T20:57:49.337Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ef/39f3448795499c440ab66084a9db7d20ca7662e94305f175a80f5b7e0072/aiohttp-3.13.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c038a8fdc8103cd51dbd986ecdce141473ffd9775a7a8057a6ed9c3653478011", size = 1716325, upload-time = "2025-10-28T20:57:51.327Z" }, + { url = "https://files.pythonhosted.org/packages/d7/51/b311500ffc860b181c05d91c59a1313bdd05c82960fdd4035a15740d431e/aiohttp-3.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66bac29b95a00db411cd758fea0e4b9bdba6d549dfe333f9a945430f5f2cc5a6", size = 1547978, upload-time = "2025-10-28T20:57:53.554Z" }, + { url = "https://files.pythonhosted.org/packages/31/64/b9d733296ef79815226dab8c586ff9e3df41c6aff2e16c06697b2d2e6775/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4ebf9cfc9ba24a74cf0718f04aac2a3bbe745902cc7c5ebc55c0f3b5777ef213", size = 1682042, upload-time = "2025-10-28T20:57:55.617Z" }, + { url = "https://files.pythonhosted.org/packages/3f/30/43d3e0f9d6473a6db7d472104c4eff4417b1e9df01774cb930338806d36b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a4b88ebe35ce54205c7074f7302bd08a4cb83256a3e0870c72d6f68a3aaf8e49", size = 1680085, upload-time = "2025-10-28T20:57:57.59Z" }, + { url = "https://files.pythonhosted.org/packages/16/51/c709f352c911b1864cfd1087577760ced64b3e5bee2aa88b8c0c8e2e4972/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:98c4fb90bb82b70a4ed79ca35f656f4281885be076f3f970ce315402b53099ae", size = 1728238, upload-time = "2025-10-28T20:57:59.525Z" }, + { url = "https://files.pythonhosted.org/packages/19/e2/19bd4c547092b773caeb48ff5ae4b1ae86756a0ee76c16727fcfd281404b/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:ec7534e63ae0f3759df3a1ed4fa6bc8f75082a924b590619c0dd2f76d7043caa", size = 1544395, upload-time = "2025-10-28T20:58:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/cf/87/860f2803b27dfc5ed7be532832a3498e4919da61299b4a1f8eb89b8ff44d/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5b927cf9b935a13e33644cbed6c8c4b2d0f25b713d838743f8fe7191b33829c4", size = 1742965, upload-time = "2025-10-28T20:58:03.972Z" }, + { url = "https://files.pythonhosted.org/packages/67/7f/db2fc7618925e8c7a601094d5cbe539f732df4fb570740be88ed9e40e99a/aiohttp-3.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:88d6c017966a78c5265d996c19cdb79235be5e6412268d7e2ce7dee339471b7a", size = 1697585, upload-time = "2025-10-28T20:58:06.189Z" }, + { url = "https://files.pythonhosted.org/packages/0c/07/9127916cb09bb38284db5036036042b7b2c514c8ebaeee79da550c43a6d6/aiohttp-3.13.2-cp314-cp314-win32.whl", hash = "sha256:f7c183e786e299b5d6c49fb43a769f8eb8e04a2726a2bd5887b98b5cc2d67940", size = 431621, upload-time = "2025-10-28T20:58:08.636Z" }, + { url = "https://files.pythonhosted.org/packages/fb/41/554a8a380df6d3a2bba8a7726429a23f4ac62aaf38de43bb6d6cde7b4d4d/aiohttp-3.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:fe242cd381e0fb65758faf5ad96c2e460df6ee5b2de1072fe97e4127927e00b4", size = 457627, upload-time = "2025-10-28T20:58:11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8e/3824ef98c039d3951cb65b9205a96dd2b20f22241ee17d89c5701557c826/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f10d9c0b0188fe85398c61147bbd2a657d616c876863bfeff43376e0e3134673", size = 767360, upload-time = "2025-10-28T20:58:13.358Z" }, + { url = "https://files.pythonhosted.org/packages/a4/0f/6a03e3fc7595421274fa34122c973bde2d89344f8a881b728fa8c774e4f1/aiohttp-3.13.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e7c952aefdf2460f4ae55c5e9c3e80aa72f706a6317e06020f80e96253b1accd", size = 504616, upload-time = "2025-10-28T20:58:15.339Z" }, + { url = "https://files.pythonhosted.org/packages/c6/aa/ed341b670f1bc8a6f2c6a718353d13b9546e2cef3544f573c6a1ff0da711/aiohttp-3.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c20423ce14771d98353d2e25e83591fa75dfa90a3c1848f3d7c68243b4fbded3", size = 509131, upload-time = "2025-10-28T20:58:17.693Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f0/c68dac234189dae5c4bbccc0f96ce0cc16b76632cfc3a08fff180045cfa4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e96eb1a34396e9430c19d8338d2ec33015e4a87ef2b4449db94c22412e25ccdf", size = 1864168, upload-time = "2025-10-28T20:58:20.113Z" }, + { url = "https://files.pythonhosted.org/packages/8f/65/75a9a76db8364b5d0e52a0c20eabc5d52297385d9af9c35335b924fafdee/aiohttp-3.13.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:23fb0783bc1a33640036465019d3bba069942616a6a2353c6907d7fe1ccdaf4e", size = 1719200, upload-time = "2025-10-28T20:58:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/8df2ed78d7f41d232f6bd3ff866b6f617026551aa1d07e2f03458f964575/aiohttp-3.13.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e1a9bea6244a1d05a4e57c295d69e159a5c50d8ef16aa390948ee873478d9a5", size = 1843497, upload-time = "2025-10-28T20:58:24.672Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e0/94d7215e405c5a02ccb6a35c7a3a6cfff242f457a00196496935f700cde5/aiohttp-3.13.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a3d54e822688b56e9f6b5816fb3de3a3a64660efac64e4c2dc435230ad23bad", size = 1935703, upload-time = "2025-10-28T20:58:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/0b/78/1eeb63c3f9b2d1015a4c02788fb543141aad0a03ae3f7a7b669b2483f8d4/aiohttp-3.13.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7a653d872afe9f33497215745da7a943d1dc15b728a9c8da1c3ac423af35178e", size = 1792738, upload-time = "2025-10-28T20:58:29.787Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/aaf1eea4c188e51538c04cc568040e3082db263a57086ea74a7d38c39e42/aiohttp-3.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:56d36e80d2003fa3fc0207fac644216d8532e9504a785ef9a8fd013f84a42c61", size = 1624061, upload-time = "2025-10-28T20:58:32.529Z" }, + { url = "https://files.pythonhosted.org/packages/9b/c2/3b6034de81fbcc43de8aeb209073a2286dfb50b86e927b4efd81cf848197/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78cd586d8331fb8e241c2dd6b2f4061778cc69e150514b39a9e28dd050475661", size = 1789201, upload-time = "2025-10-28T20:58:34.618Z" }, + { url = "https://files.pythonhosted.org/packages/c9/38/c15dcf6d4d890217dae79d7213988f4e5fe6183d43893a9cf2fe9e84ca8d/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:20b10bbfbff766294fe99987f7bb3b74fdd2f1a2905f2562132641ad434dcf98", size = 1776868, upload-time = "2025-10-28T20:58:38.835Z" }, + { url = "https://files.pythonhosted.org/packages/04/75/f74fd178ac81adf4f283a74847807ade5150e48feda6aef024403716c30c/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9ec49dff7e2b3c85cdeaa412e9d438f0ecd71676fde61ec57027dd392f00c693", size = 1790660, upload-time = "2025-10-28T20:58:41.507Z" }, + { url = "https://files.pythonhosted.org/packages/e7/80/7368bd0d06b16b3aba358c16b919e9c46cf11587dc572091031b0e9e3ef0/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:94f05348c4406450f9d73d38efb41d669ad6cd90c7ee194810d0eefbfa875a7a", size = 1617548, upload-time = "2025-10-28T20:58:43.674Z" }, + { url = "https://files.pythonhosted.org/packages/7d/4b/a6212790c50483cb3212e507378fbe26b5086d73941e1ec4b56a30439688/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:fa4dcb605c6f82a80c7f95713c2b11c3b8e9893b3ebd2bc9bde93165ed6107be", size = 1817240, upload-time = "2025-10-28T20:58:45.787Z" }, + { url = "https://files.pythonhosted.org/packages/ff/f7/ba5f0ba4ea8d8f3c32850912944532b933acbf0f3a75546b89269b9b7dde/aiohttp-3.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cf00e5db968c3f67eccd2778574cf64d8b27d95b237770aa32400bd7a1ca4f6c", size = 1762334, upload-time = "2025-10-28T20:58:47.936Z" }, + { url = "https://files.pythonhosted.org/packages/7e/83/1a5a1856574588b1cad63609ea9ad75b32a8353ac995d830bf5da9357364/aiohttp-3.13.2-cp314-cp314t-win32.whl", hash = "sha256:d23b5fe492b0805a50d3371e8a728a9134d8de5447dce4c885f5587294750734", size = 464685, upload-time = "2025-10-28T20:58:50.642Z" }, + { url = "https://files.pythonhosted.org/packages/9f/4d/d22668674122c08f4d56972297c51a624e64b3ed1efaa40187607a7cb66e/aiohttp-3.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:ff0a7b0a82a7ab905cbda74006318d1b12e37c797eb1b0d4eb3e316cf47f658f", size = 498093, upload-time = "2025-10-28T20:58:52.782Z" }, +] + +[[package]] +name = "aiohttp-cors" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/d89e846a5444b3d5eb8985a6ddb0daef3774928e1bfbce8e84ec97b0ffa7/aiohttp_cors-0.8.1.tar.gz", hash = "sha256:ccacf9cb84b64939ea15f859a146af1f662a6b1d68175754a07315e305fb1403", size = 38626, upload-time = "2025-03-31T14:16:20.048Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/3b/40a68de458904bcc143622015fff2352b6461cd92fd66d3527bf1c6f5716/aiohttp_cors-0.8.1-py3-none-any.whl", hash = "sha256:3180cf304c5c712d626b9162b195b1db7ddf976a2a25172b35bb2448b890a80d", size = 25231, upload-time = "2025-03-31T14:16:18.478Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + [[package]] name = "alabaster" version = "1.0.0" @@ -101,6 +255,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, ] +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, +] + [[package]] name = "attrs" version = "25.3.0" @@ -171,13 +334,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/1d/64c6fd3f1b4180dd7c4766cfd7d241a0d7d432a477dca34fbf23386f88bd/bqskitrs-0.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:92f438063ce769a5fdb35220666cd90bb6c20551147cc5c72e77b0996fb4bef4", size = 1944299, upload-time = "2023-11-29T18:05:24.532Z" }, ] +[[package]] +name = "cachetools" +version = "6.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/1d/ede8680603f6016887c062a2cf4fc8fdba905866a3ab8831aa8aa651320c/cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607", size = 31731, upload-time = "2025-12-15T18:24:53.744Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/fc/1d7b80d0eb7b714984ce40efc78859c022cd930e402f599d8ca9e39c78a4/cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51", size = 11551, upload-time = "2025-12-15T18:24:52.332Z" }, +] + [[package]] name = "certifi" -version = "2025.8.3" +version = "2024.7.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/02/a95f2b11e207f68bc64d7aae9666fed2e2b3f307748d5123dffb72a1bbea/certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", size = 164065, upload-time = "2024-07-04T01:36:11.653Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, + { url = "https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90", size = 162960, upload-time = "2024-07-04T01:36:09.038Z" }, ] [[package]] @@ -312,11 +484,11 @@ wheels = [ [[package]] name = "cloudpickle" -version = "3.1.1" +version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/39/069100b84d7418bc358d81669d5748efb14b9cceacd2f9c75f550424132f/cloudpickle-3.1.1.tar.gz", hash = "sha256:b216fa8ae4019d5482a8ac3c95d8f6346115d8835911fd4aefd1a445e4242c64", size = 22113, upload-time = "2025-01-14T17:02:05.085Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/51/913ecca3970a2227cf4d5e8937df52cc28f465ac442216110b8e3323262d/cloudpickle-2.2.1.tar.gz", hash = "sha256:d89684b8de9e34a2a43b3460fbca07d09d6e25ce858df4d5a44240403b6178f5", size = 60800, upload-time = "2023-01-19T09:27:28.318Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/e8/64c37fadfc2816a7701fa8a6ed8d87327c7d54eacfbfb6edab14a2f2be75/cloudpickle-3.1.1-py3-none-any.whl", hash = "sha256:c8c5a44295039331ee9dad40ba100a9c7297b6f988e50e87ccdf3765a668350e", size = 20992, upload-time = "2025-01-14T17:02:02.417Z" }, + { url = "https://files.pythonhosted.org/packages/15/80/44286939ca215e88fa827b2aeb6fa3fd2b4a7af322485c7170d6f9fd96e0/cloudpickle-2.2.1-py3-none-any.whl", hash = "sha256:61f594d1f4c295fa5cd9014ceb3a1fc4a70b0de1164b94fbc2d854ccba056f9f", size = 25944, upload-time = "2023-01-19T09:27:26.341Z" }, ] [[package]] @@ -328,6 +500,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "colorful" +version = "0.5.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/31/109ef4bedeb32b4202e02ddb133162457adc4eb890a9ed9c05c9dd126ed0/colorful-0.5.8.tar.gz", hash = "sha256:bb16502b198be2f1c42ba3c52c703d5f651d826076817185f0294c1a549a7445", size = 209361, upload-time = "2025-10-29T11:53:21.663Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/11/25cdf9d5fc21efd30134fc74c43702c6f7ef09ebae8ed927f1283403ad8d/colorful-0.5.8-py2.py3-none-any.whl", hash = "sha256:a9381fdda3337fbaba5771991020abc69676afa102646650b759927892875992", size = 201334, upload-time = "2025-10-29T11:53:20.251Z" }, +] + [[package]] name = "colorlog" version = "6.10.1" @@ -717,6 +901,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" }, ] +[[package]] +name = "deprecated" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, +] + [[package]] name = "dill" version = "0.4.0" @@ -833,6 +1029,127 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/9c/df0ef2c51845a13043e5088f7bb988ca6cd5bb82d5d4203d6a158aa58cf2/fonttools-4.59.0-py3-none-any.whl", hash = "sha256:241313683afd3baacb32a6bd124d0bce7404bc5280e12e291bae1b9bba28711d", size = 1128050, upload-time = "2025-07-16T12:04:52.687Z" }, ] +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + [[package]] name = "fsspec" version = "2025.7.0" @@ -859,6 +1176,48 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/69/964b55f389c289e16ba2a5dfe587c3c462aac09e24123f09ddf703889584/furo-2025.9.25-py3-none-any.whl", hash = "sha256:2937f68e823b8e37b410c972c371bc2b1d88026709534927158e0cb3fac95afe", size = 340409, upload-time = "2025-09-25T21:37:17.244Z" }, ] +[[package]] +name = "google-api-core" +version = "2.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759, upload-time = "2025-10-28T21:34:51.529Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706, upload-time = "2025-10-28T21:34:50.151Z" }, +] + +[[package]] +name = "google-auth" +version = "2.45.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e5/00/3c794502a8b892c404b2dea5b3650eb21bfc7069612fbfd15c7f17c1cb0d/google_auth-2.45.0.tar.gz", hash = "sha256:90d3f41b6b72ea72dd9811e765699ee491ab24139f34ebf1ca2b9cc0c38708f3", size = 320708, upload-time = "2025-12-15T22:58:42.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/97/451d55e05487a5cd6279a01a7e34921858b16f7dc8aa38a2c684743cd2b3/google_auth-2.45.0-py2.py3-none-any.whl", hash = "sha256:82344e86dc00410ef5382d99be677c6043d72e502b625aa4f4afa0bdacca0f36", size = 233312, upload-time = "2025-12-15T22:58:40.777Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.72.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, +] + [[package]] name = "graphviz" version = "0.21" @@ -1065,14 +1424,14 @@ wheels = [ [[package]] name = "importlib-metadata" -version = "8.7.0" +version = "8.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/bd/fa8ce65b0a7d4b6d143ec23b0f5fd3f7ab80121078c465bc02baeaab22dc/importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5", size = 54320, upload-time = "2024-08-20T17:11:42.348Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/c0/14/362d31bf1076b21e1bcdcb0dc61944822ff263937b804a79231df2774d28/importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1", size = 26269, upload-time = "2024-08-20T17:11:41.102Z" }, ] [[package]] @@ -1092,8 +1451,7 @@ dependencies = [ { name = "appnope", marker = "sys_platform == 'darwin'" }, { name = "comm" }, { name = "debugpy" }, - { name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "ipython", version = "9.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "ipython" }, { name = "jupyter-client" }, { name = "jupyter-core" }, { name = "matplotlib-inline" }, @@ -1113,22 +1471,18 @@ wheels = [ name = "ipython" version = "8.37.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version < '3.11' and 'x86_64' not in platform_machine) or (python_full_version < '3.11' and sys_platform != 'darwin')", -] dependencies = [ - { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, - { name = "decorator", marker = "python_full_version < '3.11'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "jedi", marker = "python_full_version < '3.11'" }, - { name = "matplotlib-inline", marker = "python_full_version < '3.11'" }, - { name = "pexpect", marker = "python_full_version < '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit", marker = "python_full_version < '3.11'" }, - { name = "pygments", marker = "python_full_version < '3.11'" }, - { name = "stack-data", marker = "python_full_version < '3.11'" }, - { name = "traitlets", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088, upload-time = "2025-05-31T16:39:09.613Z" } wheels = [ @@ -1136,44 +1490,19 @@ wheels = [ ] [[package]] -name = "ipython" -version = "9.4.0" +name = "ipywidgets" +version = "8.1.8" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13'", - "python_full_version == '3.12.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.12.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.12.*' and sys_platform != 'darwin')", - "python_full_version == '3.11.*' and 'x86_64' in platform_machine and sys_platform == 'darwin'", - "(python_full_version == '3.11.*' and 'x86_64' not in platform_machine) or (python_full_version == '3.11.*' and sys_platform != 'darwin')", -] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, - { name = "decorator", marker = "python_full_version >= '3.11'" }, - { name = "ipython-pygments-lexers", marker = "python_full_version >= '3.11'" }, - { name = "jedi", marker = "python_full_version >= '3.11'" }, - { name = "matplotlib-inline", marker = "python_full_version >= '3.11'" }, - { name = "pexpect", marker = "python_full_version >= '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit", marker = "python_full_version >= '3.11'" }, - { name = "pygments", marker = "python_full_version >= '3.11'" }, - { name = "stack-data", marker = "python_full_version >= '3.11'" }, - { name = "traitlets", marker = "python_full_version >= '3.11'" }, - { name = "typing-extensions", marker = "python_full_version == '3.11.*'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/80/406f9e3bde1c1fd9bf5a0be9d090f8ae623e401b7670d8f6fdf2ab679891/ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270", size = 4385338, upload-time = "2025-07-01T11:11:30.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066", size = 611021, upload-time = "2025-07-01T11:11:27.85Z" }, -] - -[[package]] -name = "ipython-pygments-lexers" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pygments", marker = "python_full_version >= '3.11'" }, + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, ] [[package]] @@ -1285,6 +1614,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0", size = 28880, upload-time = "2025-05-27T07:38:15.137Z" }, ] +[[package]] +name = "jupyterlab-widgets" +version = "3.0.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, +] + [[package]] name = "kiwisolver" version = "1.4.8" @@ -1615,7 +1953,7 @@ dependencies = [ { name = "qiskit" }, { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'" }, { name = "qiskit-ibm-runtime" }, - { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'" }, + { name = "qiskit-ibm-transpiler" }, { name = "rich" }, { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, @@ -1661,9 +1999,9 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = ">=1.3.3" }, - { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.4.2" }, + { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.5.5" }, { name = "qiskit-ibm-runtime", specifier = ">=0.30.0,<0.42.0" }, - { name = "qiskit-ibm-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.13.1" }, + { name = "qiskit-ibm-transpiler", specifier = "==0.15.0" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, @@ -1697,6 +2035,205 @@ test = [ { name = "pytest-cov", specifier = ">=7.0.0" }, ] +[[package]] +name = "msgpack" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/a2/3b68a9e769db68668b25c6108444a35f9bd163bb848c0650d516761a59c0/msgpack-1.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0051fffef5a37ca2cd16978ae4f0aef92f164df86823871b5162812bebecd8e2", size = 81318, upload-time = "2025-10-08T09:14:38.722Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e1/2b720cc341325c00be44e1ed59e7cfeae2678329fbf5aa68f5bda57fe728/msgpack-1.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a605409040f2da88676e9c9e5853b3449ba8011973616189ea5ee55ddbc5bc87", size = 83786, upload-time = "2025-10-08T09:14:40.082Z" }, + { url = "https://files.pythonhosted.org/packages/71/e5/c2241de64bfceac456b140737812a2ab310b10538a7b34a1d393b748e095/msgpack-1.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b696e83c9f1532b4af884045ba7f3aa741a63b2bc22617293a2c6a7c645f251", size = 398240, upload-time = "2025-10-08T09:14:41.151Z" }, + { url = "https://files.pythonhosted.org/packages/b7/09/2a06956383c0fdebaef5aa9246e2356776f12ea6f2a44bd1368abf0e46c4/msgpack-1.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:365c0bbe981a27d8932da71af63ef86acc59ed5c01ad929e09a0b88c6294e28a", size = 406070, upload-time = "2025-10-08T09:14:42.821Z" }, + { url = "https://files.pythonhosted.org/packages/0e/74/2957703f0e1ef20637d6aead4fbb314330c26f39aa046b348c7edcf6ca6b/msgpack-1.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41d1a5d875680166d3ac5c38573896453bbbea7092936d2e107214daf43b1d4f", size = 393403, upload-time = "2025-10-08T09:14:44.38Z" }, + { url = "https://files.pythonhosted.org/packages/a5/09/3bfc12aa90f77b37322fc33e7a8a7c29ba7c8edeadfa27664451801b9860/msgpack-1.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354e81bcdebaab427c3df4281187edc765d5d76bfb3a7c125af9da7a27e8458f", size = 398947, upload-time = "2025-10-08T09:14:45.56Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4f/05fcebd3b4977cb3d840f7ef6b77c51f8582086de5e642f3fefee35c86fc/msgpack-1.1.2-cp310-cp310-win32.whl", hash = "sha256:e64c8d2f5e5d5fda7b842f55dec6133260ea8f53c4257d64494c534f306bf7a9", size = 64769, upload-time = "2025-10-08T09:14:47.334Z" }, + { url = "https://files.pythonhosted.org/packages/d0/3e/b4547e3a34210956382eed1c85935fff7e0f9b98be3106b3745d7dec9c5e/msgpack-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:db6192777d943bdaaafb6ba66d44bf65aa0e9c5616fa1d2da9bb08828c6b39aa", size = 71293, upload-time = "2025-10-08T09:14:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" }, + { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" }, + { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" }, + { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" }, + { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" }, + { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:372839311ccf6bdaf39b00b61288e0557916c3729529b301c52c2d88842add42", size = 427556, upload-time = "2025-10-08T09:15:06.837Z" }, + { url = "https://files.pythonhosted.org/packages/f5/87/ffe21d1bf7d9991354ad93949286f643b2bb6ddbeab66373922b44c3b8cc/msgpack-1.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2929af52106ca73fcb28576218476ffbb531a036c2adbcf54a3664de124303e9", size = 404920, upload-time = "2025-10-08T09:15:08.179Z" }, + { url = "https://files.pythonhosted.org/packages/ff/41/8543ed2b8604f7c0d89ce066f42007faac1eaa7d79a81555f206a5cdb889/msgpack-1.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be52a8fc79e45b0364210eef5234a7cf8d330836d0a64dfbb878efa903d84620", size = 415013, upload-time = "2025-10-08T09:15:09.83Z" }, + { url = "https://files.pythonhosted.org/packages/41/0d/2ddfaa8b7e1cee6c490d46cb0a39742b19e2481600a7a0e96537e9c22f43/msgpack-1.1.2-cp312-cp312-win32.whl", hash = "sha256:1fff3d825d7859ac888b0fbda39a42d59193543920eda9d9bea44d958a878029", size = 65096, upload-time = "2025-10-08T09:15:11.11Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b", size = 72708, upload-time = "2025-10-08T09:15:12.554Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/5b1a1f70eb0e87d1678e9624908f86317787b536060641d6798e3cf70ace/msgpack-1.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:be5980f3ee0e6bd44f3a9e9dea01054f175b50c3e6cdb692bc9424c0bbb8bf69", size = 64119, upload-time = "2025-10-08T09:15:13.589Z" }, + { url = "https://files.pythonhosted.org/packages/6b/31/b46518ecc604d7edf3a4f94cb3bf021fc62aa301f0cb849936968164ef23/msgpack-1.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4efd7b5979ccb539c221a4c4e16aac1a533efc97f3b759bb5a5ac9f6d10383bf", size = 81212, upload-time = "2025-10-08T09:15:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/92/dc/c385f38f2c2433333345a82926c6bfa5ecfff3ef787201614317b58dd8be/msgpack-1.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42eefe2c3e2af97ed470eec850facbe1b5ad1d6eacdbadc42ec98e7dcf68b4b7", size = 84315, upload-time = "2025-10-08T09:15:15.543Z" }, + { url = "https://files.pythonhosted.org/packages/d3/68/93180dce57f684a61a88a45ed13047558ded2be46f03acb8dec6d7c513af/msgpack-1.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fdf7d83102bf09e7ce3357de96c59b627395352a4024f6e2458501f158bf999", size = 412721, upload-time = "2025-10-08T09:15:16.567Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ba/459f18c16f2b3fc1a1ca871f72f07d70c07bf768ad0a507a698b8052ac58/msgpack-1.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fac4be746328f90caa3cd4bc67e6fe36ca2bf61d5c6eb6d895b6527e3f05071e", size = 424657, upload-time = "2025-10-08T09:15:17.825Z" }, + { url = "https://files.pythonhosted.org/packages/38/f8/4398c46863b093252fe67368b44edc6c13b17f4e6b0e4929dbf0bdb13f23/msgpack-1.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fffee09044073e69f2bad787071aeec727183e7580443dfeb8556cbf1978d162", size = 402668, upload-time = "2025-10-08T09:15:19.003Z" }, + { url = "https://files.pythonhosted.org/packages/28/ce/698c1eff75626e4124b4d78e21cca0b4cc90043afb80a507626ea354ab52/msgpack-1.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5928604de9b032bc17f5099496417f113c45bc6bc21b5c6920caf34b3c428794", size = 419040, upload-time = "2025-10-08T09:15:20.183Z" }, + { url = "https://files.pythonhosted.org/packages/67/32/f3cd1667028424fa7001d82e10ee35386eea1408b93d399b09fb0aa7875f/msgpack-1.1.2-cp313-cp313-win32.whl", hash = "sha256:a7787d353595c7c7e145e2331abf8b7ff1e6673a6b974ded96e6d4ec09f00c8c", size = 65037, upload-time = "2025-10-08T09:15:21.416Z" }, + { url = "https://files.pythonhosted.org/packages/74/07/1ed8277f8653c40ebc65985180b007879f6a836c525b3885dcc6448ae6cb/msgpack-1.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:a465f0dceb8e13a487e54c07d04ae3ba131c7c5b95e2612596eafde1dccf64a9", size = 72631, upload-time = "2025-10-08T09:15:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/e5/db/0314e4e2db56ebcf450f277904ffd84a7988b9e5da8d0d61ab2d057df2b6/msgpack-1.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:e69b39f8c0aa5ec24b57737ebee40be647035158f14ed4b40e6f150077e21a84", size = 64118, upload-time = "2025-10-08T09:15:23.402Z" }, + { url = "https://files.pythonhosted.org/packages/22/71/201105712d0a2ff07b7873ed3c220292fb2ea5120603c00c4b634bcdafb3/msgpack-1.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e23ce8d5f7aa6ea6d2a2b326b4ba46c985dbb204523759984430db7114f8aa00", size = 81127, upload-time = "2025-10-08T09:15:24.408Z" }, + { url = "https://files.pythonhosted.org/packages/1b/9f/38ff9e57a2eade7bf9dfee5eae17f39fc0e998658050279cbb14d97d36d9/msgpack-1.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c15b7d74c939ebe620dd8e559384be806204d73b4f9356320632d783d1f7939", size = 84981, upload-time = "2025-10-08T09:15:25.812Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a9/3536e385167b88c2cc8f4424c49e28d49a6fc35206d4a8060f136e71f94c/msgpack-1.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99e2cb7b9031568a2a5c73aa077180f93dd2e95b4f8d3b8e14a73ae94a9e667e", size = 411885, upload-time = "2025-10-08T09:15:27.22Z" }, + { url = "https://files.pythonhosted.org/packages/2f/40/dc34d1a8d5f1e51fc64640b62b191684da52ca469da9cd74e84936ffa4a6/msgpack-1.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:180759d89a057eab503cf62eeec0aa61c4ea1200dee709f3a8e9397dbb3b6931", size = 419658, upload-time = "2025-10-08T09:15:28.4Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ef/2b92e286366500a09a67e03496ee8b8ba00562797a52f3c117aa2b29514b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:04fb995247a6e83830b62f0b07bf36540c213f6eac8e851166d8d86d83cbd014", size = 403290, upload-time = "2025-10-08T09:15:29.764Z" }, + { url = "https://files.pythonhosted.org/packages/78/90/e0ea7990abea5764e4655b8177aa7c63cdfa89945b6e7641055800f6c16b/msgpack-1.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8e22ab046fa7ede9e36eeb4cfad44d46450f37bb05d5ec482b02868f451c95e2", size = 415234, upload-time = "2025-10-08T09:15:31.022Z" }, + { url = "https://files.pythonhosted.org/packages/72/4e/9390aed5db983a2310818cd7d3ec0aecad45e1f7007e0cda79c79507bb0d/msgpack-1.1.2-cp314-cp314-win32.whl", hash = "sha256:80a0ff7d4abf5fecb995fcf235d4064b9a9a8a40a3ab80999e6ac1e30b702717", size = 66391, upload-time = "2025-10-08T09:15:32.265Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:9ade919fac6a3e7260b7f64cea89df6bec59104987cbea34d34a2fa15d74310b", size = 73787, upload-time = "2025-10-08T09:15:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b0/9d9f667ab48b16ad4115c1935d94023b82b3198064cb84a123e97f7466c1/msgpack-1.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:59415c6076b1e30e563eb732e23b994a61c159cec44deaf584e5cc1dd662f2af", size = 66453, upload-time = "2025-10-08T09:15:34.225Z" }, + { url = "https://files.pythonhosted.org/packages/16/67/93f80545eb1792b61a217fa7f06d5e5cb9e0055bed867f43e2b8e012e137/msgpack-1.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:897c478140877e5307760b0ea66e0932738879e7aa68144d9b78ea4c8302a84a", size = 85264, upload-time = "2025-10-08T09:15:35.61Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/33c8a24959cf193966ef11a6f6a2995a65eb066bd681fd085afd519a57ce/msgpack-1.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a668204fa43e6d02f89dbe79a30b0d67238d9ec4c5bd8a940fc3a004a47b721b", size = 89076, upload-time = "2025-10-08T09:15:36.619Z" }, + { url = "https://files.pythonhosted.org/packages/fc/6b/62e85ff7193663fbea5c0254ef32f0c77134b4059f8da89b958beb7696f3/msgpack-1.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5559d03930d3aa0f3aacb4c42c776af1a2ace2611871c84a75afe436695e6245", size = 435242, upload-time = "2025-10-08T09:15:37.647Z" }, + { url = "https://files.pythonhosted.org/packages/c1/47/5c74ecb4cc277cf09f64e913947871682ffa82b3b93c8dad68083112f412/msgpack-1.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:70c5a7a9fea7f036b716191c29047374c10721c389c21e9ffafad04df8c52c90", size = 432509, upload-time = "2025-10-08T09:15:38.794Z" }, + { url = "https://files.pythonhosted.org/packages/24/a4/e98ccdb56dc4e98c929a3f150de1799831c0a800583cde9fa022fa90602d/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f2cb069d8b981abc72b41aea1c580ce92d57c673ec61af4c500153a626cb9e20", size = 415957, upload-time = "2025-10-08T09:15:40.238Z" }, + { url = "https://files.pythonhosted.org/packages/da/28/6951f7fb67bc0a4e184a6b38ab71a92d9ba58080b27a77d3e2fb0be5998f/msgpack-1.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d62ce1f483f355f61adb5433ebfd8868c5f078d1a52d042b0a998682b4fa8c27", size = 422910, upload-time = "2025-10-08T09:15:41.505Z" }, + { url = "https://files.pythonhosted.org/packages/f0/03/42106dcded51f0a0b5284d3ce30a671e7bd3f7318d122b2ead66ad289fed/msgpack-1.1.2-cp314-cp314t-win32.whl", hash = "sha256:1d1418482b1ee984625d88aa9585db570180c286d942da463533b238b98b812b", size = 75197, upload-time = "2025-10-08T09:15:42.954Z" }, + { url = "https://files.pythonhosted.org/packages/15/86/d0071e94987f8db59d4eeb386ddc64d0bb9b10820a8d82bcd3e53eeb2da6/msgpack-1.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5a46bf7e831d09470ad92dff02b8b1ac92175ca36b087f904a0519857c6be3ff", size = 85772, upload-time = "2025-10-08T09:15:43.954Z" }, + { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153, upload-time = "2025-10-06T14:48:26.409Z" }, + { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993, upload-time = "2025-10-06T14:48:28.4Z" }, + { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607, upload-time = "2025-10-06T14:48:29.581Z" }, + { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847, upload-time = "2025-10-06T14:48:32.107Z" }, + { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616, upload-time = "2025-10-06T14:48:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333, upload-time = "2025-10-06T14:48:35.9Z" }, + { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239, upload-time = "2025-10-06T14:48:37.302Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618, upload-time = "2025-10-06T14:48:38.963Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655, upload-time = "2025-10-06T14:48:40.312Z" }, + { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245, upload-time = "2025-10-06T14:48:41.848Z" }, + { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523, upload-time = "2025-10-06T14:48:43.749Z" }, + { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129, upload-time = "2025-10-06T14:48:45.225Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999, upload-time = "2025-10-06T14:48:46.703Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711, upload-time = "2025-10-06T14:48:48.146Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504, upload-time = "2025-10-06T14:48:49.447Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422, upload-time = "2025-10-06T14:48:50.789Z" }, + { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050, upload-time = "2025-10-06T14:48:51.938Z" }, + { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153, upload-time = "2025-10-06T14:48:53.146Z" }, + { url = "https://files.pythonhosted.org/packages/34/9e/5c727587644d67b2ed479041e4b1c58e30afc011e3d45d25bbe35781217c/multidict-6.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4d409aa42a94c0b3fa617708ef5276dfe81012ba6753a0370fcc9d0195d0a1fc", size = 76604, upload-time = "2025-10-06T14:48:54.277Z" }, + { url = "https://files.pythonhosted.org/packages/17/e4/67b5c27bd17c085a5ea8f1ec05b8a3e5cba0ca734bfcad5560fb129e70ca/multidict-6.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14c9e076eede3b54c636f8ce1c9c252b5f057c62131211f0ceeec273810c9721", size = 44715, upload-time = "2025-10-06T14:48:55.445Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/866a5d77be6ea435711bef2a4291eed11032679b6b28b56b4776ab06ba3e/multidict-6.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c09703000a9d0fa3c3404b27041e574cc7f4df4c6563873246d0e11812a94b6", size = 44332, upload-time = "2025-10-06T14:48:56.706Z" }, + { url = "https://files.pythonhosted.org/packages/31/61/0c2d50241ada71ff61a79518db85ada85fdabfcf395d5968dae1cbda04e5/multidict-6.7.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a265acbb7bb33a3a2d626afbe756371dce0279e7b17f4f4eda406459c2b5ff1c", size = 245212, upload-time = "2025-10-06T14:48:58.042Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e0/919666a4e4b57fff1b57f279be1c9316e6cdc5de8a8b525d76f6598fefc7/multidict-6.7.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51cb455de290ae462593e5b1cb1118c5c22ea7f0d3620d9940bf695cea5a4bd7", size = 246671, upload-time = "2025-10-06T14:49:00.004Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cc/d027d9c5a520f3321b65adea289b965e7bcbd2c34402663f482648c716ce/multidict-6.7.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:db99677b4457c7a5c5a949353e125ba72d62b35f74e26da141530fbb012218a7", size = 225491, upload-time = "2025-10-06T14:49:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/75/c4/bbd633980ce6155a28ff04e6a6492dd3335858394d7bb752d8b108708558/multidict-6.7.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f470f68adc395e0183b92a2f4689264d1ea4b40504a24d9882c27375e6662bb9", size = 257322, upload-time = "2025-10-06T14:49:02.745Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6d/d622322d344f1f053eae47e033b0b3f965af01212de21b10bcf91be991fb/multidict-6.7.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0db4956f82723cc1c270de9c6e799b4c341d327762ec78ef82bb962f79cc07d8", size = 254694, upload-time = "2025-10-06T14:49:04.15Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9f/78f8761c2705d4c6d7516faed63c0ebdac569f6db1bef95e0d5218fdc146/multidict-6.7.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e56d780c238f9e1ae66a22d2adf8d16f485381878250db8d496623cd38b22bd", size = 246715, upload-time = "2025-10-06T14:49:05.967Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/950818e04f91b9c2b95aab3d923d9eabd01689d0dcd889563988e9ea0fd8/multidict-6.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d14baca2ee12c1a64740d4531356ba50b82543017f3ad6de0deb943c5979abb", size = 243189, upload-time = "2025-10-06T14:49:07.37Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3d/77c79e1934cad2ee74991840f8a0110966d9599b3af95964c0cd79bb905b/multidict-6.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:295a92a76188917c7f99cda95858c822f9e4aae5824246bba9b6b44004ddd0a6", size = 237845, upload-time = "2025-10-06T14:49:08.759Z" }, + { url = "https://files.pythonhosted.org/packages/63/1b/834ce32a0a97a3b70f86437f685f880136677ac00d8bce0027e9fd9c2db7/multidict-6.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39f1719f57adbb767ef592a50ae5ebb794220d1188f9ca93de471336401c34d2", size = 246374, upload-time = "2025-10-06T14:49:10.574Z" }, + { url = "https://files.pythonhosted.org/packages/23/ef/43d1c3ba205b5dec93dc97f3fba179dfa47910fc73aaaea4f7ceb41cec2a/multidict-6.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a13fb8e748dfc94749f622de065dd5c1def7e0d2216dba72b1d8069a389c6ff", size = 253345, upload-time = "2025-10-06T14:49:12.331Z" }, + { url = "https://files.pythonhosted.org/packages/6b/03/eaf95bcc2d19ead522001f6a650ef32811aa9e3624ff0ad37c445c7a588c/multidict-6.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e3aa16de190d29a0ea1b48253c57d99a68492c8dd8948638073ab9e74dc9410b", size = 246940, upload-time = "2025-10-06T14:49:13.821Z" }, + { url = "https://files.pythonhosted.org/packages/e8/df/ec8a5fd66ea6cd6f525b1fcbb23511b033c3e9bc42b81384834ffa484a62/multidict-6.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a048ce45dcdaaf1defb76b2e684f997fb5abf74437b6cb7b22ddad934a964e34", size = 242229, upload-time = "2025-10-06T14:49:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a2/59b405d59fd39ec86d1142630e9049243015a5f5291ba49cadf3c090c541/multidict-6.7.0-cp311-cp311-win32.whl", hash = "sha256:a90af66facec4cebe4181b9e62a68be65e45ac9b52b67de9eec118701856e7ff", size = 41308, upload-time = "2025-10-06T14:49:16.871Z" }, + { url = "https://files.pythonhosted.org/packages/32/0f/13228f26f8b882c34da36efa776c3b7348455ec383bab4a66390e42963ae/multidict-6.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:95b5ffa4349df2887518bb839409bcf22caa72d82beec453216802f475b23c81", size = 46037, upload-time = "2025-10-06T14:49:18.457Z" }, + { url = "https://files.pythonhosted.org/packages/84/1f/68588e31b000535a3207fd3c909ebeec4fb36b52c442107499c18a896a2a/multidict-6.7.0-cp311-cp311-win_arm64.whl", hash = "sha256:329aa225b085b6f004a4955271a7ba9f1087e39dcb7e65f6284a988264a63912", size = 43023, upload-time = "2025-10-06T14:49:19.648Z" }, + { url = "https://files.pythonhosted.org/packages/c2/9e/9f61ac18d9c8b475889f32ccfa91c9f59363480613fc807b6e3023d6f60b/multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184", size = 76877, upload-time = "2025-10-06T14:49:20.884Z" }, + { url = "https://files.pythonhosted.org/packages/38/6f/614f09a04e6184f8824268fce4bc925e9849edfa654ddd59f0b64508c595/multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45", size = 45467, upload-time = "2025-10-06T14:49:22.054Z" }, + { url = "https://files.pythonhosted.org/packages/b3/93/c4f67a436dd026f2e780c433277fff72be79152894d9fc36f44569cab1a6/multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa", size = 43834, upload-time = "2025-10-06T14:49:23.566Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f5/013798161ca665e4a422afbc5e2d9e4070142a9ff8905e482139cd09e4d0/multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7", size = 250545, upload-time = "2025-10-06T14:49:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/71/2f/91dbac13e0ba94669ea5119ba267c9a832f0cb65419aca75549fcf09a3dc/multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e", size = 258305, upload-time = "2025-10-06T14:49:26.778Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b0/754038b26f6e04488b48ac621f779c341338d78503fb45403755af2df477/multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546", size = 242363, upload-time = "2025-10-06T14:49:28.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/15/9da40b9336a7c9fa606c4cf2ed80a649dffeb42b905d4f63a1d7eb17d746/multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4", size = 268375, upload-time = "2025-10-06T14:49:29.96Z" }, + { url = "https://files.pythonhosted.org/packages/82/72/c53fcade0cc94dfaad583105fd92b3a783af2091eddcb41a6d5a52474000/multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1", size = 269346, upload-time = "2025-10-06T14:49:31.404Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e2/9baffdae21a76f77ef8447f1a05a96ec4bc0a24dae08767abc0a2fe680b8/multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d", size = 256107, upload-time = "2025-10-06T14:49:32.974Z" }, + { url = "https://files.pythonhosted.org/packages/3c/06/3f06f611087dc60d65ef775f1fb5aca7c6d61c6db4990e7cda0cef9b1651/multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304", size = 253592, upload-time = "2025-10-06T14:49:34.52Z" }, + { url = "https://files.pythonhosted.org/packages/20/24/54e804ec7945b6023b340c412ce9c3f81e91b3bf5fa5ce65558740141bee/multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12", size = 251024, upload-time = "2025-10-06T14:49:35.956Z" }, + { url = "https://files.pythonhosted.org/packages/14/48/011cba467ea0b17ceb938315d219391d3e421dfd35928e5dbdc3f4ae76ef/multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62", size = 251484, upload-time = "2025-10-06T14:49:37.631Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2f/919258b43bb35b99fa127435cfb2d91798eb3a943396631ef43e3720dcf4/multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0", size = 263579, upload-time = "2025-10-06T14:49:39.502Z" }, + { url = "https://files.pythonhosted.org/packages/31/22/a0e884d86b5242b5a74cf08e876bdf299e413016b66e55511f7a804a366e/multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a", size = 259654, upload-time = "2025-10-06T14:49:41.32Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/17e10e1b5c5f5a40f2fcbb45953c9b215f8a4098003915e46a93f5fcaa8f/multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8", size = 251511, upload-time = "2025-10-06T14:49:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9a/201bb1e17e7af53139597069c375e7b0dcbd47594604f65c2d5359508566/multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4", size = 41895, upload-time = "2025-10-06T14:49:48.718Z" }, + { url = "https://files.pythonhosted.org/packages/46/e2/348cd32faad84eaf1d20cce80e2bb0ef8d312c55bca1f7fa9865e7770aaf/multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b", size = 46073, upload-time = "2025-10-06T14:49:50.28Z" }, + { url = "https://files.pythonhosted.org/packages/25/ec/aad2613c1910dce907480e0c3aa306905830f25df2e54ccc9dea450cb5aa/multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec", size = 43226, upload-time = "2025-10-06T14:49:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/d2/86/33272a544eeb36d66e4d9a920602d1a2f57d4ebea4ef3cdfe5a912574c95/multidict-6.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bee7c0588aa0076ce77c0ea5d19a68d76ad81fcd9fe8501003b9a24f9d4000f6", size = 76135, upload-time = "2025-10-06T14:49:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/91/1c/eb97db117a1ebe46d457a3d235a7b9d2e6dcab174f42d1b67663dd9e5371/multidict-6.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7ef6b61cad77091056ce0e7ce69814ef72afacb150b7ac6a3e9470def2198159", size = 45117, upload-time = "2025-10-06T14:49:55.82Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d8/6c3442322e41fb1dd4de8bd67bfd11cd72352ac131f6368315617de752f1/multidict-6.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c0359b1ec12b1d6849c59f9d319610b7f20ef990a6d454ab151aa0e3b9f78ca", size = 43472, upload-time = "2025-10-06T14:49:57.048Z" }, + { url = "https://files.pythonhosted.org/packages/75/3f/e2639e80325af0b6c6febdf8e57cc07043ff15f57fa1ef808f4ccb5ac4cd/multidict-6.7.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cd240939f71c64bd658f186330603aac1a9a81bf6273f523fca63673cb7378a8", size = 249342, upload-time = "2025-10-06T14:49:58.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/cc/84e0585f805cbeaa9cbdaa95f9a3d6aed745b9d25700623ac89a6ecff400/multidict-6.7.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60a4d75718a5efa473ebd5ab685786ba0c67b8381f781d1be14da49f1a2dc60", size = 257082, upload-time = "2025-10-06T14:49:59.89Z" }, + { url = "https://files.pythonhosted.org/packages/b0/9c/ac851c107c92289acbbf5cfb485694084690c1b17e555f44952c26ddc5bd/multidict-6.7.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53a42d364f323275126aff81fb67c5ca1b7a04fda0546245730a55c8c5f24bc4", size = 240704, upload-time = "2025-10-06T14:50:01.485Z" }, + { url = "https://files.pythonhosted.org/packages/50/cc/5f93e99427248c09da95b62d64b25748a5f5c98c7c2ab09825a1d6af0e15/multidict-6.7.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3b29b980d0ddbecb736735ee5bef69bb2ddca56eff603c86f3f29a1128299b4f", size = 266355, upload-time = "2025-10-06T14:50:02.955Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0c/2ec1d883ceb79c6f7f6d7ad90c919c898f5d1c6ea96d322751420211e072/multidict-6.7.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8a93b1c0ed2d04b97a5e9336fd2d33371b9a6e29ab7dd6503d63407c20ffbaf", size = 267259, upload-time = "2025-10-06T14:50:04.446Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2d/f0b184fa88d6630aa267680bdb8623fb69cb0d024b8c6f0d23f9a0f406d3/multidict-6.7.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ff96e8815eecacc6645da76c413eb3b3d34cfca256c70b16b286a687d013c32", size = 254903, upload-time = "2025-10-06T14:50:05.98Z" }, + { url = "https://files.pythonhosted.org/packages/06/c9/11ea263ad0df7dfabcad404feb3c0dd40b131bc7f232d5537f2fb1356951/multidict-6.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7516c579652f6a6be0e266aec0acd0db80829ca305c3d771ed898538804c2036", size = 252365, upload-time = "2025-10-06T14:50:07.511Z" }, + { url = "https://files.pythonhosted.org/packages/41/88/d714b86ee2c17d6e09850c70c9d310abac3d808ab49dfa16b43aba9d53fd/multidict-6.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:040f393368e63fb0f3330e70c26bfd336656bed925e5cbe17c9da839a6ab13ec", size = 250062, upload-time = "2025-10-06T14:50:09.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/fe/ad407bb9e818c2b31383f6131ca19ea7e35ce93cf1310fce69f12e89de75/multidict-6.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b3bc26a951007b1057a1c543af845f1c7e3e71cc240ed1ace7bf4484aa99196e", size = 249683, upload-time = "2025-10-06T14:50:10.714Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/a89abdb0229e533fb925e7c6e5c40201c2873efebc9abaf14046a4536ee6/multidict-6.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7b022717c748dd1992a83e219587aabe45980d88969f01b316e78683e6285f64", size = 261254, upload-time = "2025-10-06T14:50:12.28Z" }, + { url = "https://files.pythonhosted.org/packages/8d/aa/0e2b27bd88b40a4fb8dc53dd74eecac70edaa4c1dd0707eb2164da3675b3/multidict-6.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9600082733859f00d79dee64effc7aef1beb26adb297416a4ad2116fd61374bd", size = 257967, upload-time = "2025-10-06T14:50:14.16Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/0c67b7120d5d5f6d874ed85a085f9dc770a7f9d8813e80f44a9fec820bb7/multidict-6.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94218fcec4d72bc61df51c198d098ce2b378e0ccbac41ddbed5ef44092913288", size = 250085, upload-time = "2025-10-06T14:50:15.639Z" }, + { url = "https://files.pythonhosted.org/packages/ba/55/b73e1d624ea4b8fd4dd07a3bb70f6e4c7c6c5d9d640a41c6ffe5cdbd2a55/multidict-6.7.0-cp313-cp313-win32.whl", hash = "sha256:a37bd74c3fa9d00be2d7b8eca074dc56bd8077ddd2917a839bd989612671ed17", size = 41713, upload-time = "2025-10-06T14:50:17.066Z" }, + { url = "https://files.pythonhosted.org/packages/32/31/75c59e7d3b4205075b4c183fa4ca398a2daf2303ddf616b04ae6ef55cffe/multidict-6.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:30d193c6cc6d559db42b6bcec8a5d395d34d60c9877a0b71ecd7c204fcf15390", size = 45915, upload-time = "2025-10-06T14:50:18.264Z" }, + { url = "https://files.pythonhosted.org/packages/31/2a/8987831e811f1184c22bc2e45844934385363ee61c0a2dcfa8f71b87e608/multidict-6.7.0-cp313-cp313-win_arm64.whl", hash = "sha256:ea3334cabe4d41b7ccd01e4d349828678794edbc2d3ae97fc162a3312095092e", size = 43077, upload-time = "2025-10-06T14:50:19.853Z" }, + { url = "https://files.pythonhosted.org/packages/e8/68/7b3a5170a382a340147337b300b9eb25a9ddb573bcdfff19c0fa3f31ffba/multidict-6.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ad9ce259f50abd98a1ca0aa6e490b58c316a0fce0617f609723e40804add2c00", size = 83114, upload-time = "2025-10-06T14:50:21.223Z" }, + { url = "https://files.pythonhosted.org/packages/55/5c/3fa2d07c84df4e302060f555bbf539310980362236ad49f50eeb0a1c1eb9/multidict-6.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07f5594ac6d084cbb5de2df218d78baf55ef150b91f0ff8a21cc7a2e3a5a58eb", size = 48442, upload-time = "2025-10-06T14:50:22.871Z" }, + { url = "https://files.pythonhosted.org/packages/fc/56/67212d33239797f9bd91962bb899d72bb0f4c35a8652dcdb8ed049bef878/multidict-6.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0591b48acf279821a579282444814a2d8d0af624ae0bc600aa4d1b920b6e924b", size = 46885, upload-time = "2025-10-06T14:50:24.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/d1/908f896224290350721597a61a69cd19b89ad8ee0ae1f38b3f5cd12ea2ac/multidict-6.7.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:749a72584761531d2b9467cfbdfd29487ee21124c304c4b6cb760d8777b27f9c", size = 242588, upload-time = "2025-10-06T14:50:25.716Z" }, + { url = "https://files.pythonhosted.org/packages/ab/67/8604288bbd68680eee0ab568fdcb56171d8b23a01bcd5cb0c8fedf6e5d99/multidict-6.7.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b4c3d199f953acd5b446bf7c0de1fe25d94e09e79086f8dc2f48a11a129cdf1", size = 249966, upload-time = "2025-10-06T14:50:28.192Z" }, + { url = "https://files.pythonhosted.org/packages/20/33/9228d76339f1ba51e3efef7da3ebd91964d3006217aae13211653193c3ff/multidict-6.7.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9fb0211dfc3b51efea2f349ec92c114d7754dd62c01f81c3e32b765b70c45c9b", size = 228618, upload-time = "2025-10-06T14:50:29.82Z" }, + { url = "https://files.pythonhosted.org/packages/f8/2d/25d9b566d10cab1c42b3b9e5b11ef79c9111eaf4463b8c257a3bd89e0ead/multidict-6.7.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a027ec240fe73a8d6281872690b988eed307cd7d91b23998ff35ff577ca688b5", size = 257539, upload-time = "2025-10-06T14:50:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b1/8d1a965e6637fc33de3c0d8f414485c2b7e4af00f42cab3d84e7b955c222/multidict-6.7.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1d964afecdf3a8288789df2f5751dc0a8261138c3768d9af117ed384e538fad", size = 256345, upload-time = "2025-10-06T14:50:33.26Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/06b5a8adbdeedada6f4fb8d8f193d44a347223b11939b42953eeb6530b6b/multidict-6.7.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caf53b15b1b7df9fbd0709aa01409000a2b4dd03a5f6f5cc548183c7c8f8b63c", size = 247934, upload-time = "2025-10-06T14:50:34.808Z" }, + { url = "https://files.pythonhosted.org/packages/8f/31/b2491b5fe167ca044c6eb4b8f2c9f3b8a00b24c432c365358eadac5d7625/multidict-6.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:654030da3197d927f05a536a66186070e98765aa5142794c9904555d3a9d8fb5", size = 245243, upload-time = "2025-10-06T14:50:36.436Z" }, + { url = "https://files.pythonhosted.org/packages/61/1a/982913957cb90406c8c94f53001abd9eafc271cb3e70ff6371590bec478e/multidict-6.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:2090d3718829d1e484706a2f525e50c892237b2bf9b17a79b059cb98cddc2f10", size = 235878, upload-time = "2025-10-06T14:50:37.953Z" }, + { url = "https://files.pythonhosted.org/packages/be/c0/21435d804c1a1cf7a2608593f4d19bca5bcbd7a81a70b253fdd1c12af9c0/multidict-6.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d2cfeec3f6f45651b3d408c4acec0ebf3daa9bc8a112a084206f5db5d05b754", size = 243452, upload-time = "2025-10-06T14:50:39.574Z" }, + { url = "https://files.pythonhosted.org/packages/54/0a/4349d540d4a883863191be6eb9a928846d4ec0ea007d3dcd36323bb058ac/multidict-6.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ef089f985b8c194d341eb2c24ae6e7408c9a0e2e5658699c92f497437d88c3c", size = 252312, upload-time = "2025-10-06T14:50:41.612Z" }, + { url = "https://files.pythonhosted.org/packages/26/64/d5416038dbda1488daf16b676e4dbfd9674dde10a0cc8f4fc2b502d8125d/multidict-6.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e93a0617cd16998784bf4414c7e40f17a35d2350e5c6f0bd900d3a8e02bd3762", size = 246935, upload-time = "2025-10-06T14:50:43.972Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8c/8290c50d14e49f35e0bd4abc25e1bc7711149ca9588ab7d04f886cdf03d9/multidict-6.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f0feece2ef8ebc42ed9e2e8c78fc4aa3cf455733b507c09ef7406364c94376c6", size = 243385, upload-time = "2025-10-06T14:50:45.648Z" }, + { url = "https://files.pythonhosted.org/packages/ef/a0/f83ae75e42d694b3fbad3e047670e511c138be747bc713cf1b10d5096416/multidict-6.7.0-cp313-cp313t-win32.whl", hash = "sha256:19a1d55338ec1be74ef62440ca9e04a2f001a04d0cc49a4983dc320ff0f3212d", size = 47777, upload-time = "2025-10-06T14:50:47.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/80/9b174a92814a3830b7357307a792300f42c9e94664b01dee8e457551fa66/multidict-6.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3da4fb467498df97e986af166b12d01f05d2e04f978a9c1c680ea1988e0bc4b6", size = 53104, upload-time = "2025-10-06T14:50:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/cc/28/04baeaf0428d95bb7a7bea0e691ba2f31394338ba424fb0679a9ed0f4c09/multidict-6.7.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b4121773c49a0776461f4a904cdf6264c88e42218aaa8407e803ca8025872792", size = 45503, upload-time = "2025-10-06T14:50:50.16Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b1/3da6934455dd4b261d4c72f897e3a5728eba81db59959f3a639245891baa/multidict-6.7.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3bab1e4aff7adaa34410f93b1f8e57c4b36b9af0426a76003f441ee1d3c7e842", size = 75128, upload-time = "2025-10-06T14:50:51.92Z" }, + { url = "https://files.pythonhosted.org/packages/14/2c/f069cab5b51d175a1a2cb4ccdf7a2c2dabd58aa5bd933fa036a8d15e2404/multidict-6.7.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b8512bac933afc3e45fb2b18da8e59b78d4f408399a960339598374d4ae3b56b", size = 44410, upload-time = "2025-10-06T14:50:53.275Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/64bb41266427af6642b6b128e8774ed84c11b80a90702c13ac0a86bb10cc/multidict-6.7.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:79dcf9e477bc65414ebfea98ffd013cb39552b5ecd62908752e0e413d6d06e38", size = 43205, upload-time = "2025-10-06T14:50:54.911Z" }, + { url = "https://files.pythonhosted.org/packages/02/68/6b086fef8a3f1a8541b9236c594f0c9245617c29841f2e0395d979485cde/multidict-6.7.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:31bae522710064b5cbeddaf2e9f32b1abab70ac6ac91d42572502299e9953128", size = 245084, upload-time = "2025-10-06T14:50:56.369Z" }, + { url = "https://files.pythonhosted.org/packages/15/ee/f524093232007cd7a75c1d132df70f235cfd590a7c9eaccd7ff422ef4ae8/multidict-6.7.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a0df7ff02397bb63e2fd22af2c87dfa39e8c7f12947bc524dbdc528282c7e34", size = 252667, upload-time = "2025-10-06T14:50:57.991Z" }, + { url = "https://files.pythonhosted.org/packages/02/a5/eeb3f43ab45878f1895118c3ef157a480db58ede3f248e29b5354139c2c9/multidict-6.7.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a0222514e8e4c514660e182d5156a415c13ef0aabbd71682fc714e327b95e99", size = 233590, upload-time = "2025-10-06T14:50:59.589Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/76d02f8270b97269d7e3dbd45644b1785bda457b474315f8cf999525a193/multidict-6.7.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2397ab4daaf2698eb51a76721e98db21ce4f52339e535725de03ea962b5a3202", size = 264112, upload-time = "2025-10-06T14:51:01.183Z" }, + { url = "https://files.pythonhosted.org/packages/76/0b/c28a70ecb58963847c2a8efe334904cd254812b10e535aefb3bcce513918/multidict-6.7.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8891681594162635948a636c9fe0ff21746aeb3dd5463f6e25d9bea3a8a39ca1", size = 261194, upload-time = "2025-10-06T14:51:02.794Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/2ab26e4209773223159b83aa32721b4021ffb08102f8ac7d689c943fded1/multidict-6.7.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18706cc31dbf402a7945916dd5cddf160251b6dab8a2c5f3d6d5a55949f676b3", size = 248510, upload-time = "2025-10-06T14:51:04.724Z" }, + { url = "https://files.pythonhosted.org/packages/93/cd/06c1fa8282af1d1c46fd55c10a7930af652afdce43999501d4d68664170c/multidict-6.7.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f844a1bbf1d207dd311a56f383f7eda2d0e134921d45751842d8235e7778965d", size = 248395, upload-time = "2025-10-06T14:51:06.306Z" }, + { url = "https://files.pythonhosted.org/packages/99/ac/82cb419dd6b04ccf9e7e61befc00c77614fc8134362488b553402ecd55ce/multidict-6.7.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4393e3581e84e5645506923816b9cc81f5609a778c7e7534054091acc64d1c6", size = 239520, upload-time = "2025-10-06T14:51:08.091Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f3/a0f9bf09493421bd8716a362e0cd1d244f5a6550f5beffdd6b47e885b331/multidict-6.7.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:fbd18dc82d7bf274b37aa48d664534330af744e03bccf696d6f4c6042e7d19e7", size = 245479, upload-time = "2025-10-06T14:51:10.365Z" }, + { url = "https://files.pythonhosted.org/packages/8d/01/476d38fc73a212843f43c852b0eee266b6971f0e28329c2184a8df90c376/multidict-6.7.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b6234e14f9314731ec45c42fc4554b88133ad53a09092cc48a88e771c125dadb", size = 258903, upload-time = "2025-10-06T14:51:12.466Z" }, + { url = "https://files.pythonhosted.org/packages/49/6d/23faeb0868adba613b817d0e69c5f15531b24d462af8012c4f6de4fa8dc3/multidict-6.7.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:08d4379f9744d8f78d98c8673c06e202ffa88296f009c71bbafe8a6bf847d01f", size = 252333, upload-time = "2025-10-06T14:51:14.48Z" }, + { url = "https://files.pythonhosted.org/packages/1e/cc/48d02ac22b30fa247f7dad82866e4b1015431092f4ba6ebc7e77596e0b18/multidict-6.7.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fe04da3f79387f450fd0061d4dd2e45a72749d31bf634aecc9e27f24fdc4b3f", size = 243411, upload-time = "2025-10-06T14:51:16.072Z" }, + { url = "https://files.pythonhosted.org/packages/4a/03/29a8bf5a18abf1fe34535c88adbdfa88c9fb869b5a3b120692c64abe8284/multidict-6.7.0-cp314-cp314-win32.whl", hash = "sha256:fbafe31d191dfa7c4c51f7a6149c9fb7e914dcf9ffead27dcfd9f1ae382b3885", size = 40940, upload-time = "2025-10-06T14:51:17.544Z" }, + { url = "https://files.pythonhosted.org/packages/82/16/7ed27b680791b939de138f906d5cf2b4657b0d45ca6f5dd6236fdddafb1a/multidict-6.7.0-cp314-cp314-win_amd64.whl", hash = "sha256:2f67396ec0310764b9222a1728ced1ab638f61aadc6226f17a71dd9324f9a99c", size = 45087, upload-time = "2025-10-06T14:51:18.875Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3c/e3e62eb35a1950292fe39315d3c89941e30a9d07d5d2df42965ab041da43/multidict-6.7.0-cp314-cp314-win_arm64.whl", hash = "sha256:ba672b26069957ee369cfa7fc180dde1fc6f176eaf1e6beaf61fbebbd3d9c000", size = 42368, upload-time = "2025-10-06T14:51:20.225Z" }, + { url = "https://files.pythonhosted.org/packages/8b/40/cd499bd0dbc5f1136726db3153042a735fffd0d77268e2ee20d5f33c010f/multidict-6.7.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:c1dcc7524066fa918c6a27d61444d4ee7900ec635779058571f70d042d86ed63", size = 82326, upload-time = "2025-10-06T14:51:21.588Z" }, + { url = "https://files.pythonhosted.org/packages/13/8a/18e031eca251c8df76daf0288e6790561806e439f5ce99a170b4af30676b/multidict-6.7.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:27e0b36c2d388dc7b6ced3406671b401e84ad7eb0656b8f3a2f46ed0ce483718", size = 48065, upload-time = "2025-10-06T14:51:22.93Z" }, + { url = "https://files.pythonhosted.org/packages/40/71/5e6701277470a87d234e433fb0a3a7deaf3bcd92566e421e7ae9776319de/multidict-6.7.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2a7baa46a22e77f0988e3b23d4ede5513ebec1929e34ee9495be535662c0dfe2", size = 46475, upload-time = "2025-10-06T14:51:24.352Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6a/bab00cbab6d9cfb57afe1663318f72ec28289ea03fd4e8236bb78429893a/multidict-6.7.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bf77f54997a9166a2f5675d1201520586439424c2511723a7312bdb4bcc034e", size = 239324, upload-time = "2025-10-06T14:51:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5f/8de95f629fc22a7769ade8b41028e3e5a822c1f8904f618d175945a81ad3/multidict-6.7.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e011555abada53f1578d63389610ac8a5400fc70ce71156b0aa30d326f1a5064", size = 246877, upload-time = "2025-10-06T14:51:27.604Z" }, + { url = "https://files.pythonhosted.org/packages/23/b4/38881a960458f25b89e9f4a4fdcb02ac101cfa710190db6e5528841e67de/multidict-6.7.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:28b37063541b897fd6a318007373930a75ca6d6ac7c940dbe14731ffdd8d498e", size = 225824, upload-time = "2025-10-06T14:51:29.664Z" }, + { url = "https://files.pythonhosted.org/packages/1e/39/6566210c83f8a261575f18e7144736059f0c460b362e96e9cf797a24b8e7/multidict-6.7.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05047ada7a2fde2631a0ed706f1fd68b169a681dfe5e4cf0f8e4cb6618bbc2cd", size = 253558, upload-time = "2025-10-06T14:51:31.684Z" }, + { url = "https://files.pythonhosted.org/packages/00/a3/67f18315100f64c269f46e6c0319fa87ba68f0f64f2b8e7fd7c72b913a0b/multidict-6.7.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:716133f7d1d946a4e1b91b1756b23c088881e70ff180c24e864c26192ad7534a", size = 252339, upload-time = "2025-10-06T14:51:33.699Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2a/1cb77266afee2458d82f50da41beba02159b1d6b1f7973afc9a1cad1499b/multidict-6.7.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1bed1b467ef657f2a0ae62844a607909ef1c6889562de5e1d505f74457d0b96", size = 244895, upload-time = "2025-10-06T14:51:36.189Z" }, + { url = "https://files.pythonhosted.org/packages/dd/72/09fa7dd487f119b2eb9524946ddd36e2067c08510576d43ff68469563b3b/multidict-6.7.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ca43bdfa5d37bd6aee89d85e1d0831fb86e25541be7e9d376ead1b28974f8e5e", size = 241862, upload-time = "2025-10-06T14:51:41.291Z" }, + { url = "https://files.pythonhosted.org/packages/65/92/bc1f8bd0853d8669300f732c801974dfc3702c3eeadae2f60cef54dc69d7/multidict-6.7.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:44b546bd3eb645fd26fb949e43c02a25a2e632e2ca21a35e2e132c8105dc8599", size = 232376, upload-time = "2025-10-06T14:51:43.55Z" }, + { url = "https://files.pythonhosted.org/packages/09/86/ac39399e5cb9d0c2ac8ef6e10a768e4d3bc933ac808d49c41f9dc23337eb/multidict-6.7.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a6ef16328011d3f468e7ebc326f24c1445f001ca1dec335b2f8e66bed3006394", size = 240272, upload-time = "2025-10-06T14:51:45.265Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b6/fed5ac6b8563ec72df6cb1ea8dac6d17f0a4a1f65045f66b6d3bf1497c02/multidict-6.7.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5aa873cbc8e593d361ae65c68f85faadd755c3295ea2c12040ee146802f23b38", size = 248774, upload-time = "2025-10-06T14:51:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8d/b954d8c0dc132b68f760aefd45870978deec6818897389dace00fcde32ff/multidict-6.7.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3d7b6ccce016e29df4b7ca819659f516f0bc7a4b3efa3bb2012ba06431b044f9", size = 242731, upload-time = "2025-10-06T14:51:48.541Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/a2dac7009125d3540c2f54e194829ea18ac53716c61b655d8ed300120b0f/multidict-6.7.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:171b73bd4ee683d307599b66793ac80981b06f069b62eea1c9e29c9241aa66b0", size = 240193, upload-time = "2025-10-06T14:51:50.355Z" }, + { url = "https://files.pythonhosted.org/packages/39/ca/c05f144128ea232ae2178b008d5011d4e2cea86e4ee8c85c2631b1b94802/multidict-6.7.0-cp314-cp314t-win32.whl", hash = "sha256:b2d7f80c4e1fd010b07cb26820aae86b7e73b681ee4889684fb8d2d4537aab13", size = 48023, upload-time = "2025-10-06T14:51:51.883Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8f/0a60e501584145588be1af5cc829265701ba3c35a64aec8e07cbb71d39bb/multidict-6.7.0-cp314-cp314t-win_amd64.whl", hash = "sha256:09929cab6fcb68122776d575e03c6cc64ee0b8fca48d17e135474b042ce515cd", size = 53507, upload-time = "2025-10-06T14:51:53.672Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ae/3148b988a9c6239903e786eac19c889fab607c31d6efa7fb2147e5680f23/multidict-6.7.0-cp314-cp314t-win_arm64.whl", hash = "sha256:cc41db090ed742f32bd2d2c721861725e6109681eddf835d0a82bd3a5c382827", size = 44804, upload-time = "2025-10-06T14:51:55.415Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +] + [[package]] name = "myst-nb" version = "1.3.0" @@ -1704,8 +2241,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "ipykernel" }, - { name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "ipython", version = "9.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "ipython" }, { name = "jupyter-cache" }, { name = "myst-parser" }, { name = "nbclient" }, @@ -2062,6 +2598,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/4e/0d0c945463719429b7bd21dece907ad0bde437a2ff12b9b12fee94722ab0/nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6574241a3ec5fdc9334353ab8c479fe75841dbe8f4532a8fc97ce63503330ba1", size = 89265, upload-time = "2024-10-01T17:00:38.172Z" }, ] +[[package]] +name = "opencensus" +version = "0.11.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "opencensus-context" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/15/a7/a46dcffa1b63084f9f17fe3c8cb20724c4c8f91009fd0b2cfdb27d5d2b35/opencensus-0.11.4.tar.gz", hash = "sha256:cbef87d8b8773064ab60e5c2a1ced58bbaa38a6d052c41aec224958ce544eff2", size = 64966, upload-time = "2024-01-03T18:04:07.085Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/ed/9fbdeb23a09e430d87b7d72d430484b88184633dc50f6bfb792354b6f661/opencensus-0.11.4-py2.py3-none-any.whl", hash = "sha256:a18487ce68bc19900336e0ff4655c5a116daf10c1b3685ece8d971bddad6a864", size = 128225, upload-time = "2024-01-03T18:04:05.127Z" }, +] + +[[package]] +name = "opencensus-context" +version = "0.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/96/3b6f638f6275a8abbd45e582448723bffa29c1fb426721dedb5c72f7d056/opencensus-context-0.1.3.tar.gz", hash = "sha256:a03108c3c10d8c80bb5ddf5c8a1f033161fa61972a9917f9b9b3a18517f0088c", size = 4066, upload-time = "2022-08-03T22:20:22.359Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/68/162c97ea78c957d68ecf78a5c5041d2e25bd5562bdf5d89a6cbf7f8429bf/opencensus_context-0.1.3-py2.py3-none-any.whl", hash = "sha256:073bb0590007af276853009fac7e4bab1d523c3f03baf4cb4511ca38967c6039", size = 5060, upload-time = "2022-08-03T22:20:20.352Z" }, +] + [[package]] name = "openqasm3" version = "1.0.1" @@ -2076,6 +2635,141 @@ parser = [ { name = "antlr4-python3-runtime" }, ] +[[package]] +name = "opentelemetry-api" +version = "1.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deprecated" }, + { name = "importlib-metadata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/ca/920a73b4a11cd271ba1c62f34dba27d7783996a6a7ac0bac7c83b230736d/opentelemetry_api-1.33.0.tar.gz", hash = "sha256:cc4380fd2e6da7dcb52a828ea81844ed1f4f2eb638ca3c816775109d93d58ced", size = 65000, upload-time = "2025-05-09T14:56:00.967Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/c4/26c7ec8e51c19632f42503dbabed286c261fb06f8f61ffd348690e36958a/opentelemetry_api-1.33.0-py3-none-any.whl", hash = "sha256:158df154f628e6615b65fdf6e59f99afabea7213e72c5809dd4adf06c0d997cd", size = 65772, upload-time = "2025-05-09T14:55:38.395Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-proto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/31/70add0d54358ea5007f687b931a1f980e6c977299897cce763e968ffc4a5/opentelemetry_exporter_otlp_proto_common-1.33.0.tar.gz", hash = "sha256:2f43679dab68ce7708db18cb145b59a7e9184d46608ef037c9c22f47c5beb320", size = 20830, upload-time = "2025-05-09T14:56:03.176Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/ee/a8a2a0c965a8ac53d31a3d5b5582de16d27ece4108c152f42adeb11a6455/opentelemetry_exporter_otlp_proto_common-1.33.0-py3-none-any.whl", hash = "sha256:5c282fc752e4ebdf484c6af2f22d0af2048a5685400d59524e8a3dbcee315014", size = 18840, upload-time = "2025-05-09T14:55:42.378Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-grpc" +version = "1.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deprecated" }, + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/86/13350f3a15800b6be90c3e2da98571e1421a50c06384cc2aad06a7266b20/opentelemetry_exporter_otlp_proto_grpc-1.33.0.tar.gz", hash = "sha256:99a2ec88f05ffa36897402820a73178cbc37dc3f9ebe2dbde6209be3303446f4", size = 22555, upload-time = "2025-05-09T14:56:03.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/e5/c37dae2fbc8c2b5d99ab1c6a0196e25df2e3f9980d19140506862ace2dc5/opentelemetry_exporter_otlp_proto_grpc-1.33.0-py3-none-any.whl", hash = "sha256:04b11348a40f4c21958d704083445f9bbd32155e046ba9157133fa1bf864d2f2", size = 18592, upload-time = "2025-05-09T14:55:43.706Z" }, +] + +[[package]] +name = "opentelemetry-exporter-prometheus" +version = "0.54b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-sdk" }, + { name = "prometheus-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/5f/bf13dce00e2300ff4ca7c3d434c52e673b8be2ee44c18968dcf1382558fe/opentelemetry_exporter_prometheus-0.54b0.tar.gz", hash = "sha256:3afe55fafeb1afd183abc8d4f71fb440fa8ac2ae2f04ea375636f4df58464dd7", size = 14950, upload-time = "2025-05-09T14:56:05.476Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/4d/f08543a48af300b768180679fd9365d78f24f790bfb302ca8105af5cbf92/opentelemetry_exporter_prometheus-0.54b0-py3-none-any.whl", hash = "sha256:20ad0fb1ded5fb76d05ee043b6642b2171edfce8b32e8f40b04c9ef4aabf5ffa", size = 12950, upload-time = "2025-05-09T14:55:46.005Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation" +version = "0.54b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "packaging" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2b/00/00ab7ce770c419337e3286c29e59f979a05694aebf15a957bd17d7a0c2cb/opentelemetry_instrumentation-0.54b0.tar.gz", hash = "sha256:2949d0bbf2316eb5d928a5ef610d0a8a2c261ba80167d878abf6016e1c4ae7bb", size = 28434, upload-time = "2025-05-09T14:59:13.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/e9/426f4e5da65e2f8f53e7a8d2551bb56e49776cccf0b99cd99ab6295542cd/opentelemetry_instrumentation-0.54b0-py3-none-any.whl", hash = "sha256:1a502238f8af65625ad48800d268d467653e319d959e1732d3b3248916d21327", size = 31018, upload-time = "2025-05-09T14:58:13.019Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation-requests" +version = "0.54b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "opentelemetry-util-http" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/20/2ef61cc45a44f1d865d0a57c84c65649799d1d22fcb69f78c3133dd8fcba/opentelemetry_instrumentation_requests-0.54b0.tar.gz", hash = "sha256:abc604d58a0da9cbfad2e9439df2b85437ec00bf550753cf64bf6d61e2b98bdd", size = 15148, upload-time = "2025-05-09T14:59:44.091Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/46/0507f3f64683f8cf4aef9483c1b760418f9f17a2480fa970db6225ea42da/opentelemetry_instrumentation_requests-0.54b0-py3-none-any.whl", hash = "sha256:c05324b3a5a047b28cd7bccf1f506d7ebadbfd8faefc2661fe7d40c3218d9a8c", size = 12967, upload-time = "2025-05-09T14:58:58.498Z" }, +] + +[[package]] +name = "opentelemetry-proto" +version = "1.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/55/13a941b5fa0730875f2ef534cca8e09dd00142f4a4e1ab781f9825b212c4/opentelemetry_proto-1.33.0.tar.gz", hash = "sha256:ec5aa35486c990207ead2512a8d616d1b324928562c91dbc7e0cb9aa48c60b7b", size = 34362, upload-time = "2025-05-09T14:56:11.569Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/44/8f4029c09c7d4f275c7ed56af186ebd82af257a879266e9b3965f82ca09d/opentelemetry_proto-1.33.0-py3-none-any.whl", hash = "sha256:84a1d7daacac4aa0f24a5b1190a3e0619011dbff56f945fc2b6fc0a18f48b942", size = 55856, upload-time = "2025-05-09T14:55:55.513Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/0a/b7ae406175a2798a767e12db223e842911d9c398eea100c41c989afd2aa8/opentelemetry_sdk-1.33.0.tar.gz", hash = "sha256:a7fc56d1e07b218fcc316b24d21b59d3f1967b2ca22c217b05da3a26b797cc68", size = 161381, upload-time = "2025-05-09T14:56:12.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/34/831f5d9ae9375c9ba2446cb3cc0be79d8d73b78f813c9567e1615c2624f6/opentelemetry_sdk-1.33.0-py3-none-any.whl", hash = "sha256:bed376b6d37fbf00688bb65edfee817dd01d48b8559212831437529a6066049a", size = 118861, upload-time = "2025-05-09T14:55:56.956Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.54b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deprecated" }, + { name = "opentelemetry-api" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/92/8c/bc970d1599ff40b7913c953a95195addf11c81a27cc85d5ed568e9f8c57f/opentelemetry_semantic_conventions-0.54b0.tar.gz", hash = "sha256:467b739977bdcb079af1af69f73632535cdb51099d5e3c5709a35d10fe02a9c9", size = 118646, upload-time = "2025-05-09T14:56:13.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/aa/f7c46c19aee189e0123ef7209eaafc417e242b2073485dfb40523d6d8612/opentelemetry_semantic_conventions-0.54b0-py3-none-any.whl", hash = "sha256:fad7c1cf8908fd449eb5cf9fbbeefb301acf4bc995101f85277899cec125d823", size = 194937, upload-time = "2025-05-09T14:55:58.562Z" }, +] + +[[package]] +name = "opentelemetry-util-http" +version = "0.54b0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/14/51f18a82e858a06332e56fb523afbd5e5ff2dac5511a8c4ca64d163f15ca/opentelemetry_util_http-0.54b0.tar.gz", hash = "sha256:2b5fe7157928bdbde194d38df7cbd35a679631fe5b6c23b2c4a271229f7e42b5", size = 8041, upload-time = "2025-05-09T14:59:53.905Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/e0/b53c6af5f2a44c301290e7853829e5a3b195d1057a1ff24ab165f18f67ce/opentelemetry_util_http-0.54b0-py3-none-any.whl", hash = "sha256:40598360e08ee7f8ea563f40dee5e30b1c15be54615e11497aaf190930e94250", size = 7302, upload-time = "2025-05-09T14:59:10.374Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -2287,6 +2981,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "prometheus-client" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481, upload-time = "2025-09-18T20:47:25.043Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145, upload-time = "2025-09-18T20:47:23.875Z" }, +] + [[package]] name = "prompt-toolkit" version = "3.0.51" @@ -2299,18 +3002,144 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" }, ] +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "proto-plus" +version = "1.27.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/89/9cbe2f4bba860e149108b683bc2efec21f14d5f7ed6e25562ad86acbc373/proto_plus-1.27.0.tar.gz", hash = "sha256:873af56dd0d7e91836aee871e5799e1c6f1bda86ac9a983e0bb9f0c266a568c4", size = 56158, upload-time = "2025-12-16T13:46:25.729Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/24/3b7a0818484df9c28172857af32c2397b6d8fcd99d9468bd4684f98ebf0a/proto_plus-1.27.0-py3-none-any.whl", hash = "sha256:1baa7f81cf0f8acb8bc1f6d085008ba4171eaf669629d1b6d1673b21ed1c0a82", size = 50205, upload-time = "2025-12-16T13:46:24.76Z" }, +] + [[package]] name = "protobuf" -version = "6.31.1" +version = "5.29.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/f3/b9655a711b32c19720253f6f06326faf90580834e2e83f840472d752bc8b/protobuf-6.31.1.tar.gz", hash = "sha256:d8cac4c982f0b957a4dc73a80e2ea24fab08e679c0de9deb835f4a12d69aca9a", size = 441797, upload-time = "2025-05-28T19:25:54.947Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/6f/6ab8e4bf962fd5570d3deaa2d5c38f0a363f57b4501047b5ebeb83ab1125/protobuf-6.31.1-cp310-abi3-win32.whl", hash = "sha256:7fa17d5a29c2e04b7d90e5e32388b8bfd0e7107cd8e616feef7ed3fa6bdab5c9", size = 423603, upload-time = "2025-05-28T19:25:41.198Z" }, - { url = "https://files.pythonhosted.org/packages/44/3a/b15c4347dd4bf3a1b0ee882f384623e2063bb5cf9fa9d57990a4f7df2fb6/protobuf-6.31.1-cp310-abi3-win_amd64.whl", hash = "sha256:426f59d2964864a1a366254fa703b8632dcec0790d8862d30034d8245e1cd447", size = 435283, upload-time = "2025-05-28T19:25:44.275Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/b9689a2a250264a84e66c46d8862ba788ee7a641cdca39bccf64f59284b7/protobuf-6.31.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:6f1227473dc43d44ed644425268eb7c2e488ae245d51c6866d19fe158e207402", size = 425604, upload-time = "2025-05-28T19:25:45.702Z" }, - { url = "https://files.pythonhosted.org/packages/76/a1/7a5a94032c83375e4fe7e7f56e3976ea6ac90c5e85fac8576409e25c39c3/protobuf-6.31.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:a40fc12b84c154884d7d4c4ebd675d5b3b5283e155f324049ae396b95ddebc39", size = 322115, upload-time = "2025-05-28T19:25:47.128Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b1/b59d405d64d31999244643d88c45c8241c58f17cc887e73bcb90602327f8/protobuf-6.31.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4ee898bf66f7a8b0bd21bce523814e6fbd8c6add948045ce958b73af7e8878c6", size = 321070, upload-time = "2025-05-28T19:25:50.036Z" }, - { url = "https://files.pythonhosted.org/packages/f7/af/ab3c51ab7507a7325e98ffe691d9495ee3d3aa5f589afad65ec920d39821/protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e", size = 168724, upload-time = "2025-05-28T19:25:53.926Z" }, + { url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" }, + { url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" }, + { url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" }, + { url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" }, + { url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" }, + { url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" }, ] [[package]] @@ -2346,6 +3175,84 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] +[[package]] +name = "py-spy" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/e2/ff811a367028b87e86714945bb9ecb5c1cc69114a8039a67b3a862cef921/py_spy-0.4.1.tar.gz", hash = "sha256:e53aa53daa2e47c2eef97dd2455b47bb3a7e7f962796a86cc3e7dbde8e6f4db4", size = 244726, upload-time = "2025-07-31T19:33:25.172Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/e3/3a32500d845bdd94f6a2b4ed6244982f42ec2bc64602ea8fcfe900678ae7/py_spy-0.4.1-py2.py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:809094208c6256c8f4ccadd31e9a513fe2429253f48e20066879239ba12cd8cc", size = 3682508, upload-time = "2025-07-31T19:33:13.753Z" }, + { url = "https://files.pythonhosted.org/packages/4f/bf/e4d280e9e0bec71d39fc646654097027d4bbe8e04af18fb68e49afcff404/py_spy-0.4.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:1fb8bf71ab8df95a95cc387deed6552934c50feef2cf6456bc06692a5508fd0c", size = 1796395, upload-time = "2025-07-31T19:33:15.325Z" }, + { url = "https://files.pythonhosted.org/packages/df/79/9ed50bb0a9de63ed023aa2db8b6265b04a7760d98c61eb54def6a5fddb68/py_spy-0.4.1-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee776b9d512a011d1ad3907ed53ae32ce2f3d9ff3e1782236554e22103b5c084", size = 2034938, upload-time = "2025-07-31T19:33:17.194Z" }, + { url = "https://files.pythonhosted.org/packages/53/a5/36862e3eea59f729dfb70ee6f9e14b051d8ddce1aa7e70e0b81d9fe18536/py_spy-0.4.1-py2.py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:532d3525538254d1859b49de1fbe9744df6b8865657c9f0e444bf36ce3f19226", size = 2658968, upload-time = "2025-07-31T19:33:18.916Z" }, + { url = "https://files.pythonhosted.org/packages/08/f8/9ea0b586b065a623f591e5e7961282ec944b5fbbdca33186c7c0296645b3/py_spy-0.4.1-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4972c21890b6814017e39ac233c22572c4a61fd874524ebc5ccab0f2237aee0a", size = 2147541, upload-time = "2025-07-31T19:33:20.565Z" }, + { url = "https://files.pythonhosted.org/packages/68/fb/bc7f639aed026bca6e7beb1e33f6951e16b7d315594e7635a4f7d21d63f4/py_spy-0.4.1-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6a80ec05eb8a6883863a367c6a4d4f2d57de68466f7956b6367d4edd5c61bb29", size = 2763338, upload-time = "2025-07-31T19:33:22.202Z" }, + { url = "https://files.pythonhosted.org/packages/e1/da/fcc9a9fcd4ca946ff402cff20348e838b051d69f50f5d1f5dca4cd3c5eb8/py_spy-0.4.1-py2.py3-none-win_amd64.whl", hash = "sha256:d92e522bd40e9bf7d87c204033ce5bb5c828fca45fa28d970f58d71128069fdc", size = 1818784, upload-time = "2025-07-31T19:33:23.802Z" }, +] + +[[package]] +name = "pyarrow" +version = "18.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/7b/640785a9062bb00314caa8a387abce547d2a420cf09bd6c715fe659ccffb/pyarrow-18.1.0.tar.gz", hash = "sha256:9386d3ca9c145b5539a1cfc75df07757dff870168c959b473a0bccbc3abc8c73", size = 1118671, upload-time = "2024-11-26T02:01:48.62Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/bb/8d4a1573f66e0684f190dd2b55fd0b97a7214de8882d58a3867e777bf640/pyarrow-18.1.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e21488d5cfd3d8b500b3238a6c4b075efabc18f0f6d80b29239737ebd69caa6c", size = 29531620, upload-time = "2024-11-26T01:58:27.03Z" }, + { url = "https://files.pythonhosted.org/packages/30/90/893acfad917533b624a97b9e498c0e8393908508a0a72d624fe935e632bf/pyarrow-18.1.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:b516dad76f258a702f7ca0250885fc93d1fa5ac13ad51258e39d402bd9e2e1e4", size = 30836521, upload-time = "2024-11-26T01:58:34.607Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2a/526545a7464b5fb2fa6e2c4bad16ca90e59e1843025c534fd907b7f73e5a/pyarrow-18.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f443122c8e31f4c9199cb23dca29ab9427cef990f283f80fe15b8e124bcc49b", size = 39213905, upload-time = "2024-11-26T01:58:40.558Z" }, + { url = "https://files.pythonhosted.org/packages/8a/77/4b3fab91a30e19e233e738d0c5eca5a8f6dd05758bc349a2ca262c65de79/pyarrow-18.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a03da7f2758645d17b7b4f83c8bffeae5bbb7f974523fe901f36288d2eab71", size = 40128881, upload-time = "2024-11-26T01:58:45.561Z" }, + { url = "https://files.pythonhosted.org/packages/aa/e2/a88e16c5e45e562449c52305bd3bc2f9d704295322d3434656e7ccac1444/pyarrow-18.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ba17845efe3aa358ec266cf9cc2800fa73038211fb27968bfa88acd09261a470", size = 38627517, upload-time = "2024-11-26T01:58:50.922Z" }, + { url = "https://files.pythonhosted.org/packages/6d/84/8037c20005ccc7b869726465be0957bd9c29cfc88612962030f08292ad06/pyarrow-18.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c35813c11a059056a22a3bef520461310f2f7eea5c8a11ef9de7062a23f8d56", size = 40060187, upload-time = "2024-11-26T01:58:56.848Z" }, + { url = "https://files.pythonhosted.org/packages/2a/38/d6435c723ff73df8ae74626ea778262fbcc2b9b0d1a4f3db915b61711b05/pyarrow-18.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9736ba3c85129d72aefa21b4f3bd715bc4190fe4426715abfff90481e7d00812", size = 25118314, upload-time = "2024-11-26T01:59:02.303Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4d/a4988e7d82f4fbc797715db4185939a658eeffb07a25bab7262bed1ea076/pyarrow-18.1.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:eaeabf638408de2772ce3d7793b2668d4bb93807deed1725413b70e3156a7854", size = 29554860, upload-time = "2024-11-26T01:59:06.94Z" }, + { url = "https://files.pythonhosted.org/packages/59/03/3a42c5c1e4bd4c900ab62aa1ff6b472bdb159ba8f1c3e5deadab7222244f/pyarrow-18.1.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:3b2e2239339c538f3464308fd345113f886ad031ef8266c6f004d49769bb074c", size = 30867076, upload-time = "2024-11-26T01:59:11.475Z" }, + { url = "https://files.pythonhosted.org/packages/75/7e/332055ac913373e89256dce9d14b7708f55f7bd5be631456c897f0237738/pyarrow-18.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f39a2e0ed32a0970e4e46c262753417a60c43a3246972cfc2d3eb85aedd01b21", size = 39212135, upload-time = "2024-11-26T01:59:16.045Z" }, + { url = "https://files.pythonhosted.org/packages/8c/64/5099cdb325828722ef7ffeba9a4696f238eb0cdeae227f831c2d77fcf1bd/pyarrow-18.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31e9417ba9c42627574bdbfeada7217ad8a4cbbe45b9d6bdd4b62abbca4c6f6", size = 40125195, upload-time = "2024-11-26T01:59:21.267Z" }, + { url = "https://files.pythonhosted.org/packages/83/88/1938d783727db1b178ff71bc6a6143d7939e406db83a9ec23cad3dad325c/pyarrow-18.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:01c034b576ce0eef554f7c3d8c341714954be9b3f5d5bc7117006b85fcf302fe", size = 38641884, upload-time = "2024-11-26T01:59:26.672Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b5/9e14e9f7590e0eaa435ecea84dabb137284a4dbba7b3c337b58b65b76d95/pyarrow-18.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f266a2c0fc31995a06ebd30bcfdb7f615d7278035ec5b1cd71c48d56daaf30b0", size = 40076877, upload-time = "2024-11-26T01:59:31.926Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a3/817ac7fe0891a2d66e247e223080f3a6a262d8aefd77e11e8c27e6acf4e1/pyarrow-18.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d4f13eee18433f99adefaeb7e01d83b59f73360c231d4782d9ddfaf1c3fbde0a", size = 25119811, upload-time = "2024-11-26T01:59:35.669Z" }, + { url = "https://files.pythonhosted.org/packages/6a/50/12829e7111b932581e51dda51d5cb39207a056c30fe31ef43f14c63c4d7e/pyarrow-18.1.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:9f3a76670b263dc41d0ae877f09124ab96ce10e4e48f3e3e4257273cee61ad0d", size = 29514620, upload-time = "2024-11-26T01:59:39.797Z" }, + { url = "https://files.pythonhosted.org/packages/d1/41/468c944eab157702e96abab3d07b48b8424927d4933541ab43788bb6964d/pyarrow-18.1.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:da31fbca07c435be88a0c321402c4e31a2ba61593ec7473630769de8346b54ee", size = 30856494, upload-time = "2024-11-26T01:59:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/68/f9/29fb659b390312a7345aeb858a9d9c157552a8852522f2c8bad437c29c0a/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:543ad8459bc438efc46d29a759e1079436290bd583141384c6f7a1068ed6f992", size = 39203624, upload-time = "2024-11-26T01:59:49.189Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f6/19360dae44200e35753c5c2889dc478154cd78e61b1f738514c9f131734d/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0743e503c55be0fdb5c08e7d44853da27f19dc854531c0570f9f394ec9671d54", size = 40139341, upload-time = "2024-11-26T01:59:54.849Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e6/9b3afbbcf10cc724312e824af94a2e993d8ace22994d823f5c35324cebf5/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d4b3d2a34780645bed6414e22dda55a92e0fcd1b8a637fba86800ad737057e33", size = 38618629, upload-time = "2024-11-26T01:59:59.966Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2e/3b99f8a3d9e0ccae0e961978a0d0089b25fb46ebbcfb5ebae3cca179a5b3/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c52f81aa6f6575058d8e2c782bf79d4f9fdc89887f16825ec3a66607a5dd8e30", size = 40078661, upload-time = "2024-11-26T02:00:04.55Z" }, + { url = "https://files.pythonhosted.org/packages/76/52/f8da04195000099d394012b8d42c503d7041b79f778d854f410e5f05049a/pyarrow-18.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ad4892617e1a6c7a551cfc827e072a633eaff758fa09f21c4ee548c30bcaf99", size = 25092330, upload-time = "2024-11-26T02:00:09.576Z" }, + { url = "https://files.pythonhosted.org/packages/cb/87/aa4d249732edef6ad88899399047d7e49311a55749d3c373007d034ee471/pyarrow-18.1.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:84e314d22231357d473eabec709d0ba285fa706a72377f9cc8e1cb3c8013813b", size = 29497406, upload-time = "2024-11-26T02:00:14.469Z" }, + { url = "https://files.pythonhosted.org/packages/3c/c7/ed6adb46d93a3177540e228b5ca30d99fc8ea3b13bdb88b6f8b6467e2cb7/pyarrow-18.1.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:f591704ac05dfd0477bb8f8e0bd4b5dc52c1cadf50503858dce3a15db6e46ff2", size = 30835095, upload-time = "2024-11-26T02:00:19.347Z" }, + { url = "https://files.pythonhosted.org/packages/41/d7/ed85001edfb96200ff606943cff71d64f91926ab42828676c0fc0db98963/pyarrow-18.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acb7564204d3c40babf93a05624fc6a8ec1ab1def295c363afc40b0c9e66c191", size = 39194527, upload-time = "2024-11-26T02:00:24.085Z" }, + { url = "https://files.pythonhosted.org/packages/59/16/35e28eab126342fa391593415d79477e89582de411bb95232f28b131a769/pyarrow-18.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74de649d1d2ccb778f7c3afff6085bd5092aed4c23df9feeb45dd6b16f3811aa", size = 40131443, upload-time = "2024-11-26T02:00:29.483Z" }, + { url = "https://files.pythonhosted.org/packages/0c/95/e855880614c8da20f4cd74fa85d7268c725cf0013dc754048593a38896a0/pyarrow-18.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f96bd502cb11abb08efea6dab09c003305161cb6c9eafd432e35e76e7fa9b90c", size = 38608750, upload-time = "2024-11-26T02:00:34.069Z" }, + { url = "https://files.pythonhosted.org/packages/54/9d/f253554b1457d4fdb3831b7bd5f8f00f1795585a606eabf6fec0a58a9c38/pyarrow-18.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:36ac22d7782554754a3b50201b607d553a8d71b78cdf03b33c1125be4b52397c", size = 40066690, upload-time = "2024-11-26T02:00:39.603Z" }, + { url = "https://files.pythonhosted.org/packages/2f/58/8912a2563e6b8273e8aa7b605a345bba5a06204549826f6493065575ebc0/pyarrow-18.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:25dbacab8c5952df0ca6ca0af28f50d45bd31c1ff6fcf79e2d120b4a65ee7181", size = 25081054, upload-time = "2024-11-26T02:00:43.611Z" }, + { url = "https://files.pythonhosted.org/packages/82/f9/d06ddc06cab1ada0c2f2fd205ac8c25c2701182de1b9c4bf7a0a44844431/pyarrow-18.1.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6a276190309aba7bc9d5bd2933230458b3521a4317acfefe69a354f2fe59f2bc", size = 29525542, upload-time = "2024-11-26T02:00:48.094Z" }, + { url = "https://files.pythonhosted.org/packages/ab/94/8917e3b961810587ecbdaa417f8ebac0abb25105ae667b7aa11c05876976/pyarrow-18.1.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:ad514dbfcffe30124ce655d72771ae070f30bf850b48bc4d9d3b25993ee0e386", size = 30829412, upload-time = "2024-11-26T02:00:52.458Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e3/3b16c3190f3d71d3b10f6758d2d5f7779ef008c4fd367cedab3ed178a9f7/pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aebc13a11ed3032d8dd6e7171eb6e86d40d67a5639d96c35142bd568b9299324", size = 39119106, upload-time = "2024-11-26T02:00:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d6/5d704b0d25c3c79532f8c0639f253ec2803b897100f64bcb3f53ced236e5/pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6cf5c05f3cee251d80e98726b5c7cc9f21bab9e9783673bac58e6dfab57ecc8", size = 40090940, upload-time = "2024-11-26T02:01:02.31Z" }, + { url = "https://files.pythonhosted.org/packages/37/29/366bc7e588220d74ec00e497ac6710c2833c9176f0372fe0286929b2d64c/pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:11b676cd410cf162d3f6a70b43fb9e1e40affbc542a1e9ed3681895f2962d3d9", size = 38548177, upload-time = "2024-11-26T02:01:07.371Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/fabf6ecabb1fe5b7d96889228ca2a9158c4c3bb732e3b8ee3f7f6d40b703/pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b76130d835261b38f14fc41fdfb39ad8d672afb84c447126b84d5472244cfaba", size = 40043567, upload-time = "2024-11-26T02:01:12.931Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + [[package]] name = "pybtex" version = "0.25.1" @@ -2796,6 +3703,10 @@ wheels = [ qasm3-import = [ { name = "qiskit-qasm3-import" }, ] +qpy-compat = [ + { name = "symengine" }, + { name = "sympy" }, +] [[package]] name = "qiskit-aer" @@ -2847,27 +3758,35 @@ wheels = [ [[package]] name = "qiskit-ibm-ai-local-transpiler" -version = "0.4.2" +version = "0.5.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jsonschema", marker = "python_full_version < '3.13'" }, - { name = "networkx", marker = "python_full_version < '3.13'" }, - { name = "qiskit", marker = "python_full_version < '3.13'" }, - { name = "qiskit-ibm-runtime", marker = "python_full_version < '3.13'" }, + { name = "jsonschema" }, + { name = "networkx" }, + { name = "qiskit" }, + { name = "qiskit-ibm-runtime" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/2b/d4a31925f23a4614587bd256f1a5b46d53f667971243df2bff62ceb1286e/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6b13b0978b0bb906c1175a63b1c2c00070ed7f3ff9c302d9b8a8e104f5a8ec39", size = 97513406, upload-time = "2025-07-02T15:25:39.934Z" }, - { url = "https://files.pythonhosted.org/packages/54/70/b80685df8b5b957c6e61e44eec9c13f0b72c8a4458734048c5de875d1eb8/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:94a59d360c4470dac7a8467b86cd3787430b917c3d7aa1635279087459168a19", size = 98170843, upload-time = "2025-07-02T15:24:43.794Z" }, - { url = "https://files.pythonhosted.org/packages/10/ec/d62bb53f8dfc16cc908696809f5508b161f8c6709f6be44b410281c4e184/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4933917d137e07a7c889e11c9db30d6f48fc09fe1ecd2e6f856bf451e2e5fba8", size = 97637275, upload-time = "2025-07-02T15:23:20.273Z" }, - { url = "https://files.pythonhosted.org/packages/78/34/807162739e60cbd1f9365d5d00ce583445c4b5ac5e381384c892b69ebf25/qiskit_ibm_ai_local_transpiler-0.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:d4a426b7798a4064487a1d50b0bf019ea1f5eec2a74580aaa2cb945c9b35b385", size = 97416246, upload-time = "2025-07-02T15:23:46.745Z" }, - { url = "https://files.pythonhosted.org/packages/dd/f3/d653647764d13142f028ede9cd772fdb04e73259af622c3207210936d073/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0dd30e5679fb7c2371a11380a3b2c485410a3cb5f23628a94188d50cb4f197ff", size = 97513399, upload-time = "2025-07-02T15:23:59.758Z" }, - { url = "https://files.pythonhosted.org/packages/ba/20/1885c4064bbfd9919e0e03ccff97c3b4afdbeb3bc8effaf9253b5502afc8/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3fa93eb41ad5c14480b726c9737a98017c3a1723326e18c2b2c3c964a6de0b9", size = 98170686, upload-time = "2025-07-02T15:21:48.295Z" }, - { url = "https://files.pythonhosted.org/packages/58/c4/072723658abfd11169a63462396e8765b09f5a204a8d9401ad44da0e5004/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8703192d174ef0f71272bb50fe74b5612690cd9ee9e933a3346567327a04e8eb", size = 97636848, upload-time = "2025-07-02T15:23:38.279Z" }, - { url = "https://files.pythonhosted.org/packages/ae/01/4b4dc70144d08e0694d3a92aa0c7486a9dbb48f8442a7ada92d14f1bdfc7/qiskit_ibm_ai_local_transpiler-0.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:5af2024463e2c34e58e56ead767d6b0f9ee14c3d4d1a01fce3f2ca0230479147", size = 97416835, upload-time = "2025-07-02T15:24:51.17Z" }, - { url = "https://files.pythonhosted.org/packages/31/f7/1e3a0eaf8250ba30a1c0dd4bb9a375d414cf18015cba5d6a85f369de13b9/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7d601b5f508582a6aec4f2fbe04ed50cc52d30e133fc8051178e5558ecaabe13", size = 97512749, upload-time = "2025-07-02T15:27:47.411Z" }, - { url = "https://files.pythonhosted.org/packages/05/fc/df0b6e3a9bdd1690aad940144130f247825fa0710270baba9614805d0071/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d99f87b76c2ae68678afa6f70f8632842a017c1a917774a89de12c9db58f557", size = 98169638, upload-time = "2025-07-02T15:20:13.497Z" }, - { url = "https://files.pythonhosted.org/packages/1c/b4/90a577916747678edcde64dba3a724796ed8cb99915a3e3962f90791ae23/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49da8a583a117b4bc1c51d92a2075718b0cd7e5f000afbc80235e52b2568f70", size = 97636994, upload-time = "2025-07-02T15:23:41.209Z" }, - { url = "https://files.pythonhosted.org/packages/7a/cb/bd0f3995d06c9a2cafa7c49f990dd15e4a2b6860fd43cf6c29d9b9446018/qiskit_ibm_ai_local_transpiler-0.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:aeaa9acacda590f5fd3f668bc16a75f2a515ba6002a1088c617b1b1546076886", size = 97417172, upload-time = "2025-07-02T15:23:07.882Z" }, + { url = "https://files.pythonhosted.org/packages/4a/f8/ca66875254a7d97b139aecf59ee415709acbad48059010a62e4d3e4a2298/qiskit_ibm_ai_local_transpiler-0.5.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:44483902c501253f3ccab414eb9abd0d2f913bb673989b4840788888cec3be5a", size = 97495155, upload-time = "2025-12-01T09:40:35.925Z" }, + { url = "https://files.pythonhosted.org/packages/df/14/49ecf952a537762014fc533423cee8cc79b6584dc6cd507739600ec73322/qiskit_ibm_ai_local_transpiler-0.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:226780d8406b7856a70c81f836e6f7bc6cd3648e3c7f84659009b92e94786c57", size = 98155403, upload-time = "2025-12-01T09:30:18.917Z" }, + { url = "https://files.pythonhosted.org/packages/16/7e/98ebb8b84c225a5e53a352680fdf39ac60784bf3e6299d09be00e1ac18c7/qiskit_ibm_ai_local_transpiler-0.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04721337ad52e2f12ecc762b5f313cfb3b0540b9180c188825b863e9f0c1aec9", size = 97612249, upload-time = "2025-12-01T09:32:06.08Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9d/472d50a23a3bd5a64d88c58e2095d912bae07d93d304074db53ee388fdc3/qiskit_ibm_ai_local_transpiler-0.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:787b5266743131d2c2edebd4ff0289601c1e2836b72b8bbf80bf7f1d90295fe2", size = 97419184, upload-time = "2025-12-01T09:34:00.781Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b5/a7b7ddeca70bb0c042f78c101e4773dc39e3bd8a7315834caac7486b45f0/qiskit_ibm_ai_local_transpiler-0.5.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c87111e92a3a945172086c3ec9687ae610c8dce444dcb30f145dd60683e4f630", size = 97495282, upload-time = "2025-12-01T09:32:01.733Z" }, + { url = "https://files.pythonhosted.org/packages/f3/23/1357320715e57df2c1c6a6eadccec2baeb2716ca910d8350acbcf4a77530/qiskit_ibm_ai_local_transpiler-0.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:01841681bfe33f9c9b32a16f34715d01aa1fb02fe7601af0b621422ab1f0eba0", size = 98155269, upload-time = "2025-12-01T09:33:45.697Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c0/244c5ee9e324a6a6e49c6be612aa79ed4dad3baadb65291bbdf11dbb9ed9/qiskit_ibm_ai_local_transpiler-0.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:360b2cc7cd49c248beaec888d07ef5aa79adc929d3e7e1c7e6e7efa40cd777b0", size = 97611489, upload-time = "2025-12-01T09:32:33.366Z" }, + { url = "https://files.pythonhosted.org/packages/0e/ef/a95076a458a10f0497f6cd19f27c9ee2edb697b82202aaf7205c66b3d2a7/qiskit_ibm_ai_local_transpiler-0.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:6643b17fecbca65c6df23260c1240ca9f12f04b6669c7616dd64ecb3761a7e39", size = 97418884, upload-time = "2025-12-01T09:34:21.721Z" }, + { url = "https://files.pythonhosted.org/packages/c6/14/8d0c54df2803910bbb5fdfae0a1e3c6abbc2ca8c6d8f0d3da90ca7fb2779/qiskit_ibm_ai_local_transpiler-0.5.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ba37c5d7a6238987c569a7d9c5a63c91a802983795fee6690d05f9e238a1e71b", size = 97496543, upload-time = "2025-12-01T09:33:12.579Z" }, + { url = "https://files.pythonhosted.org/packages/6f/8e/c1b7225356b4efe6a6021b81f4c8850fe72f68a2a09de8022a22ac1d4290/qiskit_ibm_ai_local_transpiler-0.5.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ef5ad71fbef8765eec04424c2da6b4ad66de2331d6f472065bfd63f4c5e5db8e", size = 98156400, upload-time = "2025-12-01T09:30:56.165Z" }, + { url = "https://files.pythonhosted.org/packages/bd/eb/bd0a630c15ddff7ed2a6ed14adde6887c2480c4b7f352bffddba3775919d/qiskit_ibm_ai_local_transpiler-0.5.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5d3f4d08e1e19b3e04dcc7da05afe4f85dacf60334eea74e92298b1b513b22c", size = 97609910, upload-time = "2025-12-01T09:32:02.061Z" }, + { url = "https://files.pythonhosted.org/packages/17/d7/d00f7480e07465d3e7a89d8e915a9a77f07745ef681d16480a837e626b9d/qiskit_ibm_ai_local_transpiler-0.5.5-cp312-cp312-win_amd64.whl", hash = "sha256:6e676a7957ac7238d5dafd77485367b85f2646971577ca19dfc3aa1c472a915c", size = 97416763, upload-time = "2025-12-01T09:33:52.582Z" }, + { url = "https://files.pythonhosted.org/packages/62/b5/a70c533f4868829ac2e9d59acafb7ce6d9bb1d4f5fe111ba4b7c20e2cdc7/qiskit_ibm_ai_local_transpiler-0.5.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:46b7bcd67c3c246e3582b9d5f745389d2fffba38ee6a1958efd943589698ed4f", size = 97497225, upload-time = "2025-12-01T09:32:49.27Z" }, + { url = "https://files.pythonhosted.org/packages/f9/98/57fc89b55c83283e63ef665fc9419ec37f2c662999f1bfa2a30e25be0322/qiskit_ibm_ai_local_transpiler-0.5.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5a18edc3066dd0906e80f8e0f91b97b32dd5963d329ccf3afb354acd70b63fd6", size = 98156658, upload-time = "2025-12-01T09:36:13.65Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d7/720078b851286a13ff5e0ea84cab5719aa0bcbad1b0eb3e51b59f685e8e4/qiskit_ibm_ai_local_transpiler-0.5.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c38956831ccaaa964e101ce6f499dfc66a88d48b9190e6aac85bd2647dbda3a", size = 97610386, upload-time = "2025-12-01T09:32:06.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/cf/7d0c37a8451b05594e5fe5b5462812b40f4a1f898b729252ab342db7e422/qiskit_ibm_ai_local_transpiler-0.5.5-cp313-cp313-win_amd64.whl", hash = "sha256:44c7fd72b6102174b2b3a0abe92544cfdd997bb21d3a776ed1dc98b39c25cf7c", size = 97417004, upload-time = "2025-12-01T09:34:18.338Z" }, + { url = "https://files.pythonhosted.org/packages/01/5b/89ff08909c46eb2d35662c201189ab1433e26999ec6a9e62297c68ae09d8/qiskit_ibm_ai_local_transpiler-0.5.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e51fecee5abb2b7fc4ff77d0a67420fd563dc1f9a383ab26721fd75f0f0daf23", size = 97497915, upload-time = "2025-12-01T09:40:27.455Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a0/a10873b97316462911b7349e3ea843c0160e9f7c2a72afca9c38690ea05a/qiskit_ibm_ai_local_transpiler-0.5.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cb0afb2781ce4483931fc4047b9408f09a1af37e417b92a1237ec3bf96ef8ecd", size = 98158297, upload-time = "2025-12-01T09:34:33.824Z" }, + { url = "https://files.pythonhosted.org/packages/36/14/f404bebcbe8e439f475df8f274e13c2df9b54fabe96bfa09e2946ad43581/qiskit_ibm_ai_local_transpiler-0.5.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b55c8f401a61816c82073bce5a000b56562696b574e38d82491578a844cda25", size = 97610225, upload-time = "2025-12-01T09:32:09.393Z" }, + { url = "https://files.pythonhosted.org/packages/bf/47/e909a70b0f891a3b5ba600409334e5f88dba8a7503a5230b1916d2837ac2/qiskit_ibm_ai_local_transpiler-0.5.5-cp314-cp314-win_amd64.whl", hash = "sha256:381737a81a6e04cd18eae0cfc6ef27f1cc7ce2cd1404658e9a615578bca0cb92", size = 97416036, upload-time = "2025-12-01T09:34:27.992Z" }, ] [[package]] @@ -2893,18 +3812,20 @@ wheels = [ [[package]] name = "qiskit-ibm-transpiler" -version = "0.13.1" +version = "0.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "backoff", marker = "python_full_version < '3.13'" }, - { name = "networkx", marker = "python_full_version < '3.13'" }, - { name = "qiskit", marker = "python_full_version < '3.13'" }, - { name = "qiskit-qasm3-import", marker = "python_full_version < '3.13'" }, - { name = "requests", marker = "python_full_version < '3.13'" }, + { name = "backoff" }, + { name = "networkx" }, + { name = "qiskit" }, + { name = "qiskit-ibm-ai-local-transpiler" }, + { name = "qiskit-qasm3-import" }, + { name = "qiskit-serverless" }, + { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/ac/d6f176107a0a07aeae583dbde3e7812cd31f670f0d285a0167ece51f040e/qiskit_ibm_transpiler-0.13.1.tar.gz", hash = "sha256:83631565b3adb6ce3825a82af8b6276e3f5e87d193c6efd01b7edae3bf56b31c", size = 46935, upload-time = "2025-07-21T09:42:49.367Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/b2/6871963305c0dcf72e8aedaafd956268a139756ffe9a58a516a425dda0f1/qiskit_ibm_transpiler-0.15.0.tar.gz", hash = "sha256:e7c4105fb4ea147623eb939df7ad2068f76d5817399cfd466874e41407350ab4", size = 45267, upload-time = "2025-12-02T09:17:17.097Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/a4/4127dccc7ecfca71d0df5310ced026790ffd1e8da196fc360011416bcffa/qiskit_ibm_transpiler-0.13.1-py3-none-any.whl", hash = "sha256:5ebd20cf2b6fea77a2cf0263a113bfe37f4e2ac2a836469e4fe714565f886060", size = 61069, upload-time = "2025-07-21T09:42:47.889Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c8/c70678b54cb909608c0f7b4e0f5d3dcd565704e85a0417786f4b4bc0dd71/qiskit_ibm_transpiler-0.15.0-py3-none-any.whl", hash = "sha256:86f5f9b69b237f88e8d2f77f0d278d4826b39f4fca255ddb4a0fdc9d39739364", size = 47121, upload-time = "2025-12-02T09:17:15.648Z" }, ] [[package]] @@ -2920,6 +3841,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3e/7e/b8bbfbf1acfe0b40872727ef4741b54794beb65da34c4c327dc31a73d35d/qiskit_qasm3_import-0.6.0-py3-none-any.whl", hash = "sha256:2109b65a6859bec4a51e7b61bd525365f298f67f19b3952bf602423c6d21d697", size = 29490, upload-time = "2025-06-10T16:34:10.035Z" }, ] +[[package]] +name = "qiskit-serverless" +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "certifi" }, + { name = "cloudpickle" }, + { name = "importlib-metadata" }, + { name = "ipython" }, + { name = "ipywidgets" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or (python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin')" }, + { name = "numpy", version = "2.3.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13' and 'x86_64' not in platform_machine) or (python_full_version >= '3.11' and sys_platform != 'darwin') or (python_full_version >= '3.13' and sys_platform == 'darwin')" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-grpc" }, + { name = "opentelemetry-instrumentation-requests" }, + { name = "opentelemetry-sdk" }, + { name = "pyarrow" }, + { name = "qiskit", extra = ["qpy-compat"] }, + { name = "qiskit-ibm-runtime" }, + { name = "ray", extra = ["default"] }, + { name = "requests" }, + { name = "tqdm" }, + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/8f/2c005581d2779507dc573549d43314fb86343913e57756b0a3c9531afe9c/qiskit_serverless-0.27.1.tar.gz", hash = "sha256:6a7a2f1ddfb792ffc681b3a1cb4aa1219fd7de5252cd2ea4cb5b45e5f58695b3", size = 40156, upload-time = "2025-11-06T19:43:33.624Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/cb/510d5086f9c242051d55b587949c045e618059dc7b09065e52ad14ca1fbc/qiskit_serverless-0.27.1-py3-none-any.whl", hash = "sha256:e0288c4dee4877ed174f74d2b41dd0d8b6666709bcdbba0b868b1c57da8cc856", size = 57958, upload-time = "2025-11-06T19:43:32.261Z" }, +] + [[package]] name = "qwasm" version = "1.0.1" @@ -2932,6 +3883,56 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f5/e9/fbde58bf8dcc05dc9d09dfcd06e631f470aa1e6732870cf06cd34ab86eaf/qwasm-1.0.1-py3-none-any.whl", hash = "sha256:c4c82a3f962d29314634868e06375f0cb4676c3d5266fbe137f6cd67321b0ef1", size = 15322, upload-time = "2022-10-05T09:46:54.856Z" }, ] +[[package]] +name = "ray" +version = "2.52.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "filelock" }, + { name = "jsonschema" }, + { name = "msgpack" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "pyyaml" }, + { name = "requests" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/19/7882c5918d3af848543ad1000b7da22db0f65fa20da8d371272ee24d41ba/ray-2.52.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:993194a8be70540e0f819862031bbf19a64401fbe6c31b42065fd313ba466d34", size = 69385176, upload-time = "2025-11-28T02:22:03.533Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/e42cc912a657211eca9eb0befe71ffc4b6a209d561e9eaed246255c05c4d/ray-2.52.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:65bf461fdfe4ffa667c46f9455f8740b2ad6c1fa471b461d5f5cf6b7baf177b5", size = 71253481, upload-time = "2025-11-28T02:22:09.623Z" }, + { url = "https://files.pythonhosted.org/packages/ee/3e/f180102b73157592ab48a160711771728bbbdc77f6a0510a6a7a2ca18818/ray-2.52.1-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:b3f9e61b799fb3cc8fd7077a3d2eb676ddfef7db644f6b6a2b657c5c3214cf19", size = 72083695, upload-time = "2025-11-28T02:22:15.281Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b4/f6109cb80f8c3057fb5361d0c76249856cda0872ef36220d9b7f600f1253/ray-2.52.1-cp310-cp310-win_amd64.whl", hash = "sha256:24694e60cdc7770b90f123cc578cabb9d1a231c1fe673b5da0027b118de45846", size = 27169182, upload-time = "2025-11-28T02:22:19.866Z" }, + { url = "https://files.pythonhosted.org/packages/8c/64/688d72f53f7adf582913a1bba95ab9fc3232a144057aec6b6f62cc1c76b4/ray-2.52.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f59e3b2d1a1466ac0778f2c6fac9ccb5f30107d77e3dddd1d60167248d268474", size = 69389239, upload-time = "2025-11-28T02:22:24.803Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c6/ae42db4bc9efd221643abad28d0fcdeecc31d49728f07eb27d2b1e4fcebc/ray-2.52.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:2b57ef272a2a0a0dbae6d18d70aa541eab620b4fe3b44d50466d3a533c16f9d9", size = 71373439, upload-time = "2025-11-28T02:22:30.132Z" }, + { url = "https://files.pythonhosted.org/packages/40/5e/b000aa0e8189b37a8f2dfb4f589bb78105e9c451ad75424d4e67f03c5c79/ray-2.52.1-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:a5a3c268d45060c50cd029979ecc5f1eaaec040b19fa88dd4fe9e927d19ff13e", size = 72201688, upload-time = "2025-11-28T02:22:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/0b2e7bf4e1e80c83aaba789de81f346b6fd5f014223873e22f94e2e1c5d4/ray-2.52.1-cp311-cp311-win_amd64.whl", hash = "sha256:4e8478544fef69a17d865431c0bebdcfeff7c0f76a306f29b73c3bc3cbb0bdb9", size = 27163246, upload-time = "2025-11-28T02:22:40.926Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c5/d5c3b6e28dee2bb6f9029dfcb950f41c2e682b1bf4cdbbbe42bde66f2ea8/ray-2.52.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:6831592fedf0a122016f5dab4b67d85fa3d4db3b21f588d18834b5c031396d1c", size = 69374499, upload-time = "2025-11-28T02:22:45.765Z" }, + { url = "https://files.pythonhosted.org/packages/63/9f/a019b66f1d716cfed89edfa6c597c9bffe4eab559042a8495a9c2b2c82ab/ray-2.52.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:08eb8f5fd55292ba6bee363a32491136a5e54af54e007f81e0603986fbea41a4", size = 71412116, upload-time = "2025-11-28T02:22:51.568Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a5/eaea6f080953dfe1506c4d7b7e16a46536b6ebc9f39703683e0c94e115e0/ray-2.52.1-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:843c0108ad72bb7fc6c23a22e29e6099546a5eaad3ad675c78a146d9080f6ec6", size = 72267230, upload-time = "2025-11-28T02:22:56.877Z" }, + { url = "https://files.pythonhosted.org/packages/eb/69/d6cabdd6f3651f380a0cdf90d97b71ec266d6ba06fd2e649e8c878ab08ce/ray-2.52.1-cp312-cp312-win_amd64.whl", hash = "sha256:8045172ad3fcff62b9dab9a4cd2e0991ad0e27fc814fe625a8d3a120306651d6", size = 27144021, upload-time = "2025-11-28T02:23:01.55Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8a/d802270d2871cb3a18cb470f4645eb5cef0deaeda9a4c0d1ac280f2a7424/ray-2.52.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:b5bc29548abb0a0a7ae9e6ff3b0ccca2824edaf011a4336e15a32793d574fbfd", size = 69321286, upload-time = "2025-11-28T02:23:06.263Z" }, + { url = "https://files.pythonhosted.org/packages/7c/35/5f354584dfbc38e0851f9284f905798060d7fca98c9e9da42838296515b7/ray-2.52.1-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e3826aeb4e4399de0c6885bd8be7ce2f629fa0010f0013f1183e0726b3d25e40", size = 71319629, upload-time = "2025-11-28T02:23:11.995Z" }, + { url = "https://files.pythonhosted.org/packages/a0/a0/b5e0099e1b1b3dc2e4c6c78a6630fd97ed2706cd47daba4d7872897cfe86/ray-2.52.1-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:bbe492c780a39a64bd3d0766cad10d54cf12222df88d287ec2d8f2d52de37c79", size = 72181309, upload-time = "2025-11-28T02:23:17.565Z" }, +] + +[package.optional-dependencies] +default = [ + { name = "aiohttp" }, + { name = "aiohttp-cors" }, + { name = "colorful" }, + { name = "grpcio" }, + { name = "opencensus" }, + { name = "opentelemetry-exporter-prometheus" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "prometheus-client" }, + { name = "py-spy" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "smart-open" }, + { name = "virtualenv" }, +] + [[package]] name = "referencing" version = "0.36.2" @@ -3123,6 +4124,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/ed/9de62c2150ca8e2e5858acf3f4f4d0d180a38feef9fdab4078bea63d8dba/rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e99685fc95d386da368013e7fb4269dd39c30d99f812a8372d62f244f662709c", size = 555334, upload-time = "2025-07-01T15:56:51.703Z" }, ] +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + [[package]] name = "rustworkx" version = "0.16.0" @@ -3386,6 +4399,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] +[[package]] +name = "smart-open" +version = "7.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/9a/0a7acb748b86e2922982366d780ca4b16c33f7246fa5860d26005c97e4f3/smart_open-7.5.0.tar.gz", hash = "sha256:f394b143851d8091011832ac8113ea4aba6b92e6c35f6e677ddaaccb169d7cb9", size = 53920, upload-time = "2025-11-08T21:38:40.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/95/bc978be7ea0babf2fb48a414b6afaad414c6a9e8b1eafc5b8a53c030381a/smart_open-7.5.0-py3-none-any.whl", hash = "sha256:87e695c5148bbb988f15cec00971602765874163be85acb1c9fb8abc012e6599", size = 63940, upload-time = "2025-11-08T21:38:39.024Z" }, +] + [[package]] name = "snowballstemmer" version = "3.0.1" @@ -3735,51 +4760,39 @@ wheels = [ [[package]] name = "symengine" -version = "0.14.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/ae/051d3e2ffd128f4a8fa67d380bb7be45637d39e206b4c3737c087a3d4b71/symengine-0.14.1.tar.gz", hash = "sha256:4e9e4b4ec56371c2151803ae0403dab07dd1c74ce88e9abca433bebeb6e2f0f0", size = 938282, upload-time = "2025-04-21T04:03:04.916Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/64/7a9c565d804cc1aafdf4941a2fa3985a6b660ac70ac15080e5112113beeb/symengine-0.14.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0f977360c9993dae163951386ea5b865d8310f323cf11234e62b6535f330d3ac", size = 25935332, upload-time = "2025-04-21T04:00:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/08/9d/deba31c5a38cf26244298ebb63fee5d730638d23b6ab055ecf4988bcf485/symengine-0.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:524249b3224617f91e4e0b81c4134fa496024ddf67b383163586d74683f064a3", size = 22999100, upload-time = "2025-04-21T04:00:46.425Z" }, - { url = "https://files.pythonhosted.org/packages/87/77/13b5faf6b7873df3f2365aa2e43c7dac3e5cb7f037d7d0b60c648132fba9/symengine-0.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f2fb2b9ba7038cba436783a5c1bddc40ba84c7812a4b9c50571fd47ff265038", size = 60837233, upload-time = "2025-04-21T04:00:50.435Z" }, - { url = "https://files.pythonhosted.org/packages/46/cb/9bce97ad8135a32b47e90b3f57084bdc0bb844aa866b3ca0bc88987a2ac4/symengine-0.14.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a010412317d93e37fbee3f4bc04886408653e863997993424e7b9e4d8c85c150", size = 90826835, upload-time = "2025-04-21T04:00:55.849Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8f/3c335e44db300f4d91f7b098661a2add403367833cc27d26dc235520661a/symengine-0.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb14724ab6a6844d04adbd48d7aadcadfe4974193e87eedac93963a6e88bf53", size = 50356243, upload-time = "2025-04-21T04:01:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/d9f33b8a08bdfc07fff733c7f869deb5a0e8c93f5cb95ed4cb9d16294dfb/symengine-0.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:4635fa8855fcadae8c60f27f498388699b7ee88c6be7c3e23564eb0907f6b397", size = 18755307, upload-time = "2025-04-21T04:01:04.187Z" }, - { url = "https://files.pythonhosted.org/packages/65/eb/875243e2856ef203f102cfefe54b81f4a08daed2c7b2ad929e8b82282d93/symengine-0.14.1-cp311-abi3-macosx_10_13_x86_64.whl", hash = "sha256:182d7ca746622764e50af4f926eb9733bd4d1fddb9526faa67bc6ca88b333e23", size = 26038565, upload-time = "2025-09-14T15:23:14.361Z" }, - { url = "https://files.pythonhosted.org/packages/13/85/58acf0f28ae556205044bce9228a4e0e3bb532e0d4a81f3af84e0c45d95b/symengine-0.14.1-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:6fbe25be42ba2040f09d464c06a7812f8e8d04c8087abbad914be561deac2141", size = 23108837, upload-time = "2025-09-14T15:23:17.395Z" }, - { url = "https://files.pythonhosted.org/packages/a2/00/0355f1a261d608b1eaa972071e73070bc415cd1932e90574354e98f46254/symengine-0.14.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:78ac61effb97f63eca70bb4ececb2cb329b09f1d587cfab51768bd3c04543010", size = 61943252, upload-time = "2025-09-14T15:23:21.076Z" }, - { url = "https://files.pythonhosted.org/packages/47/b4/41374adf5f7e60576862e4b4df1519225001fe2f230a3d15c67aa273ea48/symengine-0.14.1-cp311-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5ee52a0aaacafc032dbe5ca57c0b3d87a228e9ef6e88676a4ecc0111fb647b9e", size = 94027577, upload-time = "2025-09-14T15:23:26.165Z" }, - { url = "https://files.pythonhosted.org/packages/52/af/0de548738de262f2288cdefc02df35aaa8c398369643619f59a9c2b5a0b0/symengine-0.14.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577dd78b33f29e7713443588c576013ede4757cb8aedc36bcc405cf85844d7f9", size = 51085045, upload-time = "2025-09-14T15:23:30.185Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d3/fb148c2a2fdefa8f1630f3a0da0170d77ee8e1ac3baf7804504ddc9baacd/symengine-0.14.1-cp311-abi3-win_amd64.whl", hash = "sha256:c1142fd44cc952025185521c1f8a756af8625955f41ad7b947df2b81a14ce7f3", size = 18739305, upload-time = "2025-09-14T15:23:33.031Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f8/689900a258a68b121d7c61a6705b5332969dd95517f9be1d66a4937a17e1/symengine-0.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:43a394acef2355bbcbed089c8f83a7dbdac28f4f979e094b549f571fc411dea6", size = 25992552, upload-time = "2025-04-21T04:01:07.102Z" }, - { url = "https://files.pythonhosted.org/packages/6e/10/82291c78d6dbc17b2e4371559a3945920ecc536ec36b6c8dde28165064f9/symengine-0.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7eb37cd5a9eb0c1c5e35c515139fd1221d937b269aef3569b92c7bb4e251be4", size = 23052876, upload-time = "2025-04-21T04:01:09.679Z" }, - { url = "https://files.pythonhosted.org/packages/30/1a/2199515b7d4f3aa74262e3eb31916a593c4daa7da53bb2c9cbd2cc13fad8/symengine-0.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7657663cfb0d87d66848f7cacda0b2447e127584bc9ec65120e75ce68b21b809", size = 60873086, upload-time = "2025-04-21T04:01:14.285Z" }, - { url = "https://files.pythonhosted.org/packages/07/ce/1e7d9abea217cee8a543ff1fb395b4462e9a4df8072e25b42984e8a6938e/symengine-0.14.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94535da1085a4927364fbb4a8705f7f504897ac53da2cc6d6a8edc897e49c4da", size = 90878511, upload-time = "2025-04-21T04:01:21.764Z" }, - { url = "https://files.pythonhosted.org/packages/6e/23/4bcd98c8a79bc0d584786eb765f33dffca1136fe9b506c6e336d61fad844/symengine-0.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32a29b9462446c9e7f3bf464c7faa847ac2a2d75f0f3fd2f7c0606f9b9384cb", size = 50397966, upload-time = "2025-04-21T04:01:27.732Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/72612eae87f3d0ca58ae4e2207eaee9f8c1dfddc6862a1dc8e2257d67e14/symengine-0.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:f639a488886a066c4d8f19f2a4fd2213de2ea428153d8e1bf425c14f8bc74d57", size = 18803262, upload-time = "2025-04-21T04:01:31.136Z" }, - { url = "https://files.pythonhosted.org/packages/59/ab/3ef6b6385b277511a2e80f5425629af6566c491200ced6ba4a5b33db6b9c/symengine-0.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4c657fba40960dc143d90b20fe49ae769d5c82b323b9dd459f5e3dea4796df8f", size = 25962842, upload-time = "2025-04-21T04:01:34.359Z" }, - { url = "https://files.pythonhosted.org/packages/58/8d/e47e7e9166b4d53cacb0ad722164a6a2bfbb459d62bee105a05998f7b2aa/symengine-0.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9789c62a8ade18f368241525e910dae745fdde1f3b8bb782e5ac8bbfad505e92", size = 23046175, upload-time = "2025-04-21T04:01:37.275Z" }, - { url = "https://files.pythonhosted.org/packages/be/76/6c2227ca8076c238b65341beb3ce4a5bb29174afce3eb9f124b319242693/symengine-0.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcab68fe738a50df3a1b2415f75395c588aab237cb636818332e6cda7ddcf5fb", size = 60719492, upload-time = "2025-04-21T04:01:40.806Z" }, - { url = "https://files.pythonhosted.org/packages/bb/d8/e2dad8babfbb6c8abdb2c443aefca0ae65078c2a0c1f791117a2e659b005/symengine-0.14.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f58a88571a5f7ceca499d7f7834c00d129a55d4c2104a463ba8e3ec24c252e89", size = 90545323, upload-time = "2025-04-21T04:01:46.143Z" }, - { url = "https://files.pythonhosted.org/packages/64/4f/84948cd8384deb43465c14daea81e53159b1c22a2fd55c4f087c47f180df/symengine-0.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a55b8f78541d57a28beda6971bed0a7ddbd585148bb030221f7ca3a0c8e2517", size = 50278629, upload-time = "2025-04-21T04:01:51.673Z" }, - { url = "https://files.pythonhosted.org/packages/d6/7f/4d6b6998a69af3614cc4cb5953acc23b116b35e0596be4dd991397f0cdce/symengine-0.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:5091ce86728022d2c7e0e864ab23070494c1f24fb430ab3437d46806e854651e", size = 18754027, upload-time = "2025-04-21T04:01:55.355Z" }, - { url = "https://files.pythonhosted.org/packages/db/09/c382abfa3e83f11be0ade2ab063f11cc4a3a906b5194f62956856ba766b6/symengine-0.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9859c0c926475dfed666707afba04639a6d46ab48bc463faf50c79b6513de861", size = 25960338, upload-time = "2025-04-21T04:01:57.962Z" }, - { url = "https://files.pythonhosted.org/packages/13/8d/d4b541515b0fa5c390109572d035d397e28ac6f4bd69bee88806b231a65f/symengine-0.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:431545ef66b20efa24e5de9d754ffb184ad9ed29743740c0e9d815c1a1ec37a8", size = 23040715, upload-time = "2025-04-21T04:02:00.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/c7/4ca78ac8df7dacf35bfa77411c317d65adc6add07f58a4d210060b678511/symengine-0.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e69fe8be6e1d1f5209abeb7a8308a074d981b9f1f166086f23f6eed20d861e7f", size = 60716721, upload-time = "2025-04-21T04:02:04.19Z" }, - { url = "https://files.pythonhosted.org/packages/04/92/1d1d9084ccf1749af477273ac952ab68970175a62ef093b32d83dd3efc53/symengine-0.14.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b51617f42213ceb49786b474195d17e7d62e492d0592caa4b404f0e1b1acf58", size = 90546321, upload-time = "2025-04-21T04:02:09.873Z" }, - { url = "https://files.pythonhosted.org/packages/8d/23/922e6fd625ef08c4b703790d3accdcc48e6b340538de25a29ee8b5bebe6c/symengine-0.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e91af61b854e82ae5382e5f91e66d83ac007c0b19b3946f747bc4fc6ca25d66", size = 50277827, upload-time = "2025-04-21T04:02:15.465Z" }, - { url = "https://files.pythonhosted.org/packages/7b/05/29090873cc7b3d23b492a192fa51ada148c80de016db2dc29225230f6499/symengine-0.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:d232d03ceb008d6eb24cb3e1f423af44d3d78cfe09aed801d9fc68ef7b41b611", size = 18753449, upload-time = "2025-04-21T04:02:38.332Z" }, - { url = "https://files.pythonhosted.org/packages/d8/23/0a542b0d3af0b017c129852265aa1a208f152855fd9feb0c1480d846b784/symengine-0.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1324f94852cf2541be29de31899d00bdcab547fea9e9534bcc548062c3f33038", size = 25893789, upload-time = "2025-04-21T04:02:19.407Z" }, - { url = "https://files.pythonhosted.org/packages/e3/38/d22630f658238e33138ceb57b368fd99555472f5e4be561bbc27cf4b134d/symengine-0.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e4b61cb16a559f2e098d52285b27fac4e6ee15194368cef5b78727f71a490bb5", size = 22991458, upload-time = "2025-04-21T04:02:22.396Z" }, - { url = "https://files.pythonhosted.org/packages/be/28/9ae2ee8c3a6e5b35b25a42625de4cd8ef432121dd4ff75bca6809b9e61ac/symengine-0.14.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58f8e1756c9f8cdb7f6cdf189b3752f20cb464f82bf1c7a3873156b12c567896", size = 60604042, upload-time = "2025-04-21T04:02:25.915Z" }, - { url = "https://files.pythonhosted.org/packages/7d/c0/233806912e5515505a058d2527a53117e0e6cd8e59525f1c7cb870805a47/symengine-0.14.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a96f1adfed8cfad62a4f58fe2f32b42718e0938afef0bffeb8131d862ca71a9b", size = 90280432, upload-time = "2025-04-21T04:02:31.02Z" }, - { url = "https://files.pythonhosted.org/packages/bd/93/a6f379c6bd9554efc4cd5475e75fc164d6c44e69d98ddf6553f12a2532aa/symengine-0.14.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c4f500fdd09cbd3cde34a027a964e47b4fc7bfcd5ec8b9a4e654a37036d364b", size = 50183106, upload-time = "2025-04-21T04:02:35.537Z" }, - { url = "https://files.pythonhosted.org/packages/e7/92/31a04faad202197006ad91166a5cb8b513b3238ab4796faabaacece56665/symengine-0.14.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4b85100df4b0e1f6bd2f036539f55961f1e95e77d73fa7beefddbf43359dfda0", size = 26129364, upload-time = "2025-09-14T15:23:35.883Z" }, - { url = "https://files.pythonhosted.org/packages/f7/35/5811158a9a9121f4acc219dd1d1e2c0efec8746d0ddef73890b8348f5e47/symengine-0.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a5938a252c3516f77654689a3e858becc20effce8d34832d1d293ce23ca0d27", size = 23188595, upload-time = "2025-09-14T15:23:38.981Z" }, - { url = "https://files.pythonhosted.org/packages/03/05/c327964f2aeb73a85f5fba80e5357b637794c886389af05718915dd390d8/symengine-0.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:744b01250d15ecdfad63fa7d590a251598794bd977d35d0fab6cb18e8742a493", size = 61923804, upload-time = "2025-09-14T15:23:43.287Z" }, - { url = "https://files.pythonhosted.org/packages/98/f0/f7d488b93081d25a47e974335808cbb6ece96aaaf15abbb72d5d35ee5eab/symengine-0.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:9fd6465d3a797d44e5e4d3b540c4416f18ddccb77768267f0f1e783c44d97bbc", size = 94038098, upload-time = "2025-09-14T15:23:48.45Z" }, - { url = "https://files.pythonhosted.org/packages/22/45/45e84f7f3154d61df6de21b5e38912f9ce91bd7422072a575fe9a3b2ed43/symengine-0.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d1fe80abee5ad6f53bd64c38e25737bb526eff6d24d8428df0f92283e592799", size = 51127881, upload-time = "2025-09-14T15:23:52.894Z" }, - { url = "https://files.pythonhosted.org/packages/ce/30/6b63d1dc9047587cee5cb9d3a4d75041e8173d839eb4c962ad357730a928/symengine-0.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:faf659b9436dcc5ade7f6085d17d42181c18d78ddcaf91de16cd9a412fc77357", size = 18878832, upload-time = "2025-09-14T15:23:55.911Z" }, +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/ff/a2041497a482a0ae585672fe12cc8983c7fc46ce792811b55a067e5e5516/symengine-0.13.0.tar.gz", hash = "sha256:ab83a08897ebf12579702c2b71ba73d4732fb706cc4291d810aedf39c690c14c", size = 114237, upload-time = "2024-09-30T22:06:25.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/ed/964f75a2dc5b0e2c97b732f44dfb9c40fe7c0f5e21a1ecc2edff89db3d81/symengine-0.13.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:259fd4111c7a70c72bdff5686de1949e8132baeb612eacdaf8837720c6fe449b", size = 25867912, upload-time = "2024-09-30T22:03:05.097Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ce/c74dfbaf487a428984644b3cb5e1131c4808f60eab1456f37a107f20b87a/symengine-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44f2eb28a1e36db0bbd6679435412f79da9743bf9c1cb3eff25e0c343b7ddd48", size = 22711016, upload-time = "2024-09-30T22:03:09.144Z" }, + { url = "https://files.pythonhosted.org/packages/4b/65/df699e2b4c2bbf608394b05d1095d77b3f02569e09960f7840f708c7c5dc/symengine-0.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d141712fa14d9138bd19e64b10392f850c68d88cd7db29f1bda33e32d1095559", size = 61000047, upload-time = "2024-09-30T22:03:13.613Z" }, + { url = "https://files.pythonhosted.org/packages/ff/a9/623d97da0da9615367484127dd3b5d1049675832fb9a6a3572f2e072bb86/symengine-0.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:830226d933bfcdb93546e4062541627d9a3bc7a178a63fb16c002eb5c5221938", size = 90017189, upload-time = "2024-09-30T22:03:20.545Z" }, + { url = "https://files.pythonhosted.org/packages/79/a0/d30329ef1bd2b188cb5bbf6d9394e72fa9f38b33a6caa2128ee187716259/symengine-0.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a08090163819a0bbfa97d64bd2d8dac2c5268147ed9c242799d7f7e8728a6f4e", size = 49698796, upload-time = "2024-09-30T22:03:31.169Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e3/cf99b6353b46b8d9ff05e8d7d24764c8afed7c46b888eece99c6e04cc295/symengine-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1e435dcd8ed25e4c7c21ab1c0376be910efc7f35da76d532367df27b359f0358", size = 17830331, upload-time = "2024-09-30T22:03:35.649Z" }, + { url = "https://files.pythonhosted.org/packages/47/a7/e69cff22c2b169b469faa390f0102fbdefe1dfede893a086454483db0fc3/symengine-0.13.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:da0eba7e106095cdce88eb275c8a9d7c4586ad88f229394c53e1184155c00745", size = 25878286, upload-time = "2024-09-30T22:03:39.216Z" }, + { url = "https://files.pythonhosted.org/packages/60/40/bb3faf5a3d4cc99cf5252cc3f4f5267568abd4aae6439374623841cc0025/symengine-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b0c175f4f895a73a925508af03faf7efd6cad8593256bbdb5346bd996d3ec5c8", size = 22721741, upload-time = "2024-09-30T22:03:42.574Z" }, + { url = "https://files.pythonhosted.org/packages/de/da/d6350f60f11abc7ee56fcb6b996deba7b31584b5942a4c5db7d3d4f324dd/symengine-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e58d1e2abd08381aa0cf24c88c0e8b7f592df92619b51e32d36835fbd2dd6ae8", size = 60999516, upload-time = "2024-09-30T22:03:47.206Z" }, + { url = "https://files.pythonhosted.org/packages/d1/ee/db107db7d0557aa8dbc9485741a60dd4f869d3da32180710506f9ba942b9/symengine-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db745f2c7a3c5e83510cf4decb43201f43552dfb05ad8af9787c89708be9ede", size = 90019965, upload-time = "2024-09-30T22:03:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f0/0642f5d9681ff26e57c317d0514315cf1b0dfe1bc8f68ee14a13a270d704/symengine-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2572c98b09ac284db6ecff63f6170461194dc94c4209afd34c092ec67873d85", size = 49690621, upload-time = "2024-09-30T22:03:59.467Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/4300eda41959e3839115b2cb0ddb21818804f5eb129cf92eb9cc55c6efe5/symengine-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:12727f02a2919f005aee48e68e0cbb70cf857b19385857b4d985d1c9b075f620", size = 17831939, upload-time = "2024-09-30T22:04:03.649Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b2/786d3efb98ae1c8e0a9869d6901f24a6633bd621f9e4e1427c86bff35abb/symengine-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cf91d24f1bfd6d53228593c7804dd106b71b19674d5afc4fa322d516e1793bdd", size = 25853458, upload-time = "2024-09-30T22:04:06.435Z" }, + { url = "https://files.pythonhosted.org/packages/3f/74/78b9e7f17c9b9b345d8ef0dbdefebbfc2c7f00693949c6b5808f8a9e54d8/symengine-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5615b7eb68890917abd390ebb10434a949165f6064741c1a8cc345fee14e855", size = 22713256, upload-time = "2024-09-30T22:04:10.002Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a8/69f429946e9a9e63a141dcbe519df8a8c3d56aa75fa8440716871efd8b75/symengine-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb92bdf0890de264abaeacbfbdbd4dd7444b94057bd47958d913b662e549ad8a", size = 60847852, upload-time = "2024-09-30T22:04:14.415Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/a613d5fa73c1b05eb4f0a4bc2bfa21314d37c89dcdb355da684b5f9bea46/symengine-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3bce486fbc0b87970ed1b10ca9d5cafb1fd6b66382fe631261d83592851d7e", size = 89691094, upload-time = "2024-09-30T22:04:21.012Z" }, + { url = "https://files.pythonhosted.org/packages/90/9f/5a171a9edff23eb0e33e0a2dca295a8b25fd64491ebe8cf765e489bd2bcd/symengine-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7e6bae9cfcdde2775d92fbb0abe3ef04e32f65ebc4c2d164ca33f4da202d4a7", size = 49584342, upload-time = "2024-09-30T22:04:28.117Z" }, + { url = "https://files.pythonhosted.org/packages/07/16/a69dffc665e5007a0b4f1500fc401316aa070d109f83bc6887802dce199d/symengine-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:bced0a1dbdb94737c299384c85ddbad6944ce8dadc334f7bb8dbbd8f6c965807", size = 17787218, upload-time = "2024-09-30T22:04:32.066Z" }, + { url = "https://files.pythonhosted.org/packages/f2/51/36ea8d87b61f34d585d09ff585cdc2ba136c501e0a96e861fe81fd0efa5b/symengine-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d34df77971538e4c29f2d8e5ef7f459c2179465e6cdb7dfd48b79b87ecd8f4d", size = 25838153, upload-time = "2024-09-30T22:04:35.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/f7/73cd707633c01760df27d340ac2868788fa0a35034aa09f51f6a289d9a07/symengine-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ab2661d9b18867e7c6edbfa7a74b8b0a2a694bd24aa08003dc3214f77cb9d6f2", size = 22706111, upload-time = "2024-09-30T22:04:38.922Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e7/a1ddc4cc3f2604b18965342523cddd6160b6406d1ef21b58a2dea1c46312/symengine-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53f27b9013878ee4419d8e853664d8ae4b68419e3f4b9b5b7f503d32bf904755", size = 60848269, upload-time = "2024-09-30T22:04:43.816Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f5/b127d236a8ccce8b85cec8bcb0221cbb6a4e651d6f5511da925e10714a4c/symengine-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27987f75ce08c64f453e2b9b74fec6ffc5ca418c4deca0b75580979d4a4e242a", size = 89679345, upload-time = "2024-09-30T22:04:50.53Z" }, + { url = "https://files.pythonhosted.org/packages/49/d0/b07c71dfb6f7f47f90495d67cb0b2264f94f2fb9380e528fe4fcec4c5cfa/symengine-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ea9410330ea15ed4137d7a0a3c43caccacb71490e18036ce5182d08c93baf8", size = 49582795, upload-time = "2024-09-30T22:04:56.705Z" }, + { url = "https://files.pythonhosted.org/packages/de/c6/3ce562ec269b033a738b99aa75729d564bfe465a765a5b5810200924f5c9/symengine-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:5031eb7a5c6675d5195bb57f93cc7d9ac5a7a9a826d4ad6f6b2927746ed7e6e6", size = 17786679, upload-time = "2024-09-30T22:05:30.754Z" }, + { url = "https://files.pythonhosted.org/packages/ca/0f/02031b4ed54fb088ade94082e4658160333c2d5c6629ca7e567ea5a23720/symengine-0.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ce0e5dfb19943bcf3e44a4485bcac4c5533ba3705c63083494eed0b3bf246076", size = 25795209, upload-time = "2024-09-30T22:05:05.713Z" }, + { url = "https://files.pythonhosted.org/packages/34/c0/03e9e34a4e2af73dd786fb966ee3ad7ffa57659e79e4ac390be9e9f6aded/symengine-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c3b77dc54bf1181f6bd3b3338c4e6e5973a8b0fa20a189d15563ef5626e57b04", size = 22670484, upload-time = "2024-09-30T22:05:08.721Z" }, + { url = "https://files.pythonhosted.org/packages/9d/13/66c8510403089ee157f0a8930a2e043e6f4de9ee514c8084adb958934058/symengine-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca7c3f6c168f6f5b06b421833c3d3baae56067a94b671bdffbe09b8e4fefd9be", size = 60739889, upload-time = "2024-09-30T22:05:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/70/fe/d0c778204d855257865e713fcbfef11dde34621e07fee439d4d117f43203/symengine-0.13.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:847523de682416811bacb3ad11507e663b3522fbb35cd27184757e9956d0eaf0", size = 89405899, upload-time = "2024-09-30T22:05:20.504Z" }, + { url = "https://files.pythonhosted.org/packages/66/f6/f546e527caf35b7d0f14dbcea278134d4e46d7431821b9ca9f5ec3388a6a/symengine-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2fc1b7d96426463f0c9011e9fb88459d906477c1baa8a996dde6fb2bfa99d4", size = 49474632, upload-time = "2024-09-30T22:05:26.083Z" }, ] [[package]] @@ -4095,11 +5108,215 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, ] +[[package]] +name = "widgetsnbextension" +version = "4.0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, +] + +[[package]] +name = "wrapt" +version = "1.17.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/23/bb82321b86411eb51e5a5db3fb8f8032fd30bd7c2d74bfe936136b2fa1d6/wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04", size = 53482, upload-time = "2025-08-12T05:51:44.467Z" }, + { url = "https://files.pythonhosted.org/packages/45/69/f3c47642b79485a30a59c63f6d739ed779fb4cc8323205d047d741d55220/wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2", size = 38676, upload-time = "2025-08-12T05:51:32.636Z" }, + { url = "https://files.pythonhosted.org/packages/d1/71/e7e7f5670c1eafd9e990438e69d8fb46fa91a50785332e06b560c869454f/wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c", size = 38957, upload-time = "2025-08-12T05:51:54.655Z" }, + { url = "https://files.pythonhosted.org/packages/de/17/9f8f86755c191d6779d7ddead1a53c7a8aa18bccb7cea8e7e72dfa6a8a09/wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775", size = 81975, upload-time = "2025-08-12T05:52:30.109Z" }, + { url = "https://files.pythonhosted.org/packages/f2/15/dd576273491f9f43dd09fce517f6c2ce6eb4fe21681726068db0d0467096/wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd", size = 83149, upload-time = "2025-08-12T05:52:09.316Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c4/5eb4ce0d4814521fee7aa806264bf7a114e748ad05110441cd5b8a5c744b/wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05", size = 82209, upload-time = "2025-08-12T05:52:10.331Z" }, + { url = "https://files.pythonhosted.org/packages/31/4b/819e9e0eb5c8dc86f60dfc42aa4e2c0d6c3db8732bce93cc752e604bb5f5/wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418", size = 81551, upload-time = "2025-08-12T05:52:31.137Z" }, + { url = "https://files.pythonhosted.org/packages/f8/83/ed6baf89ba3a56694700139698cf703aac9f0f9eb03dab92f57551bd5385/wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390", size = 36464, upload-time = "2025-08-12T05:53:01.204Z" }, + { url = "https://files.pythonhosted.org/packages/2f/90/ee61d36862340ad7e9d15a02529df6b948676b9a5829fd5e16640156627d/wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6", size = 38748, upload-time = "2025-08-12T05:53:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c3/cefe0bd330d389c9983ced15d326f45373f4073c9f4a8c2f99b50bfea329/wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18", size = 36810, upload-time = "2025-08-12T05:52:51.906Z" }, + { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" }, + { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" }, + { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" }, + { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" }, + { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" }, + { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" }, + { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, + { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, + { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, + { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, + { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, + { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, + { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, + { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, + { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, + { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, + { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, + { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, + { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, + { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, + { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, + { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, + { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, + { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, + { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, + { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, + { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, + { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, + { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, +] + +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, + { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, + { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, + { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, + { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, + { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, + { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, + { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, + { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, + { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +] + [[package]] name = "zipp" -version = "3.23.0" +version = "3.19.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/a1/ac66fba5917fb7860f91cb251ac6cf838923a8abe89e059cc1988cb256d1/zipp-3.19.1.tar.gz", hash = "sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f", size = 22625, upload-time = "2024-05-31T16:39:21.514Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/82/1a/ac67760425f2477b1da593b347db66d474130747e6e5285d08c7f2d5884a/zipp-3.19.1-py3-none-any.whl", hash = "sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091", size = 8951, upload-time = "2024-05-31T16:39:19.68Z" }, ] From 9ed91ee0daa07053dfa21603a650a01f07681594 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 17 Dec 2025 15:38:55 +0100 Subject: [PATCH 79/98] Fix tool.check-sdist --- pyproject.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 497805763..4ab10ba45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,9 +99,6 @@ Issues = "https://github.com/munich-quantum-toolkit/predictor/issues" Discussions = "https://github.com/munich-quantum-toolkit/predictor/discussions" Research = "https://www.cda.cit.tum.de/research/quantum/" -[tool.check-sdist] -sdist-only = ["src/mqt/predictor/_version.py"] - [tool.hatch.build.targets.wheel] packages = ["src/mqt"] @@ -272,6 +269,5 @@ override-dependencies = [ "networkx==2.8.5", # Required by `qiskit-ibm-transpiler` ] - [tool.check-sdist] sdist-only = ["src/mqt/predictor/_version.py"] From 72c14817b0d1bce50bc1ba9fb237f74891197bdd Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 17 Dec 2025 16:16:04 +0100 Subject: [PATCH 80/98] Allow Python 3.13 for AIRouting --- src/mqt/predictor/rl/actions.py | 147 +++++++++++++++----------------- 1 file changed, 71 insertions(+), 76 deletions(-) diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index e6f67a0fd..d838d84e8 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -11,7 +11,6 @@ from __future__ import annotations import os -import sys from collections import defaultdict from dataclasses import dataclass from enum import Enum @@ -80,9 +79,7 @@ ) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler.preset_passmanagers import common - -if sys.version_info < (3, 13): - from qiskit_ibm_transpiler.ai.routing import AIRouting +from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.rl.parsing import ( PreProcessTKETRoutingAfterQiskitLayout, @@ -490,40 +487,40 @@ def remove_action(name: str) -> None: ], ) ) -if sys.version_info < (3, 13): - register_action( - DeviceDependentAction( - "AIRouting", - CompilationOrigin.QISKIT, - PassType.ROUTING, - stochastic=True, - transpile_pass=lambda device: [ - SafeAIRouting( - coupling_map=device.build_coupling_map(), - optimization_level=3, - layout_mode="improve", - local_mode=True, - ) - ], - ) - ) - - register_action( - DeviceDependentAction( - "AIRouting_opt", - CompilationOrigin.QISKIT, - PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device: [ - ### Requires an initial layout, but "optimize" mode overwrites it - SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=True, max_iterations=1), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), - ], - ) + +register_action( + DeviceDependentAction( + "AIRouting", + CompilationOrigin.QISKIT, + PassType.ROUTING, + stochastic=True, + transpile_pass=lambda device: [ + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="improve", + local_mode=True, + ) + ], ) +) + +register_action( + DeviceDependentAction( + "AIRouting_opt", + CompilationOrigin.QISKIT, + PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device: [ + ### Requires an initial layout, but "optimize" mode overwrites it + SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=True, max_iterations=1), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), + ], + ) +) register_action( DeviceDependentAction( @@ -697,42 +694,40 @@ def add_cregs_and_measurements( return qc -if sys.version_info < (3, 13): - - class SafeAIRouting(AIRouting): # type: ignore[misc] - """Custom AIRouting wrapper that removes classical registers before routing. - - This prevents failures in AIRouting when classical bits are present by - temporarily removing classical registers and measurements and restoring - them after routing is completed. - """ - - def run(self, dag: DAGCircuit) -> DAGCircuit: - """Run the routing pass on a DAGCircuit.""" - qc_orig = dag_to_circuit(dag) - # Extract classical registers and measurement instructions - cregs, measurements = extract_cregs_and_measurements(qc_orig) - # Remove cregs and measurements - qc_noclassical = remove_cregs(qc_orig) - # Convert back to dag and run routing (AIRouting) - dag_noclassical = circuit_to_dag(qc_noclassical) - dag_routed = super().run(dag_noclassical) - # Convert routed dag to circuit for restoration - qc_routed = dag_to_circuit(dag_routed) - # Build mapping from original qubits to qubits in routed circuit - final_layout = getattr(self, "property_set", {}).get("final_layout", None) - assert final_layout is not None, "final_layout is None — cannot map virtual qubits" - qubit_map = {} - for virt in qc_orig.qubits: - assert virt in final_layout, f"Virtual qubit {virt} not found in final layout!" - phys = final_layout[virt] - if isinstance(phys, int): - assert 0 <= phys < len(qc_routed.qubits), f"Physical index {phys} out of range in routed circuit!" - qubit_map[virt] = qc_routed.qubits[phys] - else: - assert phys in qc_routed.qubits, f"Physical qubit {phys} not found in output circuit!" - qubit_map[virt] = qc_routed.qubits[qc_routed.qubits.index(phys)] - # Restore classical registers and measurement instructions - qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) - # Return as dag - return circuit_to_dag(qc_final) +class SafeAIRouting(AIRouting): # type: ignore[misc] + """Custom AIRouting wrapper that removes classical registers before routing. + + This prevents failures in AIRouting when classical bits are present by + temporarily removing classical registers and measurements and restoring + them after routing is completed. + """ + + def run(self, dag: DAGCircuit) -> DAGCircuit: + """Run the routing pass on a DAGCircuit.""" + qc_orig = dag_to_circuit(dag) + # Extract classical registers and measurement instructions + cregs, measurements = extract_cregs_and_measurements(qc_orig) + # Remove cregs and measurements + qc_noclassical = remove_cregs(qc_orig) + # Convert back to dag and run routing (AIRouting) + dag_noclassical = circuit_to_dag(qc_noclassical) + dag_routed = super().run(dag_noclassical) + # Convert routed dag to circuit for restoration + qc_routed = dag_to_circuit(dag_routed) + # Build mapping from original qubits to qubits in routed circuit + final_layout = getattr(self, "property_set", {}).get("final_layout", None) + assert final_layout is not None, "final_layout is None — cannot map virtual qubits" + qubit_map = {} + for virt in qc_orig.qubits: + assert virt in final_layout, f"Virtual qubit {virt} not found in final layout!" + phys = final_layout[virt] + if isinstance(phys, int): + assert 0 <= phys < len(qc_routed.qubits), f"Physical index {phys} out of range in routed circuit!" + qubit_map[virt] = qc_routed.qubits[phys] + else: + assert phys in qc_routed.qubits, f"Physical qubit {phys} not found in output circuit!" + qubit_map[virt] = qc_routed.qubits[qc_routed.qubits.index(phys)] + # Restore classical registers and measurement instructions + qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) + # Return as dag + return circuit_to_dag(qc_final) From 9a853e15f5501fbd8ba5ebd469916ef643ca60e8 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Wed, 17 Dec 2025 19:38:20 +0100 Subject: [PATCH 81/98] Ignore syntax warnings --- pyproject.toml | 4 +++- uv.lock | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4ab10ba45..74627c0ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ "numpy>=1.22", "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler==0.15.0", - "qiskit-ibm-ai-local-transpiler==0.5.5; python_version < '3.13'", + "qiskit-ibm-ai-local-transpiler==0.5.5", ] classifiers = [ @@ -119,6 +119,8 @@ addopts = [ ] log_level = "INFO" filterwarnings = [ + "ignore:.*\"is\" with a literal.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", + "ignore:.*invalid escape sequence.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", 'error', 'ignore:.*pytorch.*:UserWarning:', 'ignore:.*Values in x.*:RuntimeWarning:', diff --git a/uv.lock b/uv.lock index 0c05b99d3..10a5cac5c 100644 --- a/uv.lock +++ b/uv.lock @@ -1951,7 +1951,7 @@ dependencies = [ { name = "pytket" }, { name = "pytket-qiskit" }, { name = "qiskit" }, - { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'" }, + { name = "qiskit-ibm-ai-local-transpiler" }, { name = "qiskit-ibm-runtime" }, { name = "qiskit-ibm-transpiler" }, { name = "rich" }, @@ -1999,7 +1999,7 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = ">=1.3.3" }, - { name = "qiskit-ibm-ai-local-transpiler", marker = "python_full_version < '3.13'", specifier = "==0.5.5" }, + { name = "qiskit-ibm-ai-local-transpiler", specifier = "==0.5.5" }, { name = "qiskit-ibm-runtime", specifier = ">=0.30.0,<0.42.0" }, { name = "qiskit-ibm-transpiler", specifier = "==0.15.0" }, { name = "rich", specifier = ">=12.6.0" }, From a6de70d09eccc44673bd0e662efb4adb7572e43a Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Dec 2025 16:00:15 +0100 Subject: [PATCH 82/98] Add filterwarnings --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 74627c0ba..fe29923c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -119,8 +119,8 @@ addopts = [ ] log_level = "INFO" filterwarnings = [ - "ignore:.*\"is\" with a literal.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", "ignore:.*invalid escape sequence.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", + "ignore:.*\\\"is\\\" with.*literal.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", 'error', 'ignore:.*pytorch.*:UserWarning:', 'ignore:.*Values in x.*:RuntimeWarning:', From 4c3bd926db6a3db7a539ca04d5a7d8468549150a Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Dec 2025 16:10:36 +0100 Subject: [PATCH 83/98] Add comments --- pyproject.toml | 4 ++++ src/mqt/predictor/rl/predictorenv.py | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index fe29923c9..ca9033dc4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -119,6 +119,9 @@ addopts = [ ] log_level = "INFO" filterwarnings = [ + # NOTE: qiskit-ibm-transpiler (>=0.14) imports wrappers/function_transpile.py during import, + # which currently triggers SyntaxWarnings (invalid escape sequence, and `is` with string literal). + # TODO: Remove these ignores once upstream fixes the warnings. "ignore:.*invalid escape sequence.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", "ignore:.*\\\"is\\\" with.*literal.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", 'error', @@ -131,6 +134,7 @@ filterwarnings = [ 'ignore:.*qiskit.providers.models is deprecated since Qiskit 1.2*:DeprecationWarning:', 'ignore:.*The class ``qiskit.qobj.*`` is deprecated as of Qiskit 1.3.*:DeprecationWarning:', 'ignore:.*The property ``qiskit.circuit.instruction.Instruction.*`` is deprecated as of qiskit 1.3.0.*:DeprecationWarning:', + # Windows: Python 3.13 can emit a RuntimeWarning about unsupported timeouts; keep tests strict otherwise. 'ignore:.*Timeout is not supported on Windows\\.:RuntimeWarning', ] diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index c24aa8703..4ec5807b9 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -456,7 +456,12 @@ def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCirc self.actions_layout_indices + self.actions_mapping_indices + self.actions_final_optimization_indices ): altered_qc = self._handle_qiskit_layout_postprocessing(action, pm_property_set, altered_qc) - elif action_index in self.actions_routing_indices and self.layout and pm_property_set is not None: + elif ( + action_index in self.actions_routing_indices + and self.layout is not None + and pm_property_set is not None + and "final_layout" in pm_property_set + ): self.layout.final_layout = pm_property_set["final_layout"] return altered_qc From 63e4dac34ec5c28670ef80826f66edc719d2aa54 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Dec 2025 16:20:22 +0100 Subject: [PATCH 84/98] Loosen constraints --- pyproject.toml | 4 ++-- uv.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ca9033dc4..e428f5dae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,8 +48,8 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler==0.15.0", - "qiskit-ibm-ai-local-transpiler==0.5.5", + "qiskit-ibm-transpiler>=0.15.0", + "qiskit-ibm-ai-local-transpiler>=0.5.5", ] classifiers = [ diff --git a/uv.lock b/uv.lock index 10a5cac5c..0801fa719 100644 --- a/uv.lock +++ b/uv.lock @@ -1999,9 +1999,9 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = ">=1.3.3" }, - { name = "qiskit-ibm-ai-local-transpiler", specifier = "==0.5.5" }, + { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.5.5" }, { name = "qiskit-ibm-runtime", specifier = ">=0.30.0,<0.42.0" }, - { name = "qiskit-ibm-transpiler", specifier = "==0.15.0" }, + { name = "qiskit-ibm-transpiler", specifier = ">=0.15.0" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, From 6d43c15303c0e080c0c05192281cf5928ced7934 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Dec 2025 16:37:04 +0100 Subject: [PATCH 85/98] Loosen constraints --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e428f5dae..87dfe6d47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ "numpy>=1.22", "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.15.0", - "qiskit-ibm-ai-local-transpiler>=0.5.5", + "qiskit-ibm-ai-local-transpiler>=0.5.0", ] classifiers = [ diff --git a/uv.lock b/uv.lock index 0801fa719..73ce6a785 100644 --- a/uv.lock +++ b/uv.lock @@ -1999,7 +1999,7 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = ">=1.3.3" }, - { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.5.5" }, + { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.5.0" }, { name = "qiskit-ibm-runtime", specifier = ">=0.30.0,<0.42.0" }, { name = "qiskit-ibm-transpiler", specifier = ">=0.15.0" }, { name = "rich", specifier = ">=12.6.0" }, From a67f672d66595e609dd534e5794a521b667c9fb0 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Dec 2025 16:42:47 +0100 Subject: [PATCH 86/98] Fixes --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 87dfe6d47..e428f5dae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ "numpy>=1.22", "typing-extensions>=4.1", # for `assert_never` "qiskit-ibm-transpiler>=0.15.0", - "qiskit-ibm-ai-local-transpiler>=0.5.0", + "qiskit-ibm-ai-local-transpiler>=0.5.5", ] classifiers = [ diff --git a/uv.lock b/uv.lock index 73ce6a785..0801fa719 100644 --- a/uv.lock +++ b/uv.lock @@ -1999,7 +1999,7 @@ requires-dist = [ { name = "pytket", specifier = ">=1.29.0" }, { name = "pytket-qiskit", specifier = ">=0.71.0" }, { name = "qiskit", specifier = ">=1.3.3" }, - { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.5.0" }, + { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.5.5" }, { name = "qiskit-ibm-runtime", specifier = ">=0.30.0,<0.42.0" }, { name = "qiskit-ibm-transpiler", specifier = ">=0.15.0" }, { name = "rich", specifier = ">=12.6.0" }, From d50965147dca18a62e2e4aefbca195638786d1ac Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Dec 2025 18:02:46 +0100 Subject: [PATCH 87/98] Guard Python 3.13 & Win32 import error --- pyproject.toml | 2 +- src/mqt/predictor/rl/actions.py | 148 +++++++++++++++++--------------- uv.lock | 4 +- 3 files changed, 81 insertions(+), 73 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e428f5dae..18c1f5578 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ dependencies = [ "numpy>=1.24; python_version >= '3.11'", "numpy>=1.22", "typing-extensions>=4.1", # for `assert_never` - "qiskit-ibm-transpiler>=0.15.0", + "qiskit-ibm-transpiler>=0.15.0; sys_platform != 'win32' or python_version != '3.13'", "qiskit-ibm-ai-local-transpiler>=0.5.5", ] diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index d838d84e8..f418851aa 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -11,6 +11,7 @@ from __future__ import annotations import os +import sys from collections import defaultdict from dataclasses import dataclass from enum import Enum @@ -79,13 +80,17 @@ ) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler.preset_passmanagers import common -from qiskit_ibm_transpiler.ai.routing import AIRouting from mqt.predictor.rl.parsing import ( PreProcessTKETRoutingAfterQiskitLayout, get_bqskit_native_gates, ) +IS_WIN_PY313 = sys.platform == "win32" and sys.version_info[:2] == (3, 13) +if not IS_WIN_PY313: + from qiskit_ibm_transpiler.ai.routing import AIRouting + + if TYPE_CHECKING: from collections.abc import Callable from typing import Any @@ -488,39 +493,40 @@ def remove_action(name: str) -> None: ) ) -register_action( - DeviceDependentAction( - "AIRouting", - CompilationOrigin.QISKIT, - PassType.ROUTING, - stochastic=True, - transpile_pass=lambda device: [ - SafeAIRouting( - coupling_map=device.build_coupling_map(), - optimization_level=3, - layout_mode="improve", - local_mode=True, - ) - ], +if not IS_WIN_PY313: + register_action( + DeviceDependentAction( + "AIRouting", + CompilationOrigin.QISKIT, + PassType.ROUTING, + stochastic=True, + transpile_pass=lambda device: [ + SafeAIRouting( + coupling_map=device.build_coupling_map(), + optimization_level=3, + layout_mode="improve", + local_mode=True, + ) + ], + ) + ) + + register_action( + DeviceDependentAction( + "AIRouting_opt", + CompilationOrigin.QISKIT, + PassType.MAPPING, + stochastic=True, + transpile_pass=lambda device: [ + ### Requires an initial layout, but "optimize" mode overwrites it + SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=True, max_iterations=1), + FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), + EnlargeWithAncilla(), + ApplyLayout(), + SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), + ], + ) ) -) - -register_action( - DeviceDependentAction( - "AIRouting_opt", - CompilationOrigin.QISKIT, - PassType.MAPPING, - stochastic=True, - transpile_pass=lambda device: [ - ### Requires an initial layout, but "optimize" mode overwrites it - SabreLayout(coupling_map=CouplingMap(device.build_coupling_map()), skip_routing=True, max_iterations=1), - FullAncillaAllocation(coupling_map=CouplingMap(device.build_coupling_map())), - EnlargeWithAncilla(), - ApplyLayout(), - SafeAIRouting(coupling_map=device.build_coupling_map(), optimization_level=3, layout_mode="optimize"), - ], - ) -) register_action( DeviceDependentAction( @@ -694,40 +700,42 @@ def add_cregs_and_measurements( return qc -class SafeAIRouting(AIRouting): # type: ignore[misc] - """Custom AIRouting wrapper that removes classical registers before routing. - - This prevents failures in AIRouting when classical bits are present by - temporarily removing classical registers and measurements and restoring - them after routing is completed. - """ - - def run(self, dag: DAGCircuit) -> DAGCircuit: - """Run the routing pass on a DAGCircuit.""" - qc_orig = dag_to_circuit(dag) - # Extract classical registers and measurement instructions - cregs, measurements = extract_cregs_and_measurements(qc_orig) - # Remove cregs and measurements - qc_noclassical = remove_cregs(qc_orig) - # Convert back to dag and run routing (AIRouting) - dag_noclassical = circuit_to_dag(qc_noclassical) - dag_routed = super().run(dag_noclassical) - # Convert routed dag to circuit for restoration - qc_routed = dag_to_circuit(dag_routed) - # Build mapping from original qubits to qubits in routed circuit - final_layout = getattr(self, "property_set", {}).get("final_layout", None) - assert final_layout is not None, "final_layout is None — cannot map virtual qubits" - qubit_map = {} - for virt in qc_orig.qubits: - assert virt in final_layout, f"Virtual qubit {virt} not found in final layout!" - phys = final_layout[virt] - if isinstance(phys, int): - assert 0 <= phys < len(qc_routed.qubits), f"Physical index {phys} out of range in routed circuit!" - qubit_map[virt] = qc_routed.qubits[phys] - else: - assert phys in qc_routed.qubits, f"Physical qubit {phys} not found in output circuit!" - qubit_map[virt] = qc_routed.qubits[qc_routed.qubits.index(phys)] - # Restore classical registers and measurement instructions - qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) - # Return as dag - return circuit_to_dag(qc_final) +if not IS_WIN_PY313: + + class SafeAIRouting(AIRouting): # type: ignore[misc] + """Custom AIRouting wrapper that removes classical registers before routing. + + This prevents failures in AIRouting when classical bits are present by + temporarily removing classical registers and measurements and restoring + them after routing is completed. + """ + + def run(self, dag: DAGCircuit) -> DAGCircuit: + """Run the routing pass on a DAGCircuit.""" + qc_orig = dag_to_circuit(dag) + # Extract classical registers and measurement instructions + cregs, measurements = extract_cregs_and_measurements(qc_orig) + # Remove cregs and measurements + qc_noclassical = remove_cregs(qc_orig) + # Convert back to dag and run routing (AIRouting) + dag_noclassical = circuit_to_dag(qc_noclassical) + dag_routed = super().run(dag_noclassical) + # Convert routed dag to circuit for restoration + qc_routed = dag_to_circuit(dag_routed) + # Build mapping from original qubits to qubits in routed circuit + final_layout = getattr(self, "property_set", {}).get("final_layout", None) + assert final_layout is not None, "final_layout is None — cannot map virtual qubits" + qubit_map = {} + for virt in qc_orig.qubits: + assert virt in final_layout, f"Virtual qubit {virt} not found in final layout!" + phys = final_layout[virt] + if isinstance(phys, int): + assert 0 <= phys < len(qc_routed.qubits), f"Physical index {phys} out of range in routed circuit!" + qubit_map[virt] = qc_routed.qubits[phys] + else: + assert phys in qc_routed.qubits, f"Physical qubit {phys} not found in output circuit!" + qubit_map[virt] = qc_routed.qubits[qc_routed.qubits.index(phys)] + # Restore classical registers and measurement instructions + qc_final = add_cregs_and_measurements(qc_routed, cregs, measurements, qubit_map) + # Return as dag + return circuit_to_dag(qc_final) diff --git a/uv.lock b/uv.lock index 0801fa719..4f16484fb 100644 --- a/uv.lock +++ b/uv.lock @@ -1953,7 +1953,7 @@ dependencies = [ { name = "qiskit" }, { name = "qiskit-ibm-ai-local-transpiler" }, { name = "qiskit-ibm-runtime" }, - { name = "qiskit-ibm-transpiler" }, + { name = "qiskit-ibm-transpiler", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, { name = "rich" }, { name = "sb3-contrib", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13' and 'x86_64' in platform_machine and sys_platform == 'darwin'" }, { name = "sb3-contrib", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13' or (python_full_version < '3.13' and 'x86_64' not in platform_machine) or sys_platform != 'darwin'" }, @@ -2001,7 +2001,7 @@ requires-dist = [ { name = "qiskit", specifier = ">=1.3.3" }, { name = "qiskit-ibm-ai-local-transpiler", specifier = ">=0.5.5" }, { name = "qiskit-ibm-runtime", specifier = ">=0.30.0,<0.42.0" }, - { name = "qiskit-ibm-transpiler", specifier = ">=0.15.0" }, + { name = "qiskit-ibm-transpiler", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'", specifier = ">=0.15.0" }, { name = "rich", specifier = ">=12.6.0" }, { name = "sb3-contrib", specifier = ">=2.0.0" }, { name = "scikit-learn", specifier = ">=1.5.1" }, From beb343bc3818b552bef1dd44071a77e1326c6001 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 18 Dec 2025 19:24:58 +0100 Subject: [PATCH 88/98] Fix filterwarnings --- pyproject.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 18c1f5578..ddc6d1440 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -122,9 +122,10 @@ filterwarnings = [ # NOTE: qiskit-ibm-transpiler (>=0.14) imports wrappers/function_transpile.py during import, # which currently triggers SyntaxWarnings (invalid escape sequence, and `is` with string literal). # TODO: Remove these ignores once upstream fixes the warnings. - "ignore:.*invalid escape sequence.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", - "ignore:.*\\\"is\\\" with.*literal.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", 'error', + "ignore:.*invalid escape sequence.*:DeprecationWarning:qiskit_ibm_transpiler\\..*", + "ignore:.*invalid escape sequence.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", + "ignore:.*is.*with.*literal.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", 'ignore:.*pytorch.*:UserWarning:', 'ignore:.*Values in x.*:RuntimeWarning:', 'ignore:.*The least populated class in y has only 3 members, which is less than n_splits=5.*:UserWarning:', From ee41df016705211d6d1e65e1ce20bbf7382fa5d5 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 8 Jan 2026 14:01:35 +0100 Subject: [PATCH 89/98] Fix warning treated as error issue --- noxfile.py | 89 ++++++++++++++++++++++++-------------------------- pyproject.toml | 8 ++--- 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/noxfile.py b/noxfile.py index 0be885b48..67b3c2e54 100755 --- a/noxfile.py +++ b/noxfile.py @@ -59,54 +59,51 @@ def lint(session: nox.Session) -> None: session.run("prek", "run", "--all-files", *session.posargs, external=True) + def _run_tests( + session: nox.Session, + *, + install_args: Sequence[str] = (), + extra_command: Sequence[str] = (), + pytest_run_args: Sequence[str] = (), + ) -> None: + env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} -def _run_tests( - session: nox.Session, - *, - install_args: Sequence[str] = (), - extra_command: Sequence[str] = (), - pytest_run_args: Sequence[str] = (), -) -> None: - env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} - - if extra_command: - session.run(*extra_command, env=env) - if "--cov" in session.posargs: - # Try to use the lighter-weight `sys.monitoring` coverage core available in Python 3.12+ to speed up coverage collection. - env["COVERAGE_CORE"] = "sysmon" - session.run( - "uv", - "run", - "--no-dev", - "--group", - "test", - *install_args, - "pytest", - *pytest_run_args, - *session.posargs, - "--cov-config=pyproject.toml", - env=env, - ) - - -@nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, default=True) -def tests(session: nox.Session) -> None: - """Run the test suite.""" - _run_tests(session) - - -@nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True) -def minimums(session: nox.Session) -> None: - """Test the minimum versions of dependencies.""" - with preserve_lockfile(): - _run_tests( - session, - install_args=["--resolution=lowest-direct"], - pytest_run_args=["-Wdefault"], + if extra_command: + session.run(*extra_command, env=env) + if "--cov" in session.posargs: + # Try to use the lighter-weight `sys.monitoring` coverage core available in Python 3.12+ to speed up coverage collection. + env["COVERAGE_CORE"] = "sysmon" + session.run( + "uv", + "run", + "--no-dev", + "--group", + "test", + *install_args, + "pytest", + *pytest_run_args, + *session.posargs, + "--cov-config=pyproject.toml", + env=env, ) - env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} - session.run("uv", "tree", "--frozen", env=env) - session.run("uv", "lock", "--refresh", env=env) + + @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, default=True) + def tests(session: nox.Session) -> None: + """Run the test suite.""" + _run_tests(session) + + @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True) + def minimums(session: nox.Session) -> None: + """Test the minimum versions of dependencies.""" + with preserve_lockfile(): + _run_tests( + session, + install_args=["--resolution=lowest-direct"], + pytest_run_args=["-Wdefault"], + ) + env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} + session.run("uv", "tree", "--frozen", env=env) + session.run("uv", "lock", "--refresh", env=env) @nox.session(reuse_venv=True) diff --git a/pyproject.toml b/pyproject.toml index ddc6d1440..734d349c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,7 +109,7 @@ source = "vcs" version-file = "src/mqt/predictor/_version.py" -[tool.pytest] +[tool.pytest.ini_options] minversion = "9.0" testpaths = ["tests"] strict = true @@ -123,9 +123,9 @@ filterwarnings = [ # which currently triggers SyntaxWarnings (invalid escape sequence, and `is` with string literal). # TODO: Remove these ignores once upstream fixes the warnings. 'error', - "ignore:.*invalid escape sequence.*:DeprecationWarning:qiskit_ibm_transpiler\\..*", - "ignore:.*invalid escape sequence.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", - "ignore:.*is.*with.*literal.*:SyntaxWarning:qiskit_ibm_transpiler\\..*", + "ignore:invalid escape sequence '\\\\w':DeprecationWarning:qiskit_ibm_transpiler\\..*", + "ignore:invalid escape sequence '\\\\w':SyntaxWarning:qiskit_ibm_transpiler\\..*", + "ignore:\"is\" with a literal:SyntaxWarning:qiskit_ibm_transpiler\\..*", 'ignore:.*pytorch.*:UserWarning:', 'ignore:.*Values in x.*:RuntimeWarning:', 'ignore:.*The least populated class in y has only 3 members, which is less than n_splits=5.*:UserWarning:', From f2ccad479de9366a4c39b9db159d5dc8f25910a4 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Thu, 8 Jan 2026 14:12:55 +0100 Subject: [PATCH 90/98] Fix noxfile --- noxfile.py | 89 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/noxfile.py b/noxfile.py index 67b3c2e54..0be885b48 100755 --- a/noxfile.py +++ b/noxfile.py @@ -59,51 +59,54 @@ def lint(session: nox.Session) -> None: session.run("prek", "run", "--all-files", *session.posargs, external=True) - def _run_tests( - session: nox.Session, - *, - install_args: Sequence[str] = (), - extra_command: Sequence[str] = (), - pytest_run_args: Sequence[str] = (), - ) -> None: - env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} - if extra_command: - session.run(*extra_command, env=env) - if "--cov" in session.posargs: - # Try to use the lighter-weight `sys.monitoring` coverage core available in Python 3.12+ to speed up coverage collection. - env["COVERAGE_CORE"] = "sysmon" - session.run( - "uv", - "run", - "--no-dev", - "--group", - "test", - *install_args, - "pytest", - *pytest_run_args, - *session.posargs, - "--cov-config=pyproject.toml", - env=env, - ) +def _run_tests( + session: nox.Session, + *, + install_args: Sequence[str] = (), + extra_command: Sequence[str] = (), + pytest_run_args: Sequence[str] = (), +) -> None: + env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} + + if extra_command: + session.run(*extra_command, env=env) + if "--cov" in session.posargs: + # Try to use the lighter-weight `sys.monitoring` coverage core available in Python 3.12+ to speed up coverage collection. + env["COVERAGE_CORE"] = "sysmon" + session.run( + "uv", + "run", + "--no-dev", + "--group", + "test", + *install_args, + "pytest", + *pytest_run_args, + *session.posargs, + "--cov-config=pyproject.toml", + env=env, + ) + - @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, default=True) - def tests(session: nox.Session) -> None: - """Run the test suite.""" - _run_tests(session) - - @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True) - def minimums(session: nox.Session) -> None: - """Test the minimum versions of dependencies.""" - with preserve_lockfile(): - _run_tests( - session, - install_args=["--resolution=lowest-direct"], - pytest_run_args=["-Wdefault"], - ) - env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} - session.run("uv", "tree", "--frozen", env=env) - session.run("uv", "lock", "--refresh", env=env) +@nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, default=True) +def tests(session: nox.Session) -> None: + """Run the test suite.""" + _run_tests(session) + + +@nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True) +def minimums(session: nox.Session) -> None: + """Test the minimum versions of dependencies.""" + with preserve_lockfile(): + _run_tests( + session, + install_args=["--resolution=lowest-direct"], + pytest_run_args=["-Wdefault"], + ) + env = {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location} + session.run("uv", "tree", "--frozen", env=env) + session.run("uv", "lock", "--refresh", env=env) @nox.session(reuse_venv=True) From 3fc330ecb56dbb2eb7c3d8b6c1fab737bf7b5182 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:44:45 +0000 Subject: [PATCH 91/98] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 - src/mqt/predictor/rl/parsing.py | 2 +- src/mqt/predictor/rl/predictorenv.py | 3 --- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a641339f8..0488c7429 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,6 @@ _📚 Refer to the [GitHub Release Notes](https://github.com/munich-quantum-tool - [#445]: https://github.com/munich-quantum-toolkit/predictor/pull/445 [#572]: https://github.com/munich-quantum-toolkit/predictor/pull/572 [#489]: https://github.com/munich-quantum-toolkit/predictor/pull/489 diff --git a/src/mqt/predictor/rl/parsing.py b/src/mqt/predictor/rl/parsing.py index d975d30c5..e85332f2b 100644 --- a/src/mqt/predictor/rl/parsing.py +++ b/src/mqt/predictor/rl/parsing.py @@ -20,7 +20,7 @@ from pytket.placement import place_with_map from qiskit import QuantumCircuit, QuantumRegister from qiskit.converters import circuit_to_dag, dag_to_circuit -from qiskit.transpiler import Layout, PassManager, Target, TranspileLayout +from qiskit.transpiler import Layout, Target, TranspileLayout from qiskit.transpiler.passes import ApplyLayout if TYPE_CHECKING: diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 529a24ccd..a237714fd 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -13,8 +13,6 @@ import logging from typing import TYPE_CHECKING, Any -from pytket._tket.passes import BasePass as TketBasePass # noqa: PLC2701 - if TYPE_CHECKING: from collections.abc import Callable from pathlib import Path @@ -73,7 +71,6 @@ get_state_sample, ) from mqt.predictor.rl.parsing import ( - PreProcessTKETRoutingAfterQiskitLayout, final_layout_bqskit_to_qiskit, final_layout_pytket_to_qiskit, postprocess_vf2postlayout, From 9a3cc0114c07c5d6efd357222b5cd4911345888f Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 13 Feb 2026 18:29:54 +0100 Subject: [PATCH 92/98] Update to the ty checks --- .pre-commit-config.yaml | 2 +- src/mqt/predictor/ml/predictor.py | 1 + src/mqt/predictor/rl/actions.py | 2 +- src/mqt/predictor/rl/helper.py | 38 +++++++++++++++++-------------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 56d1c8b9f..63cfb1e0c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -139,7 +139,7 @@ repos: - id: ty-check name: ty check entry: uv run ty check - language: unsupported + language: system require_serial: true types_or: [python, pyi, jupyter] exclude: ^(docs/) diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index d4b79cd65..1f221b82d 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -18,6 +18,7 @@ import matplotlib.pyplot as plt import numpy as np +import sys from joblib import Parallel, delayed, load from joblib import dump as joblib_dump from mqt.bench.targets import get_device diff --git a/src/mqt/predictor/rl/actions.py b/src/mqt/predictor/rl/actions.py index 7f980dd15..0eec31b98 100644 --- a/src/mqt/predictor/rl/actions.py +++ b/src/mqt/predictor/rl/actions.py @@ -707,7 +707,7 @@ def add_cregs_and_measurements( if not IS_WIN_PY313: - class SafeAIRouting(AIRouting): # type: ignore[misc] + class SafeAIRouting(AIRouting): """Custom AIRouting wrapper that removes classical registers before routing. This prevents failures in AIRouting when classical bits are present by diff --git a/src/mqt/predictor/rl/helper.py b/src/mqt/predictor/rl/helper.py index d6f17aa93..f72814329 100644 --- a/src/mqt/predictor/rl/helper.py +++ b/src/mqt/predictor/rl/helper.py @@ -69,6 +69,16 @@ def get_state_sample(max_qubits: int, path_training_circuits: Path, rng: Generat return qc, str(file_list[random_index]) +def count_ops_by_name(qc: QuantumCircuit) -> dict[str, int]: + """Return count_ops with string keys (gate names).""" + raw = qc.count_ops() + out: dict[str, int] = {} + for k, v in raw.items(): + name = k if isinstance(k, str) else k.name # Instruction -> gate name + out[name] = out.get(name, 0) + int(v) + return out + + def dict_to_featurevector(gate_dict: dict[str, int]) -> dict[str, float]: """Calculates and returns a normalized feature vector of a given quantum circuit gate dictionary.""" res_dct = dict.fromkeys(get_openqasm_gates_without_u(), 0.0) @@ -81,32 +91,26 @@ def dict_to_featurevector(gate_dict: dict[str, int]) -> dict[str, float]: return res_dct -def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float64]]: - """Creates a feature dictionary for a given quantum circuit. +def create_feature_dict(qc: QuantumCircuit) -> dict[str, int | NDArray[np.float32]]: + """Creates a feature dictionary for a given quantum circuit.""" + ops = count_ops_by_name(qc) + total = sum(v for k, v in ops.items() if k != "barrier") + ops_list_dict = dict_to_featurevector(ops) - Arguments: - qc: The quantum circuit for which the feature dictionary is created. - - Returns: - The feature dictionary for the given quantum circuit. - """ - ops_list = qc.count_ops() - total = sum(val for key, val in ops_list.items() if key != "barrier") - ops_list_dict = dict_to_featurevector(ops_list) - - feature_dict = { + feature_dict: dict[str, int | NDArray[np.float32]] = { **{key: np.array([val], dtype=np.float32) for key, val in ops_list_dict.items()}, - "measure": np.array([ops_list.get("measure", 0) / total if total > 0 else 0.0], dtype=np.float32), - "num_qubits": qc.num_qubits, - "depth": qc.depth(), + "measure": np.array([ops.get("measure", 0) / total if total > 0 else 0.0], dtype=np.float32), + "num_qubits": int(qc.num_qubits), + "depth": int(qc.depth()), } + supermarq_features = calc_supermarq_features(qc) - # for all dict values, put them in a list each feature_dict["program_communication"] = np.array([supermarq_features.program_communication], dtype=np.float32) feature_dict["critical_depth"] = np.array([supermarq_features.critical_depth], dtype=np.float32) feature_dict["entanglement_ratio"] = np.array([supermarq_features.entanglement_ratio], dtype=np.float32) feature_dict["parallelism"] = np.array([supermarq_features.parallelism], dtype=np.float32) feature_dict["liveness"] = np.array([supermarq_features.liveness], dtype=np.float32) + return feature_dict From f24172e040abba1da0ea10e29ff92e98de1c1d21 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 13 Feb 2026 18:30:37 +0100 Subject: [PATCH 93/98] Update to the ty checks --- src/mqt/predictor/ml/predictor.py | 2 +- src/mqt/predictor/rl/predictorenv.py | 60 ++++++++++++++++++---------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/mqt/predictor/ml/predictor.py b/src/mqt/predictor/ml/predictor.py index 1f221b82d..a79d31db7 100644 --- a/src/mqt/predictor/ml/predictor.py +++ b/src/mqt/predictor/ml/predictor.py @@ -11,6 +11,7 @@ from __future__ import annotations import logging +import sys import zipfile from importlib import resources from pathlib import Path @@ -18,7 +19,6 @@ import matplotlib.pyplot as plt import numpy as np -import sys from joblib import Parallel, delayed, load from joblib import dump as joblib_dump from mqt.bench.targets import get_device diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index a237714fd..024833709 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -18,12 +18,16 @@ from pathlib import Path from bqskit import Circuit + from pytket._tket.passes import BasePass as TketBasePass from pytket.circuit import Node - from qiskit.passmanager import PropertySet - from qiskit.transpiler import Target + from qiskit.passmanager.base_tasks import Task + from qiskit.transpiler import Layout, Target from mqt.predictor.reward import figure_of_merit from mqt.predictor.rl.actions import Action + from mqt.predictor.rl.parsing import ( + PreProcessTKETRoutingAfterQiskitLayout, + ) import warnings @@ -36,6 +40,7 @@ from joblib import load from pytket.circuit import Qubit from pytket.extensions.qiskit import qiskit_to_tk, tk_to_qiskit +from pytket.placement import Placement from qiskit import QuantumCircuit from qiskit.circuit import StandardEquivalenceLibrary from qiskit.passmanager.flow_controllers import DoWhileController @@ -234,7 +239,7 @@ def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any # in case the Qiskit.QuantumCircuit has unitary or u gates in it, decompose them (because otherwise qiskit will throw an error when applying the BasisTranslator if self.state.count_ops().get("unitary"): # ty: ignore[invalid-argument-type] self.state = self.state.decompose(gates_to_decompose="unitary") - elif self.state.count_ops().get("clifford"): + elif self.state.count_ops().get("clifford"): # ty: ignore[invalid-argument-type] self.state = self.state.decompose(gates_to_decompose="clifford") self.state._layout = self.layout # noqa: SLF001 @@ -355,8 +360,8 @@ def apply_action(self, action_index: int) -> QuantumCircuit | None: raise ValueError(msg) def fom_aware_compile( - self, action: Action, device: Target, qc: QuantumCircuit, max_iteration: int = 20 - ) -> tuple[QuantumCircuit, PropertySet | None]: + self, action: Action, device: Target | None, qc: QuantumCircuit, max_iteration: int = 20 + ) -> tuple[QuantumCircuit, dict[str, Any] | None]: """Run a stochastic pass multiple times optimizing for the given figure of merit. Args: @@ -368,14 +373,16 @@ def fom_aware_compile( Returns: A tuple of the best circuit found and its property set (if available). """ - best_result = None - best_property_set = None + assert device is not None + best_result: QuantumCircuit | None = None + best_property_set: dict[str, Any] | None = None best_fom = -1.0 best_swap_count = float("inf") # for fallback assert callable(action.transpile_pass), "Mapping action should be callable" for i in range(max_iteration): - pm = PassManager(action.transpile_pass(device)) + passes = cast("list[Task]", action.transpile_pass(device)) + pm = PassManager(passes) try: out_circ = pm.run(qc) prop_set = dict(pm.property_set) @@ -403,7 +410,7 @@ def fom_aware_compile( except Exception as e: logger.warning(f"[Fallback to SWAP counts] Synthesis or fidelity computation failed: {e}") - swap_count = out_circ.count_ops().get("swap", 0) + swap_count = out_circ.count_ops().get("swap", 0) # ty: ignore[no-matching-overload] if best_result is None or swap_count < best_swap_count: best_swap_count = swap_count best_result = out_circ @@ -429,20 +436,23 @@ def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCirc ) else: if action.name in ["QiskitO3", "Opt2qBlocks_preserve"] and isinstance(action, DeviceDependentAction): - passes = action.transpile_pass( + passes_ = action.transpile_pass( self.device.operation_names, CouplingMap(self.device.build_coupling_map()) if self.layout else None, ) + passes = cast("list[Task]", passes_) if action.name == "QiskitO3": + assert action.do_while is not None pm = PassManager([DoWhileController(passes, do_while=action.do_while)]) else: pm = PassManager(passes) altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else None else: - transpile_pass = ( + transpile_pass_ = ( action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass ) + transpile_pass = cast("list[Task]", transpile_pass_) pm = PassManager(transpile_pass) altered_qc = pm.run(self.state) pm_property_set = dict(pm.property_set) if hasattr(pm, "property_set") else None @@ -482,11 +492,14 @@ def _handle_qiskit_layout_postprocessing( assert pm_property_set["layout"] layout = pm_property_set.get("layout") - if layout: + if layout is not None: + orig = pm_property_set["original_qubit_indices"] + final = pm_property_set["final_layout"] + self.layout = TranspileLayout( initial_layout=layout, - input_qubit_mapping=pm_property_set.get("original_qubit_indices"), - final_layout=pm_property_set.get("final_layout"), + input_qubit_mapping=cast("dict[Any, int]", orig), + final_layout=final, _output_qubit_list=altered_qc.qubits, _input_qubit_count=self.num_qubits_uncompiled_circuit, ) @@ -497,8 +510,8 @@ def _handle_qiskit_layout_postprocessing( def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircuit: tket_qc = qiskit_to_tk(self.state, preserve_param_uuid=True) + if action.name == "NoiseAwarePlacement": - # Handle NoiseAwarePlacement separately (requires error data) if self.node_err is None or self.edge_err is None or self.readout_err is None: self.node_err, self.edge_err, self.readout_err = prepare_noise_data(self.device) assert callable(action.transpile_pass) @@ -507,11 +520,14 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui transpile_pass = ( action.transpile_pass(self.device) if callable(action.transpile_pass) else action.transpile_pass ) + assert isinstance(transpile_pass, list) - # Map TKET placement into a Qiskit layout + if action_index in self.actions_layout_indices: try: - placement = transpile_pass[0].get_placement_map(tket_qc) + p0 = transpile_pass[0] + assert isinstance(p0, Placement) + placement = p0.get_placement_map(tket_qc) except Exception as e: logger.warning("Placement failed (%s): %s. Falling back to original circuit.", action.name, e) return tk_to_qiskit(tket_qc, replace_implicit_swaps=True) @@ -531,8 +547,11 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui ]) altered_qc = pm.run(qc_tmp) + layout2 = pm.property_set.get("layout") + assert isinstance(layout2, Layout) + self.layout = TranspileLayout( - initial_layout=pm.property_set.get("layout"), + initial_layout=layout2, input_qubit_mapping=pm.property_set["original_qubit_indices"], final_layout=pm.property_set["final_layout"], _output_qubit_list=altered_qc.qubits, @@ -541,8 +560,9 @@ def _apply_tket_action(self, action: Action, action_index: int) -> QuantumCircui return altered_qc else: - for p in transpile_pass: - p.apply(tket_qc) + passes = cast("list[TketBasePass | PreProcessTKETRoutingAfterQiskitLayout]", transpile_pass) + for pass_ in passes: + pass_.apply(tket_qc) qbs = tket_qc.qubits tket_qc.rename_units({qbs[i]: Qubit("q", i) for i in range(len(qbs))}) From 9d683b1533b4d056997b7bdf29b78726c6eeea81 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Fri, 13 Feb 2026 18:36:01 +0100 Subject: [PATCH 94/98] Fix ty --- tests/compilation/test_reward.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compilation/test_reward.py b/tests/compilation/test_reward.py index 5e36fcc8a..e1a2bdafc 100644 --- a/tests/compilation/test_reward.py +++ b/tests/compilation/test_reward.py @@ -132,3 +132,4 @@ def test_esp_data_available_invalid_target(kwargs: dict[str, float | bool]) -> N """Test that `esp_data_available` returns False for invalid device configurations.""" target = make_target(**kwargs) # ty: ignore[invalid-argument-type] assert not esp_data_available(target) + \ No newline at end of file From 86b6ae9eae07cba5b97a89e7b636a588d6c62604 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 17:36:40 +0000 Subject: [PATCH 95/98] =?UTF-8?q?=F0=9F=8E=A8=20pre-commit=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/compilation/test_reward.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/compilation/test_reward.py b/tests/compilation/test_reward.py index e1a2bdafc..5e36fcc8a 100644 --- a/tests/compilation/test_reward.py +++ b/tests/compilation/test_reward.py @@ -132,4 +132,3 @@ def test_esp_data_available_invalid_target(kwargs: dict[str, float | bool]) -> N """Test that `esp_data_available` returns False for invalid device configurations.""" target = make_target(**kwargs) # ty: ignore[invalid-argument-type] assert not esp_data_available(target) - \ No newline at end of file From c40c0bd999e1260e7542b715942c1a98b8f46784 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Sun, 15 Feb 2026 11:37:17 +0100 Subject: [PATCH 96/98] Fix layout issue --- pyproject.toml | 2 -- src/mqt/predictor/rl/predictorenv.py | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d1260c740..b9ca7c52d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,8 +33,6 @@ dependencies = [ "qiskit>=1.3.3", "pytket>=1.29.0", # lowest version that supports the used pytket AutoRebase pass instead of auto_rebase "pytket_qiskit>=0.71.0", - # TODO(denialhaag): Remove once pytket_qiskit is updated - # https://github.com/munich-quantum-toolkit/predictor/issues/471 "qiskit-ibm-runtime>=0.30.0,<0.42.0", "sb3_contrib>=2.0.0", "stable-baselines3>=2.7.0", diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 024833709..25273050e 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -493,8 +493,8 @@ def _handle_qiskit_layout_postprocessing( layout = pm_property_set.get("layout") if layout is not None: - orig = pm_property_set["original_qubit_indices"] - final = pm_property_set["final_layout"] + orig = pm_property_set.get("original_qubit_indices") + final = pm_property_set.get("final_layout") self.layout = TranspileLayout( initial_layout=layout, From 22c044ebf72b4f638c471bb183ddfbca0954f185 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Sun, 15 Feb 2026 11:54:20 +0100 Subject: [PATCH 97/98] Fix fom tests --- tests/compilation/test_predictor_rl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index 9ed903558..5e873b5a6 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -147,7 +147,7 @@ def test_fom_aware_compile_fallback(monkeypatch: MonkeyPatch) -> None: monkeypatch.setattr( predictor.env, "calculate_reward", lambda _circ: (_ for _ in ()).throw(RuntimeError("fake error")) ) - compiled_qc, prop_set = predictor.env.fom_aware_compile(dummy_action, None, qc, max_iteration=1) + compiled_qc, prop_set = predictor.env.fom_aware_compile(dummy_action, predictor.env.device, qc, max_iteration=1) assert isinstance(compiled_qc, QuantumCircuit) assert isinstance(prop_set, dict) From 9cb8a168970ab4cffde1f5471cafab1a1bbda737 Mon Sep 17 00:00:00 2001 From: Zhou Shaobo Date: Sun, 15 Feb 2026 13:21:07 +0100 Subject: [PATCH 98/98] Bypass qiskit-ibm-transpiler warnings treated as errors --- noxfile.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 5a75d07e4..8fc966246 100755 --- a/noxfile.py +++ b/noxfile.py @@ -92,7 +92,13 @@ def _run_tests( @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, default=True) def tests(session: nox.Session) -> None: """Run the test suite.""" - _run_tests(session) + _run_tests( + session, + pytest_run_args=[ + r"-Wignore:invalid escape sequence '\\w':SyntaxWarning:qiskit_ibm_transpiler\..*", + r"-Wignore:\"is\" with a literal:SyntaxWarning:qiskit_ibm_transpiler\..*", + ], + ) @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True)