diff --git a/CHANGELOG.md b/CHANGELOG.md index 0488c742..0b81df38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,12 @@ This project adheres to [Semantic Versioning], with the exception that minor rel - ✨ 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**]) +- ✨ Improve RL reward design by adding intermediate rewards ([#526]) ([**@Shaobo-Zhou**]) - 🔧 Replace `mypy` with `ty` ([#572]) ([**@denialhaag**]) - 🐛 Fix instruction duration unit in estimated success probability calculation ([#445]) ([**@Shaobo-Zhou**]) + +### Removed + - ✨ Remove support for custom names of trained models ([#489]) ([**@bachase**]) - 🔥 Drop support for x86 macOS systems ([#421]) ([**@denialhaag**]) @@ -50,6 +54,7 @@ _📚 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 +[#526]: https://github.com/munich-quantum-toolkit/predictor/pull/526 [#489]: https://github.com/munich-quantum-toolkit/predictor/pull/489 [#445]: https://github.com/munich-quantum-toolkit/predictor/pull/445 [#421]: https://github.com/munich-quantum-toolkit/predictor/pull/421 diff --git a/docs/setup.md b/docs/setup.md index f0e83cd1..6d121831 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 5a75d07e..ba974846 100755 --- a/noxfile.py +++ b/noxfile.py @@ -92,7 +92,7 @@ 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=["-Wdefault"]) @nox.session(python=PYTHON_ALL_VERSIONS, reuse_venv=True, venv_backend="uv", default=True) diff --git a/pyproject.toml b/pyproject.toml index 33a06c5a..c2b8fb38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ dependencies = [ "pytket_qiskit>=0.65.0", "qiskit-ibm-runtime>=0.37.0", "sb3_contrib>=2.0.0", + "stable-baselines3>=2.7.0", "tqdm>=4.66.0", "rich>=12.6.0", "scikit-learn>=1.5.1", @@ -118,7 +119,13 @@ 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. 'error', + "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:', diff --git a/src/mqt/predictor/reward.py b/src/mqt/predictor/reward.py index a8cd7695..16512e14 100644 --- a/src/mqt/predictor/reward.py +++ b/src/mqt/predictor/reward.py @@ -23,6 +23,7 @@ if TYPE_CHECKING: from qiskit import QuantumCircuit + from qiskit.circuit import QuantumRegister, Qubit from qiskit.transpiler import Target from sklearn.ensemble import RandomForestRegressor @@ -61,22 +62,44 @@ def expected_fidelity(qc: QuantumCircuit, device: Target, precision: int = 10) - if gate_type != "barrier": assert len(qargs) in [1, 2] - first_qubit_idx = qc.find_bit(qargs[0]).index + first_qubit_idx = calc_qubit_index(qargs, qc.qregs, 0) if len(qargs) == 1: specific_fidelity = 1 - device[gate_type][first_qubit_idx,].error else: - second_qubit_idx = qc.find_bit(qargs[1]).index - try: - specific_fidelity = 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error - except KeyError: - msg = f"Error rate for gate {gate_type} on qubits {first_qubit_idx} and {second_qubit_idx} not found in device properties." - raise KeyError(msg) from None + second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) + specific_fidelity = 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error + res *= specific_fidelity return float(np.round(res, precision).item()) +def calc_qubit_index(qargs: list[Qubit], qregs: list[QuantumRegister], index: int) -> int: + """Calculates the global qubit index for a given quantum circuit and qubit index. + + Arguments: + qargs: The qubits of the quantum circuit. + qregs: The quantum registers of the quantum circuit. + index: The index of the qubit in the qargs list. + + Returns: + The global qubit index of the given qubit in the quantum circuit. + + Raises: + ValueError: If the qubit index is not found in the quantum registers. + """ + offset = 0 + for reg in qregs: + if qargs[index] not in reg: + offset += reg.size + else: + qubit_index: int = offset + reg.index(qargs[index]) + return qubit_index + error_msg = f"Global qubit index for local qubit {index} index not found." + raise ValueError(error_msg) + + def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: int = 10) -> float: """Calculates the estimated success probability of a given quantum circuit on a given device. @@ -102,7 +125,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: if gate_type == "barrier" or gate_type == "id": continue assert len(qargs) in (1, 2) - first_qubit_idx = qc.find_bit(qargs[0]).index + first_qubit_idx = calc_qubit_index(qargs, qc.qregs, 0) active_qubits.add(first_qubit_idx) if len(qargs) == 1: # single-qubit gate @@ -117,7 +140,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: )) exec_time_per_qubit[first_qubit_idx] += duration else: # multi-qubit gate - second_qubit_idx = qc.find_bit(qargs[1]).index + 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 op_times.append((gate_type, [first_qubit_idx, second_qubit_idx], duration, "s")) @@ -168,7 +191,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: continue assert len(qargs) in (1, 2) - first_qubit_idx = scheduled_circ.find_bit(qargs[0]).index + first_qubit_idx = calc_qubit_index(qargs, qc.qregs, 0) if len(qargs) == 1: if gate_type == "measure": @@ -181,7 +204,7 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: if first_qubit_idx not in active_qubits: continue - dt = device.dt # instruction durations are stored in unit dt + dt = device.dt or 1.0 # discrete time unit; fallback to 1.0 if unavailable res *= np.exp( -instruction.duration * dt @@ -189,8 +212,9 @@ def estimated_success_probability(qc: QuantumCircuit, device: Target, precision: ) continue res *= 1 - device[gate_type][first_qubit_idx,].error + else: - second_qubit_idx = scheduled_circ.find_bit(qargs[1]).index + second_qubit_idx = calc_qubit_index(qargs, qc.qregs, 1) res *= 1 - device[gate_type][first_qubit_idx, second_qubit_idx].error if qiskit_version >= "2.0.0": diff --git a/src/mqt/predictor/rl/approx_reward.py b/src/mqt/predictor/rl/approx_reward.py new file mode 100644 index 00000000..95f237d5 --- /dev/null +++ b/src/mqt/predictor/rl/approx_reward.py @@ -0,0 +1,241 @@ +# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM +# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +"""This module provides helper functions to approximate expected fidelity and estimated success probability (ESP) by transpiling a circuit to a device's basis gate set and combining resulting gate counts with calibration-derived per-gate error rates and durations.""" + +from __future__ import annotations + +from contextlib import suppress +from typing import TYPE_CHECKING + +import numpy as np +from qiskit import transpile + +if TYPE_CHECKING: + from qiskit import QuantumCircuit + from qiskit.transpiler import InstructionProperties, Target + +BLACKLIST: set[str] = {"measure", "reset", "delay", "barrier"} # These gates do not directly contribute to the error + + +def get_basis_gates_from_target(device: Target) -> list[str]: + """Return the basis gate names from a Qiskit Target.""" + return sorted([g for g in device.operation_names if g not in BLACKLIST]) + + +def estimate_basis_gate_counts(qc: QuantumCircuit, *, basis_gates: list[str]) -> dict[str, int]: + """Transpile ``qc`` to ``basis_gates`` and count occurrences of each basis gate.""" + qc_t = transpile(qc, basis_gates=basis_gates, optimization_level=1, seed_transpiler=42) + counts = dict.fromkeys(basis_gates, 0) + for ci in qc_t.data: + name = ci.operation.name + if name in BLACKLIST: + continue + if name in counts: + counts[name] += 1 + return counts + + +def approx_expected_fidelity( + qc: QuantumCircuit, + *, + device: Target, + error_rates: dict[str, float], +) -> float: + """Approximate expected fidelity using per-basis-gate error rates. + + The circuit is first transpiled to the device basis. Then a simple product + model is applied: Π_g (1 - p_g)^{count_g}. + + Args: + qc: Circuit to evaluate. + device: Target providing the basis gate set. + error_rates: Mapping ``basis_gate: g -> error_probability: p_g``. + + Returns: + Approximate fidelity in [0, 1]. + """ + basis = get_basis_gates_from_target(device) + counts = estimate_basis_gate_counts(qc, basis_gates=basis) + f = 1.0 + for g, c in counts.items(): + f *= (1.0 - error_rates.get(g, 0.0)) ** c + return float(max(min(f, 1.0), 0.0)) + + +def approx_estimated_success_probability( + qc: QuantumCircuit, + *, + device: Target, + error_rates: dict[str, float], + gate_durations: dict[str, float], + tbar: float | None, + par_feature: float, + liv_feature: float, + n_qubits: int, +) -> float: + """Approximate ESP using per-basis-gate error rates, durations, and coherence. + + This combines: + (1) a gate-infidelity product term, and + (2) an idle/decoherence penalty based on an effective circuit duration. + + Args: + qc: Circuit to evaluate. + device: Target providing the basis gate set. + error_rates: Mapping ``basis_gate -> error_probability``. + gate_durations: Mapping ``basis_gate -> duration`` (seconds). + tbar: Representative coherence time (seconds). If None, idle penalty is skipped. + par_feature: Parallelism feature in [0, 1]. + liv_feature: Liveness feature in [0, 1]. + n_qubits: Number of qubits in the circuit. + + Returns: + Approximate ESP in [0, 1]. + """ + basis = get_basis_gates_from_target(device) + counts = estimate_basis_gate_counts(qc, basis_gates=basis) + + f_gate = 1.0 + for g, c in counts.items(): + f_gate *= (1.0 - error_rates.get(g, 0.0)) ** c + + n_q = max(n_qubits, 1) + k_eff = 1.0 + (n_q - 1.0) * float(par_feature) + + total_gate_time = sum(counts[g] * gate_durations.get(g, 0.0) for g in basis) / k_eff + + idle_fraction = max(0.0, 1.0 - float(liv_feature)) + idle_factor = 1.0 if tbar is None or tbar <= 0.0 else float(np.exp(-(total_gate_time * idle_fraction) / tbar)) + + esp = f_gate * idle_factor + return float(max(min(esp, 1.0), 0.0)) + + +def compute_device_averages_from_target( + device: Target, +) -> tuple[dict[str, float], dict[str, float], float | None]: + """Compute per-basis-gate averages for error, duration, and a coherence scale. + + Computes and returns: + - error_rates: dict[basis_gate -> mean error probability] + - gate_durations: dict[basis_gate -> mean duration (seconds)] + - tbar: median over qubits of min(T1, T2) (seconds) if available, else None + + Raises: + RuntimeError: if required Target API is missing or if no calibration data exists. + """ + # ---- Hard requirements ------------------------------------------------------- + try: + num_qubits = device.num_qubits + op_names = list(device.operation_names) + coupling_map = device.build_coupling_map() + qubit_props = device.qubit_properties + except AttributeError as exc: + msg = "Device target does not expose the required Target API for approximate reward computation." + raise RuntimeError(msg) from exc + + basis_ops = [name for name in op_names if name not in BLACKLIST] + twoq_edges = coupling_map.get_edges() # list[tuple[int, int]] + + # ---- Helpers ---------------------------------------------------------------- + def _get_props(name: str, qargs: tuple[int, ...]) -> InstructionProperties | None: + """Return calibration properties for (name, qargs) or None if unavailable.""" + with suppress(KeyError): + return device[name].get(qargs, None) + return None + + def _infer_arity(name: str) -> int | None: + """Infer operation arity from Target (best effort).""" + # Preferred: operation_from_name + with suppress(AttributeError, KeyError, TypeError): + op = device.operation_from_name(name) + return int(op.num_qubits) + + # Fallback: infer from any qargs key in device[name] + with suppress(KeyError, TypeError): + props_map = device[name] + for qargs in props_map: + return len(qargs) + return None + + # ---- Accumulate raw samples -------------------------------------------------- + err_samples: dict[str, list[float]] = {name: [] for name in basis_ops} + dur_samples: dict[str, list[float]] = {name: [] for name in basis_ops} + + arity_by_name: dict[str, int] = {} + for name in basis_ops: + arity = _infer_arity(name) + if arity is not None: + arity_by_name[name] = arity + + # ---- Aggregate error/duration per gate -------------------------------------- + for name in basis_ops: + arity = arity_by_name.get(name) + if arity is None: + continue + + if arity == 1: + for q in range(num_qubits): + props = _get_props(name, (q,)) + if props is None: + continue + err = getattr(props, "error", None) + if err is not None: + err_samples[name].append(float(err)) + dur = getattr(props, "duration", None) + if dur is not None: + dur_samples[name].append(float(dur)) + + elif arity == 2: + for i, j in twoq_edges: + props = _get_props(name, (i, j)) + if props is None: + props = _get_props(name, (j, i)) # flipped orientation + if props is None: + continue + err = getattr(props, "error", None) + if err is not None: + err_samples[name].append(float(err)) + dur = getattr(props, "duration", None) + if dur is not None: + dur_samples[name].append(float(dur)) + + else: + # Ignore gates with arity > 2 + continue + + # ---- Global fallbacks -------------------------------------------------------- + all_err = [x for xs in err_samples.values() for x in xs] + all_dur = [x for xs in dur_samples.values() for x in xs] + + if not all_err and not all_dur: + msg = "No valid calibration data found in Target, cannot compute approximate reward." + raise RuntimeError(msg) + + global_err = float(np.mean(all_err)) if all_err else 0.0 + global_dur = float(np.mean(all_dur)) if all_dur else 0.0 + + error_rates = {name: (float(np.mean(vals)) if vals else global_err) for name, vals in err_samples.items()} + gate_durations = {name: (float(np.mean(vals)) if vals else global_dur) for name, vals in dur_samples.items()} + + # ---- Coherence scale --------------------------------------------------------- + tmins: list[float] = [] + if qubit_props: + for i in range(num_qubits): + props = qubit_props[i] + if props is None: + continue + t1v = getattr(props, "t1", None) + t2v = getattr(props, "t2", None) + vals = [v for v in (t1v, t2v) if v is not None] + if vals: + tmins.append(float(min(vals))) + + tbar = float(np.median(tmins)) if tmins else None + return error_rates, gate_durations, tbar diff --git a/src/mqt/predictor/rl/predictor.py b/src/mqt/predictor/rl/predictor.py index 1f75b190..2654f34f 100644 --- a/src/mqt/predictor/rl/predictor.py +++ b/src/mqt/predictor/rl/predictor.py @@ -99,12 +99,11 @@ def train_model( """ if test: set_random_seed(0) # for reproducibility - n_steps = 32 - n_epochs = 2 - batch_size = 8 + n_steps = 10 + n_epochs = 1 + batch_size = 10 progress_bar = False else: - set_random_seed(0) # default PPO values n_steps = 2048 n_epochs = 10 diff --git a/src/mqt/predictor/rl/predictorenv.py b/src/mqt/predictor/rl/predictorenv.py index 9936e8ec..64d963f0 100644 --- a/src/mqt/predictor/rl/predictorenv.py +++ b/src/mqt/predictor/rl/predictorenv.py @@ -21,7 +21,7 @@ from pytket._tket.passes import BasePass as TketBasePass from pytket.circuit import Node from qiskit.passmanager.base_tasks import Task - from qiskit.transpiler import Layout, Target + from qiskit.transpiler import Target from mqt.predictor.reward import figure_of_merit from mqt.predictor.rl.actions import Action @@ -31,6 +31,7 @@ import warnings +from math import isclose from typing import cast import numpy as np @@ -49,8 +50,10 @@ from qiskit.transpiler.passes import ( ApplyLayout, BasisTranslator, + CheckMap, EnlargeWithAncilla, FullAncillaAllocation, + GatesInBasis, SetLayout, ) from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason @@ -69,6 +72,11 @@ PassType, get_actions_by_pass_type, ) +from mqt.predictor.rl.approx_reward import ( + approx_estimated_success_probability, + approx_expected_fidelity, + compute_device_averages_from_target, +) from mqt.predictor.rl.helper import ( create_feature_dict, get_path_training_circuits, @@ -80,7 +88,7 @@ postprocess_vf2postlayout, prepare_noise_data, ) -from mqt.predictor.utils import get_openqasm_gates_for_rl +from mqt.predictor.utils import calc_supermarq_features, get_openqasm_gates_for_rl logger = logging.getLogger("mqt-predictor") @@ -94,6 +102,8 @@ def __init__( mdp: str = "paper", reward_function: figure_of_merit = "expected_fidelity", path_training_circuits: Path | None = None, + reward_scale: float = 1.0, + no_effect_penalty: float = -0.001, ) -> None: """Initializes the PredictorEnv object. @@ -102,6 +112,8 @@ def __init__( mdp: The MDP transition policy. "paper" (default) enforces a strict, linear pipeline (synthesis -> (layout->routing) / mapping), while "flexible" allows for a cyclical approach where actions can be interleaved or reversed. reward_function: The figure of merit to be used for the reward function. Defaults to "expected_fidelity". path_training_circuits: The path to the training circuits folder. Defaults to None, which uses the default path. + reward_scale: Scaling factor for rewards/penalties proportional to fidelity changes. + no_effect_penalty: Step penalty applied when an action does not change the circuit (no-op). Raises: ValueError: If the reward function is "estimated_success_probability" and no calibration data is available for the device or if the reward function is "estimated_hellinger_distance" and no trained model is available for the device. @@ -200,65 +212,182 @@ def __init__( 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 + self.reward_scale = reward_scale + self.no_effect_penalty = no_effect_penalty + self.prev_reward: float | None = None + self.prev_reward_kind: str | None = None + self._err_by_gate: dict[str, float] = {} + self._dur_by_gate: dict[str, float] = {} + self._tbar: float | None = None + self._dev_avgs_cached = False + self.state: QuantumCircuit = QuantumCircuit() - 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. - - Arguments: - action: The action to be executed, represented by its index in the action set. - - Returns: - A tuple containing the new state as a feature dictionary, the reward value, whether the episode is done, whether the episode is truncated, and additional information. + self.error_occurred = False - Raises: - RuntimeError: If no valid actions are left. - """ - self.used_actions.append(str(self.action_set[action].name)) + def _apply_and_update(self, action: int) -> QuantumCircuit | None: + """Apply an action, normalize the circuit, and update internal state.""" altered_qc = self.apply_action(action) - if not altered_qc: - return ( - create_feature_dict(self.state), - 0, - True, - False, - {}, - ) + if altered_qc is None: + return None self.state: QuantumCircuit = altered_qc self.num_steps += 1 - self.state._layout = self.layout # noqa: SLF001 - self.valid_actions = self.determine_valid_actions_for_state() - if len(self.valid_actions) == 0: + if not self.valid_actions: msg = "No valid actions left." raise RuntimeError(msg) - if action == self.action_terminate_index: + return altered_qc + + def step(self, action: int) -> tuple[dict[str, Any], float, bool, bool, dict[Any, Any]]: + """Run one environment step. + + This method: + 1. Evaluates the current circuit with the configured reward function + (using either the exact or approximate metric, depending on state). + 2. Applies the selected transpiler pass (the action). + 3. Computes a shaped step reward based on the change in the figure of merit. + + Reward design: + - For non-terminal actions, the step reward is a scaled delta between + the new and previous reward (plus an optional step penalty). + - For the terminate action, the episode ends and the final reward is + the exact (calibration-aware) metric. + """ + self.used_actions.append(str(self.action_set[action].name)) + logger.info("Applying %s", self.action_set[action].name) + + altered_qc = self._apply_and_update(action) + if altered_qc is None: + return create_feature_dict(self.state), 0.0, True, False, {} + + done = action == self.action_terminate_index + + if self.reward_function == "estimated_hellinger_distance": + reward_val = self.calculate_reward(mode="exact")[0] if done else 0.0 + self.state._layout = self.layout # noqa: SLF001 + return create_feature_dict(self.state), reward_val, done, False, {} + + # Lazy init: compute prev_reward only once per episode (or if missing) + if self.prev_reward is None: + self.prev_reward, self.prev_reward_kind = self.calculate_reward(mode="auto") + + if done: assert action in self.valid_actions, "Terminate action is not valid but was chosen." - reward_val = self.calculate_reward() - done = True + self.prev_reward, self.prev_reward_kind = self.calculate_reward(mode="exact") + reward_val = self.prev_reward else: - reward_val = 0 - done = False + new_val, new_kind = self.calculate_reward(mode="auto") + delta_reward = new_val - self.prev_reward + + if self.prev_reward_kind != new_kind: + delta_reward = 0.0 + + reward_val = ( + self.reward_scale * delta_reward + if not isclose(delta_reward, 0.0, abs_tol=1e-12) + else self.no_effect_penalty + ) + self.prev_reward, self.prev_reward_kind = new_val, new_kind obs = create_feature_dict(self.state) return obs, reward_val, done, False, {} - def calculate_reward(self, qc: QuantumCircuit | None = None) -> float: - """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 + def calculate_reward(self, qc: QuantumCircuit | None = None, mode: str = "auto") -> tuple[float, str]: + """Compute the reward for a circuit and report whether it was computed exactly or approximately. + + This environment supports two evaluation regimes for selected figures of merit: + + - **Exact**: uses the calibration-aware implementation on the full circuit/device + (e.g., uses the device Target calibration data as-is). + - **Approximate**: uses a transpile-based proxy: + the circuit is transpiled to the device's basis gates and the resulting basis-gate + counts are combined with cached **per-basis-gate** calibration statistics + (error rates and durations) to estimate the metric. This approximation ignores + additional mapping/routing overhead beyond what is reflected in the transpiled + basis-gate counts. + + Args: + qc: + Circuit to evaluate. If ``None``, evaluates the environment's current state. + mode: + Selects how the method chooses between exact and approximate evaluation: + + - ``"auto"`` (default): compute the exact metric if the circuit is already + **native and mapped** for the device; otherwise compute the approximate metric. + - ``"exact"``: always compute the exact, calibration-aware metric. + - ``"approx"``: always compute the approximate, transpile-based proxy. + + Returns: + A pair ``(value, kind)`` where: + + - ``value`` is the scalar reward value (typically in ``[0, 1]`` for EF/ESP). + - ``kind`` is ``"exact"`` or ``"approx"`` indicating which regime was used. + """ + if qc is None: + qc = self.state + + # Reward functions that are always computed exactly. + if self.reward_function not in {"expected_fidelity", "estimated_success_probability"}: + if self.reward_function == "critical_depth": + return crit_depth(qc), "exact" + if self.reward_function == "estimated_hellinger_distance": + return estimated_hellinger_distance(qc, self.device, self.hellinger_model), "exact" + # Fallback for other unknown / not-yet-implemented reward functions: + logger.warning( + "Reward function '%s' is not supported in PredictorEnv. Returning 0.0 as a fallback reward.", + self.reward_function, + ) + return 0.0, "exact" + + # Dual-path evaluation (exact vs. approximate) for EF / ESP. + if mode == "exact": + kind = "exact" + elif mode == "approx": + kind = "approx" + else: # "auto" + check_nat_gates = GatesInBasis(basis_gates=self.device.operation_names) + check_nat_gates(qc) + only_native = bool(check_nat_gates.property_set["all_gates_in_basis"]) + + check_mapping = CheckMap(coupling_map=self.device.build_coupling_map()) + check_mapping(qc) + mapped = bool(check_mapping.property_set["is_swap_mapped"]) + + kind = "exact" if (only_native and mapped) else "approx" + + if kind == "exact": + if self.reward_function == "expected_fidelity": + return expected_fidelity(qc, self.device), "exact" + + return estimated_success_probability(qc, self.device), "exact" + + # Approximate metrics use per-basis-gate averages cached from device calibration + self._ensure_device_averages_cached() + 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(self.state) - msg = f"No implementation for reward function {self.reward_function}." - raise NotImplementedError(msg) + val = approx_expected_fidelity( + qc, + device=self.device, + error_rates=self._err_by_gate, + ) + return val, "approx" + + feats = calc_supermarq_features(qc) + + val = approx_estimated_success_probability( + qc, + device=self.device, + error_rates=self._err_by_gate, + gate_durations=self._dur_by_gate, + tbar=self._tbar, + par_feature=float(feats.parallelism), + liv_feature=float(feats.liveness), + n_qubits=int(qc.num_qubits), + ) + return val, "approx" def render(self) -> None: """Renders the current state.""" @@ -285,7 +414,7 @@ def reset( if isinstance(qc, QuantumCircuit): self.state = qc elif qc: - self.state = QuantumCircuit.from_qasm_file(qc) # ty: ignore[invalid-argument-type] + self.state = QuantumCircuit.from_qasm_file(str(qc)) else: self.state, self.filename = get_state_sample(self.device.num_qubits, self.path_training_circuits, self.rng) @@ -307,6 +436,9 @@ def reset( self.error_occurred = False + self.prev_reward = None + self.prev_reward_kind = None + self.num_qubits_uncompiled_circuit = self.state.num_qubits self.has_parameterized_gates = len(self.state.parameters) > 0 @@ -316,9 +448,8 @@ 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] - # TKET layout/optimization actions must not run after a Qiskit layout has been set - # (it is not clear how tket will handle the layout). TKET routing actions are - # designed to work after a Qiskit layout via PreProcessTKETRoutingAfterQiskitLayout. + # TKET layout/optimization actions must not run after a Qiskit layout has been set. + # TKET routing actions are explicitly supported through preprocessing. if self.layout is not None: action_mask = [ action_mask[i] @@ -414,7 +545,7 @@ def fom_aware_compile( BasisTranslator(StandardEquivalenceLibrary, target_basis=device.operation_names) ]) synth_circ = synth_pass.run(out_circ.copy()) - fom = self.calculate_reward(synth_circ) + fom, _ = self.calculate_reward(synth_circ) if fom > best_fom: best_fom = fom @@ -486,7 +617,6 @@ def _apply_qiskit_action(self, action: Action, action_index: int) -> QuantumCirc altered_qc = altered_qc.decompose(gates_to_decompose="unitary") elif altered_qc.count_ops().get("clifford"): # ty: ignore[invalid-argument-type] altered_qc = altered_qc.decompose(gates_to_decompose="clifford") - return altered_qc def _handle_qiskit_layout_postprocessing( @@ -709,13 +839,11 @@ def determine_valid_actions_for_state(self) -> list[int]: """Determine valid actions based on circuit state: synthesized, mapped, routed.""" synthesized = self.is_circuit_synthesized(self.state) laid_out = self.is_circuit_laid_out(self.state, self.layout) if self.layout else False - # Routing is only allowed after layout routed = ( self.is_circuit_routed(self.state, CouplingMap(self.device.build_coupling_map())) if laid_out else False ) actions = [] - # Initial state if not synthesized and not laid_out and not routed: if self.mdp == "flexible": @@ -794,3 +922,15 @@ def determine_valid_actions_for_state(self) -> list[int]: actions.extend(self.actions_final_optimization_indices) return actions + + def _ensure_device_averages_cached(self) -> None: + """Cache per-basis-gate averages for error, duration, and a coherence scale.""" + if self._dev_avgs_cached: + return + + err_by_gate, dur_by_gate, tbar = compute_device_averages_from_target(self.device) + + self._err_by_gate = err_by_gate + self._dur_by_gate = dur_by_gate + self._tbar = tbar + self._dev_avgs_cached = True diff --git a/tests/compilation/test_approx_reward.py b/tests/compilation/test_approx_reward.py new file mode 100644 index 00000000..0a7858b1 --- /dev/null +++ b/tests/compilation/test_approx_reward.py @@ -0,0 +1,187 @@ +# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM +# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH +# All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# Licensed under the MIT License + +"""Tests for approximate reward helper functions.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING, cast + +import pytest + +from mqt.predictor.rl.approx_reward import compute_device_averages_from_target + +if TYPE_CHECKING: + from qiskit.transpiler import Target + + +@dataclass +class FakeInstructionProperties: + """Minimal stand-in for Qiskit's InstructionProperties.""" + + error: float | None = None + duration: float | None = None + + +@dataclass +class FakeQubitProperties: + """Minimal stand-in for Qiskit's QubitProperties.""" + + t1: float | None = None + t2: float | None = None + + +@dataclass +class FakeOperation: + """Minimal operation object exposing `num_qubits`.""" + + num_qubits: int + + +class FakeCouplingMap: + """Minimal coupling map exposing directed edges.""" + + def __init__(self, edges: list[tuple[int, int]]) -> None: + """Store directed coupling edges.""" + self._edges = edges + + def get_edges(self) -> list[tuple[int, int]]: + """Return directed coupling edges.""" + return self._edges + + +class FakeTarget: + """Minimal Target-like object for testing branch behavior.""" + + def __init__( + self, + *, + num_qubits: int, + operation_names: list[str], + op_props: dict[str, dict[tuple[int, ...], FakeInstructionProperties]], + arities: dict[str, int], + edges: list[tuple[int, int]], + qubit_properties: list[FakeQubitProperties | None] | None, + operation_from_name_raises_for: set[str] | None = None, + ) -> None: + """Initialize operation data, arities, connectivity, and qubit properties.""" + self.num_qubits = num_qubits + self.operation_names = operation_names + self._op_props = op_props + self._arities = arities + self._edges = edges + self.qubit_properties = qubit_properties + self._operation_from_name_raises_for = operation_from_name_raises_for or set() + + def build_coupling_map(self) -> FakeCouplingMap: + """Return a minimal coupling map.""" + return FakeCouplingMap(self._edges) + + def operation_from_name(self, name: str) -> FakeOperation: + """Return operation metadata or raise to trigger fallback inference.""" + if name in self._operation_from_name_raises_for: + msg = f"Operation {name} metadata unavailable." + raise KeyError(msg) + return FakeOperation(num_qubits=self._arities[name]) + + def __getitem__(self, name: str) -> dict[tuple[int, ...], FakeInstructionProperties]: + """Return calibration map for an operation.""" + return self._op_props[name] + + +def test_compute_device_averages_nominal_path() -> None: + """Compute per-gate means and qubit coherence median on a nominal target.""" + target = FakeTarget( + num_qubits=2, + operation_names=["measure", "x", "cx"], # measure should be ignored + op_props={ + "x": { + (0,): FakeInstructionProperties(error=0.1, duration=10.0), + (1,): FakeInstructionProperties(error=0.3, duration=30.0), + }, + "cx": { + (0, 1): FakeInstructionProperties(error=0.4, duration=40.0), + }, + }, + arities={"x": 1, "cx": 2}, + edges=[(0, 1)], + qubit_properties=[ + FakeQubitProperties(t1=100.0, t2=50.0), # min = 50 + FakeQubitProperties(t1=200.0, t2=None), # min = 200 + ], + ) + + err_by_gate, dur_by_gate, tbar = compute_device_averages_from_target(cast("Target", target)) + + assert err_by_gate == {"x": pytest.approx(0.2), "cx": pytest.approx(0.4)} + assert dur_by_gate == {"x": pytest.approx(20.0), "cx": pytest.approx(40.0)} + assert tbar == pytest.approx(125.0) + + +def test_compute_device_averages_fallbacks_are_used() -> None: + """Use orientation fallback, arity fallback, and global per-gate fallback.""" + target = FakeTarget( + num_qubits=2, + operation_names=["x", "cx", "rz"], + op_props={ + "x": { + (0,): FakeInstructionProperties(error=0.1, duration=10.0), + (1,): FakeInstructionProperties(error=0.3, duration=30.0), + }, + # Only reverse orientation is available; edge scan uses (0, 1) + "cx": { + (1, 0): FakeInstructionProperties(error=0.2, duration=20.0), + }, + # No data for rz; should get global fallback values + "rz": { + (0,): FakeInstructionProperties(error=None, duration=None), + (1,): FakeInstructionProperties(error=None, duration=None), + }, + }, + arities={"x": 1, "cx": 2, "rz": 1}, + edges=[(0, 1)], + qubit_properties=None, + # Force arity fallback for "cx" by raising in operation_from_name + operation_from_name_raises_for={"cx"}, + ) + + err_by_gate, dur_by_gate, tbar = compute_device_averages_from_target(cast("Target", target)) + + # all available samples are 0.1, 0.3, 0.2 for error and 10, 30, 20 for duration + assert err_by_gate["rz"] == pytest.approx(0.2) + assert dur_by_gate["rz"] == pytest.approx(20.0) + assert err_by_gate["cx"] == pytest.approx(0.2) + assert dur_by_gate["cx"] == pytest.approx(20.0) + assert tbar is None + + +def test_compute_device_averages_missing_target_api_raises() -> None: + """Raise a clear RuntimeError if the object is not Target-compatible.""" + with pytest.raises(RuntimeError, match="required Target API"): + compute_device_averages_from_target(cast("Target", object())) + + +def test_compute_device_averages_without_calibration_data_raises() -> None: + """Raise if calibration data contains neither error nor duration samples.""" + target = FakeTarget( + num_qubits=2, + operation_names=["x"], + op_props={ + "x": { + (0,): FakeInstructionProperties(error=None, duration=None), + (1,): FakeInstructionProperties(error=None, duration=None), + } + }, + arities={"x": 1}, + edges=[], + qubit_properties=[None, None], + ) + + with pytest.raises(RuntimeError, match="No valid calibration data found in Target"): + compute_device_averages_from_target(cast("Target", target)) diff --git a/tests/compilation/test_integration_further_SDKs.py b/tests/compilation/test_integration_further_SDKs.py index 150363ea..9aa33bb6 100644 --- a/tests/compilation/test_integration_further_SDKs.py +++ b/tests/compilation/test_integration_further_SDKs.py @@ -241,7 +241,7 @@ def test_tket_routing(available_actions_dict: dict[PassType, list[Action]]) -> N qubit_map = {qbs[i]: Qubit("q", i) for i in range(len(qbs))} tket_qc.rename_units(qubit_map) - mapped_qc = tk_to_qiskit(tket_qc, replace_implicit_swaps=True) + mapped_qc = tk_to_qiskit(tket_qc) final_layout = final_layout_pytket_to_qiskit(tket_qc, mapped_qc) diff --git a/tests/compilation/test_predictor_rl.py b/tests/compilation/test_predictor_rl.py index a36e32da..8f847473 100644 --- a/tests/compilation/test_predictor_rl.py +++ b/tests/compilation/test_predictor_rl.py @@ -38,13 +38,15 @@ if TYPE_CHECKING: from _pytest.monkeypatch import MonkeyPatch + from mqt.predictor.reward import figure_of_merit + 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.""" 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) @@ -77,6 +79,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) + predictor = Predictor(figure_of_merit=figure_of_merit, device=device) model_name = "model_" + figure_of_merit + "_" + device.description @@ -91,7 +94,7 @@ def test_qcompile_with_newly_trained_models() -> None: rl_compile(qc, device=device, figure_of_merit=figure_of_merit) predictor.train_model( - timesteps=1000, + timesteps=100, test=True, ) @@ -112,7 +115,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.")): @@ -198,3 +201,35 @@ 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") + + +@pytest.mark.parametrize( + "fom", + ["expected_fidelity", "estimated_success_probability"], +) +def test_approx_reward_paths_use_cached_per_gate_maps(fom: figure_of_merit) -> None: + """Ensure approx reward path runs and uses cached per-basis-gate calibration maps. + + We don't test exact numeric values (backend-dependent), only that: + - approx path runs, + - cached maps are populated, + - output is a valid probability in [0, 1]. + """ + qc = get_benchmark("ghz", BenchmarkLevel.INDEP, 3) + device = get_device("ibm_heron_133") + predictor = Predictor(figure_of_merit=fom, device=device) + + val, kind = predictor.env.calculate_reward(qc=qc, mode="approx") + assert kind == "approx" + assert 0.0 <= val <= 1.0 + + # Ensure caching produced per-gate mappings + assert predictor.env._dev_avgs_cached # noqa: SLF001 + assert isinstance(predictor.env._err_by_gate, dict) # noqa: SLF001 + assert isinstance(predictor.env._dur_by_gate, dict) # noqa: SLF001 + assert len(predictor.env._err_by_gate) > 0 # noqa: SLF001 + + if fom == "estimated_success_probability": + assert len(predictor.env._dur_by_gate) > 0 # noqa: SLF001 + # tbar is optional depending on backend calibration; just sanity-check type + assert predictor.env._tbar is None or predictor.env._tbar > 0.0 # noqa: SLF001 diff --git a/tests/device_selection/test_predictor_ml.py b/tests/device_selection/test_predictor_ml.py index db07cd1c..32bbf6f8 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.") ): diff --git a/uv.lock b/uv.lock index 8320148a..cde1864e 100644 --- a/uv.lock +++ b/uv.lock @@ -55,14 +55,14 @@ name = "aiohttp" version = "3.13.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, + { name = "aiohappyeyeballs", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "aiosignal", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, + { name = "attrs", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "frozenlist", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "multidict", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "propcache", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "yarl", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } wheels = [ @@ -175,7 +175,7 @@ name = "aiohttp-cors" version = "0.8.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp" }, + { name = "aiohttp", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] 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 = [ @@ -187,7 +187,7 @@ name = "aiosignal" version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "frozenlist" }, + { name = "frozenlist", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, { 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" } @@ -555,7 +555,7 @@ name = "colorful" version = "0.5.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version != '3.13.*' and 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 = [ @@ -1323,11 +1323,11 @@ name = "google-api-core" version = "2.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "google-auth" }, - { name = "googleapis-common-protos" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "requests" }, + { name = "google-auth", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "googleapis-common-protos", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "proto-plus", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "protobuf", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "requests", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/22/98/586ec94553b569080caef635f98a3723db36a38eac0e3d7eb3ea9d2e4b9a/google_api_core-2.30.0.tar.gz", hash = "sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b", size = 176959, upload-time = "2026-02-18T20:28:11.926Z" } wheels = [ @@ -1339,9 +1339,9 @@ name = "google-auth" version = "2.49.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography" }, - { name = "pyasn1-modules" }, - { name = "rsa" }, + { name = "cryptography", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "pyasn1-modules", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "rsa", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/59/7371175bfd949abfb1170aa076352131d7281bd9449c0f978604fc4431c3/google_auth-2.49.0.tar.gz", hash = "sha256:9cc2d9259d3700d7a257681f81052db6737495a1a46b610597f4b8bafe5286ae", size = 333444, upload-time = "2026-03-06T21:53:06.07Z" } wheels = [ @@ -1353,7 +1353,7 @@ name = "googleapis-common-protos" version = "1.73.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "protobuf" }, + { name = "protobuf", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/99/96/a0205167fa0154f4a542fd6925bdc63d039d88dab3588b875078107e6f06/googleapis_common_protos-1.73.0.tar.gz", hash = "sha256:778d07cd4fbeff84c6f7c72102f0daf98fa2bfd3fa8bea426edc545588da0b5a", size = 147323, upload-time = "2026-03-06T21:53:09.727Z" } wheels = [ @@ -1378,6 +1378,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/3f/9859f655d11901e7b2996c6e3d33e0caa9a1d4572c3bc61ed0faa64b2f4c/greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d", size = 277747, upload-time = "2026-02-20T20:16:21.325Z" }, { url = "https://files.pythonhosted.org/packages/fb/07/cb284a8b5c6498dbd7cba35d31380bb123d7dceaa7907f606c8ff5993cbf/greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13", size = 579202, upload-time = "2026-02-20T20:47:28.955Z" }, { url = "https://files.pythonhosted.org/packages/ed/45/67922992b3a152f726163b19f890a85129a992f39607a2a53155de3448b8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e", size = 590620, upload-time = "2026-02-20T20:55:55.581Z" }, + { url = "https://files.pythonhosted.org/packages/03/5f/6e2a7d80c353587751ef3d44bb947f0565ec008a2e0927821c007e96d3a7/greenlet-3.3.2-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7", size = 602132, upload-time = "2026-02-20T21:02:43.261Z" }, { url = "https://files.pythonhosted.org/packages/ad/55/9f1ebb5a825215fadcc0f7d5073f6e79e3007e3282b14b22d6aba7ca6cb8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f", size = 591729, upload-time = "2026-02-20T20:20:58.395Z" }, { url = "https://files.pythonhosted.org/packages/24/b4/21f5455773d37f94b866eb3cf5caed88d6cea6dd2c6e1f9c34f463cba3ec/greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef", size = 1551946, upload-time = "2026-02-20T20:49:31.102Z" }, { url = "https://files.pythonhosted.org/packages/00/68/91f061a926abead128fe1a87f0b453ccf07368666bd59ffa46016627a930/greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca", size = 1618494, upload-time = "2026-02-20T20:21:06.541Z" }, @@ -1385,6 +1386,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f3/47/16400cb42d18d7a6bb46f0626852c1718612e35dcb0dffa16bbaffdf5dd2/greenlet-3.3.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86", size = 278890, upload-time = "2026-02-20T20:19:39.263Z" }, { url = "https://files.pythonhosted.org/packages/a3/90/42762b77a5b6aa96cd8c0e80612663d39211e8ae8a6cd47c7f1249a66262/greenlet-3.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f", size = 581120, upload-time = "2026-02-20T20:47:30.161Z" }, { url = "https://files.pythonhosted.org/packages/bf/6f/f3d64f4fa0a9c7b5c5b3c810ff1df614540d5aa7d519261b53fba55d4df9/greenlet-3.3.2-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55", size = 594363, upload-time = "2026-02-20T20:55:56.965Z" }, + { url = "https://files.pythonhosted.org/packages/9c/8b/1430a04657735a3f23116c2e0d5eb10220928846e4537a938a41b350bed6/greenlet-3.3.2-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4375a58e49522698d3e70cc0b801c19433021b5c37686f7ce9c65b0d5c8677d2", size = 605046, upload-time = "2026-02-20T21:02:45.234Z" }, { url = "https://files.pythonhosted.org/packages/72/83/3e06a52aca8128bdd4dcd67e932b809e76a96ab8c232a8b025b2850264c5/greenlet-3.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358", size = 594156, upload-time = "2026-02-20T20:20:59.955Z" }, { url = "https://files.pythonhosted.org/packages/70/79/0de5e62b873e08fe3cef7dbe84e5c4bc0e8ed0c7ff131bccb8405cd107c8/greenlet-3.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99", size = 1554649, upload-time = "2026-02-20T20:49:32.293Z" }, { url = "https://files.pythonhosted.org/packages/5a/00/32d30dee8389dc36d42170a9c66217757289e2afb0de59a3565260f38373/greenlet-3.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be", size = 1619472, upload-time = "2026-02-20T20:21:07.966Z" }, @@ -1393,6 +1395,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ea/ab/1608e5a7578e62113506740b88066bf09888322a311cff602105e619bd87/greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd", size = 280358, upload-time = "2026-02-20T20:17:43.971Z" }, { url = "https://files.pythonhosted.org/packages/a5/23/0eae412a4ade4e6623ff7626e38998cb9b11e9ff1ebacaa021e4e108ec15/greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd", size = 601217, upload-time = "2026-02-20T20:47:31.462Z" }, { url = "https://files.pythonhosted.org/packages/f8/16/5b1678a9c07098ecb9ab2dd159fafaf12e963293e61ee8d10ecb55273e5e/greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac", size = 611792, upload-time = "2026-02-20T20:55:58.423Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c5/cc09412a29e43406eba18d61c70baa936e299bc27e074e2be3806ed29098/greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb", size = 626250, upload-time = "2026-02-20T21:02:46.596Z" }, { url = "https://files.pythonhosted.org/packages/50/1f/5155f55bd71cabd03765a4aac9ac446be129895271f73872c36ebd4b04b6/greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070", size = 613875, upload-time = "2026-02-20T20:21:01.102Z" }, { url = "https://files.pythonhosted.org/packages/fc/dd/845f249c3fcd69e32df80cdab059b4be8b766ef5830a3d0aa9d6cad55beb/greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79", size = 1571467, upload-time = "2026-02-20T20:49:33.495Z" }, { url = "https://files.pythonhosted.org/packages/2a/50/2649fe21fcc2b56659a452868e695634722a6655ba245d9f77f5656010bf/greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395", size = 1640001, upload-time = "2026-02-20T20:21:09.154Z" }, @@ -1401,6 +1404,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ac/48/f8b875fa7dea7dd9b33245e37f065af59df6a25af2f9561efa8d822fde51/greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4", size = 279120, upload-time = "2026-02-20T20:19:01.9Z" }, { url = "https://files.pythonhosted.org/packages/49/8d/9771d03e7a8b1ee456511961e1b97a6d77ae1dea4a34a5b98eee706689d3/greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986", size = 603238, upload-time = "2026-02-20T20:47:32.873Z" }, { url = "https://files.pythonhosted.org/packages/59/0e/4223c2bbb63cd5c97f28ffb2a8aee71bdfb30b323c35d409450f51b91e3e/greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92", size = 614219, upload-time = "2026-02-20T20:55:59.817Z" }, + { url = "https://files.pythonhosted.org/packages/94/2b/4d012a69759ac9d77210b8bfb128bc621125f5b20fc398bce3940d036b1c/greenlet-3.3.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd", size = 628268, upload-time = "2026-02-20T21:02:48.024Z" }, { url = "https://files.pythonhosted.org/packages/7a/34/259b28ea7a2a0c904b11cd36c79b8cef8019b26ee5dbe24e73b469dea347/greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab", size = 616774, upload-time = "2026-02-20T20:21:02.454Z" }, { url = "https://files.pythonhosted.org/packages/0a/03/996c2d1689d486a6e199cb0f1cf9e4aa940c500e01bdf201299d7d61fa69/greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a", size = 1571277, upload-time = "2026-02-20T20:49:34.795Z" }, { url = "https://files.pythonhosted.org/packages/d9/c4/2570fc07f34a39f2caf0bf9f24b0a1a0a47bc2e8e465b2c2424821389dfc/greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b", size = 1640455, upload-time = "2026-02-20T20:21:10.261Z" }, @@ -1409,6 +1413,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/ae/8bffcbd373b57a5992cd077cbe8858fff39110480a9d50697091faea6f39/greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab", size = 279650, upload-time = "2026-02-20T20:18:00.783Z" }, { url = "https://files.pythonhosted.org/packages/d1/c0/45f93f348fa49abf32ac8439938726c480bd96b2a3c6f4d949ec0124b69f/greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082", size = 650295, upload-time = "2026-02-20T20:47:34.036Z" }, { url = "https://files.pythonhosted.org/packages/b3/de/dd7589b3f2b8372069ab3e4763ea5329940fc7ad9dcd3e272a37516d7c9b/greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9", size = 662163, upload-time = "2026-02-20T20:56:01.295Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ac/85804f74f1ccea31ba518dcc8ee6f14c79f73fe36fa1beba38930806df09/greenlet-3.3.2-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e3cb43ce200f59483eb82949bf1835a99cf43d7571e900d7c8d5c62cdf25d2f9", size = 675371, upload-time = "2026-02-20T21:02:49.664Z" }, { url = "https://files.pythonhosted.org/packages/d2/d8/09bfa816572a4d83bccd6750df1926f79158b1c36c5f73786e26dbe4ee38/greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506", size = 664160, upload-time = "2026-02-20T20:21:04.015Z" }, { url = "https://files.pythonhosted.org/packages/48/cf/56832f0c8255d27f6c35d41b5ec91168d74ec721d85f01a12131eec6b93c/greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce", size = 1619181, upload-time = "2026-02-20T20:49:36.052Z" }, { url = "https://files.pythonhosted.org/packages/0a/23/b90b60a4aabb4cec0796e55f25ffbfb579a907c3898cd2905c8918acaa16/greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5", size = 1687713, upload-time = "2026-02-20T20:21:11.684Z" }, @@ -1417,6 +1422,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/6d/8f2ef704e614bcf58ed43cfb8d87afa1c285e98194ab2cfad351bf04f81e/greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54", size = 286617, upload-time = "2026-02-20T20:19:29.856Z" }, { url = "https://files.pythonhosted.org/packages/5e/0d/93894161d307c6ea237a43988f27eba0947b360b99ac5239ad3fe09f0b47/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4", size = 655189, upload-time = "2026-02-20T20:47:35.742Z" }, { url = "https://files.pythonhosted.org/packages/f5/2c/d2d506ebd8abcb57386ec4f7ba20f4030cbe56eae541bc6fd6ef399c0b41/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff", size = 658225, upload-time = "2026-02-20T20:56:02.527Z" }, + { url = "https://files.pythonhosted.org/packages/d1/67/8197b7e7e602150938049d8e7f30de1660cfb87e4c8ee349b42b67bdb2e1/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:59b3e2c40f6706b05a9cd299c836c6aa2378cabe25d021acd80f13abf81181cf", size = 666581, upload-time = "2026-02-20T21:02:51.526Z" }, { url = "https://files.pythonhosted.org/packages/8e/30/3a09155fbf728673a1dea713572d2d31159f824a37c22da82127056c44e4/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4", size = 657907, upload-time = "2026-02-20T20:21:05.259Z" }, { url = "https://files.pythonhosted.org/packages/f3/fd/d05a4b7acd0154ed758797f0a43b4c0962a843bedfe980115e842c5b2d08/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727", size = 1618857, upload-time = "2026-02-20T20:49:37.309Z" }, { url = "https://files.pythonhosted.org/packages/6f/e1/50ee92a5db521de8f35075b5eff060dd43d39ebd46c2181a2042f7070385/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e", size = 1680010, upload-time = "2026-02-20T20:21:13.427Z" }, @@ -1537,14 +1543,14 @@ name = "huggingface-hub" version = "0.34.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "tqdm" }, - { name = "typing-extensions" }, + { name = "filelock", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "fsspec", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "hf-xet", marker = "(python_full_version != '3.13.*' and platform_machine == 'aarch64') or (python_full_version != '3.13.*' and platform_machine == 'amd64') or (python_full_version != '3.13.*' and platform_machine == 'arm64') or (python_full_version != '3.13.*' and platform_machine == 'x86_64') or (platform_machine == 'aarch64' and sys_platform != 'win32') or (platform_machine == 'amd64' and sys_platform != 'win32') or (platform_machine == 'arm64' and sys_platform != 'win32') or (platform_machine == 'x86_64' and sys_platform != 'win32')" }, + { name = "packaging", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "pyyaml", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "requests", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "tqdm", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "typing-extensions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/8a/ea019110b644bfd2470fb0c5dd252bd087b5c15c9641dec9be9659ebc4b4/huggingface_hub-0.34.6.tar.gz", hash = "sha256:d0824eb012e37594357bb1790dfbe26c8f45eed7e701c1cdae02539e0c06f3f8", size = 460139, upload-time = "2025-09-16T08:10:51.142Z" } wheels = [ @@ -1677,11 +1683,11 @@ name = "ipywidgets" version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "comm" }, - { name = "ipython" }, - { name = "jupyterlab-widgets" }, - { name = "traitlets" }, - { name = "widgetsnbextension" }, + { name = "comm", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "ipython", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "jupyterlab-widgets", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "traitlets", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "widgetsnbextension", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] 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 = [ @@ -1952,8 +1958,8 @@ name = "loguru" version = "0.7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "win32-setctime", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version != '3.13.*' and sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "python_full_version != '3.13.*' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } wheels = [ @@ -2248,6 +2254,7 @@ dependencies = [ { name = "sb3-contrib" }, { name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "scikit-learn", version = "1.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "stable-baselines3" }, { name = "tensorboard" }, { name = "tqdm" }, { name = "typing-extensions" }, @@ -2297,6 +2304,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 = "tqdm", specifier = ">=4.66.0" }, { name = "typing-extensions", specifier = ">=4.1" }, @@ -2966,9 +2974,9 @@ name = "opencensus" version = "0.11.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "google-api-core" }, - { name = "opencensus-context" }, - { name = "six" }, + { name = "google-api-core", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opencensus-context", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "six", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] 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 = [ @@ -3003,8 +3011,8 @@ name = "opentelemetry-api" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "importlib-metadata" }, - { name = "typing-extensions" }, + { name = "importlib-metadata", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "typing-extensions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } wheels = [ @@ -3016,7 +3024,7 @@ name = "opentelemetry-exporter-otlp-proto-common" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-proto" }, + { name = "opentelemetry-proto", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } wheels = [ @@ -3028,13 +3036,13 @@ name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-exporter-otlp-proto-common" }, - { name = "opentelemetry-proto" }, - { name = "opentelemetry-sdk" }, - { name = "typing-extensions" }, + { name = "googleapis-common-protos", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "grpcio", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-api", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-exporter-otlp-proto-common", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-proto", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-sdk", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "typing-extensions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/48/b329fed2c610c2c32c9366d9dc597202c9d1e58e631c137ba15248d8850f/opentelemetry_exporter_otlp_proto_grpc-1.39.1.tar.gz", hash = "sha256:772eb1c9287485d625e4dbe9c879898e5253fea111d9181140f51291b5fec3ad", size = 24650, upload-time = "2025-12-11T13:32:41.429Z" } wheels = [ @@ -3046,9 +3054,9 @@ name = "opentelemetry-exporter-prometheus" version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-sdk" }, - { name = "prometheus-client" }, + { name = "opentelemetry-api", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-sdk", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "prometheus-client", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/14/39/7dafa6fff210737267bed35a8855b6ac7399b9e582b8cf1f25f842517012/opentelemetry_exporter_prometheus-0.60b1.tar.gz", hash = "sha256:a4011b46906323f71724649d301b4dc188aaa068852e814f4df38cc76eac616b", size = 14976, upload-time = "2025-12-11T13:32:42.944Z" } wheels = [ @@ -3060,10 +3068,10 @@ name = "opentelemetry-instrumentation" version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "packaging" }, - { name = "wrapt" }, + { name = "opentelemetry-api", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-semantic-conventions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "packaging", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "wrapt", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } wheels = [ @@ -3075,10 +3083,10 @@ name = "opentelemetry-instrumentation-requests" version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-instrumentation" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "opentelemetry-util-http" }, + { name = "opentelemetry-api", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-instrumentation", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-semantic-conventions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-util-http", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9d/4a/bb9d47d7424fc33aeba75275256ae6e6031f44b6a9a3f778d611c0c3ac27/opentelemetry_instrumentation_requests-0.60b1.tar.gz", hash = "sha256:9a1063c16c44a3ba6e81870c4fa42a0fac3ecef5a4d60a11d0976eec9046f3d4", size = 16366, upload-time = "2025-12-11T13:37:12.456Z" } wheels = [ @@ -3090,7 +3098,7 @@ name = "opentelemetry-proto" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "protobuf" }, + { name = "protobuf", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } wheels = [ @@ -3102,9 +3110,9 @@ name = "opentelemetry-sdk" version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "typing-extensions" }, + { name = "opentelemetry-api", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-semantic-conventions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "typing-extensions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } wheels = [ @@ -3116,8 +3124,8 @@ name = "opentelemetry-semantic-conventions" version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api" }, - { name = "typing-extensions" }, + { name = "opentelemetry-api", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "typing-extensions", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } wheels = [ @@ -3294,7 +3302,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess" }, + { name = "ptyprocess", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ @@ -3557,7 +3565,7 @@ name = "proto-plus" version = "1.27.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "protobuf" }, + { name = "protobuf", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/02/8832cde80e7380c600fbf55090b6ab7b62bd6825dbedde6d6657c15a1f8e/proto_plus-1.27.1.tar.gz", hash = "sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147", size = 56929, upload-time = "2026-02-02T17:34:49.035Z" } wheels = [ @@ -3697,7 +3705,7 @@ name = "pyasn1-modules" version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyasn1" }, + { name = "pyasn1", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] 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 = [ @@ -4198,8 +4206,8 @@ qasm3-import = [ { name = "qiskit-qasm3-import" }, ] qpy-compat = [ - { name = "symengine" }, - { name = "sympy" }, + { name = "symengine", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "sympy", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] [[package]] @@ -4259,9 +4267,9 @@ name = "qiskit-gym" version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "gymnasium" }, - { name = "qiskit" }, - { name = "twisterl" }, + { name = "gymnasium", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "qiskit", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "twisterl", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/16/95/9547510aa2bede0815a6d254f1215325abbad383f6bd85b30f718745fda0/qiskit_gym-0.4.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e10efe4a5ee15437e28e9c76eaca8c22b68e8d25c5496e7cc56cf2c74b32aeba", size = 1089055, upload-time = "2026-02-13T16:15:49.458Z" }, @@ -4343,14 +4351,14 @@ name = "qiskit-ibm-transpiler" version = "0.18.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "backoff" }, - { name = "networkx" }, - { name = "pyyaml" }, - { name = "qiskit" }, - { name = "qiskit-gym" }, - { name = "qiskit-qasm3-import" }, - { name = "qiskit-serverless" }, - { name = "requests" }, + { name = "backoff", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "networkx", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "pyyaml", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "qiskit", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "qiskit-gym", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "qiskit-qasm3-import", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "qiskit-serverless", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "requests", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/c8/83/040e1c7a4c8f33e5c1c9c2ba3da007f9ed4b5f9774d30c2286d323fbd039/qiskit_ibm_transpiler-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ff3c7e79a536a824d2c108df98e9a163045abc399ca45d240a02e4b97a319b", size = 423908, upload-time = "2026-03-10T11:06:05.701Z" }, @@ -4389,25 +4397,25 @@ name = "qiskit-serverless" version = "0.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp" }, - { name = "certifi" }, - { name = "cloudpickle" }, - { name = "importlib-metadata" }, - { name = "ipython" }, - { name = "ipywidgets" }, + { name = "aiohttp", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "certifi", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "cloudpickle", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "importlib-metadata", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "ipython", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "ipywidgets", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { 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" }, + { name = "numpy", version = "2.4.3", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13') or (python_full_version >= '3.11' and sys_platform != 'win32') or (python_full_version >= '3.14' and sys_platform == 'win32')" }, + { name = "opentelemetry-api", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-exporter-otlp-proto-grpc", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-instrumentation-requests", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-sdk", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "pyarrow", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "qiskit", extra = ["qpy-compat"], marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "qiskit-ibm-runtime", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "ray", extra = ["default"], marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "requests", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "tqdm", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "zipp", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/5d/747b875afc82ee80df16f0084a9b145727917b52fc29f4375f09beaf7811/qiskit_serverless-0.30.0.tar.gz", hash = "sha256:d4e0a4fa14f596916a4adc86df8d5e9a9a0c75aae919eb81c3d9fbacb2e4f66e", size = 39614, upload-time = "2026-03-04T17:09:05.42Z" } wheels = [ @@ -4431,14 +4439,14 @@ name = "ray" version = "2.54.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "filelock" }, - { name = "jsonschema" }, - { name = "msgpack" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "pyyaml" }, - { name = "requests" }, + { name = "click", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "filelock", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "jsonschema", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "msgpack", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "packaging", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "protobuf", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "pyyaml", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "requests", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/64/13/b86d791b41f33220335eba18fc4841f1ebddae41e562c6a216846404c88d/ray-2.54.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:a22937f09ee74a43171df338d84b45ef882c1c05748947ca9d5343a44d4b9379", size = 70097079, upload-time = "2026-02-18T04:04:35.409Z" }, @@ -4460,20 +4468,20 @@ wheels = [ [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" }, + { name = "aiohttp", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "aiohttp-cors", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "colorful", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "grpcio", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opencensus", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-exporter-prometheus", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-proto", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "opentelemetry-sdk", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "prometheus-client", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "py-spy", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "pydantic", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "requests", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "smart-open", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "virtualenv", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] [[package]] @@ -4669,7 +4677,7 @@ name = "rsa" version = "4.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyasn1" }, + { name = "pyasn1", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] 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 = [ @@ -5029,7 +5037,7 @@ name = "smart-open" version = "7.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "wrapt" }, + { name = "wrapt", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e8/be/a66598b305763861a9ab15ff0f2fbc44e47b1ce7a776797337a4eef37c66/smart_open-7.5.1.tar.gz", hash = "sha256:3f08e16827c4733699e6b2cc40328a3568f900cb12ad9a3ad233ba6c872d9fe7", size = 54034, upload-time = "2026-02-23T11:01:28.979Z" } wheels = [ @@ -5744,13 +5752,13 @@ name = "twisterl" version = "0.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "huggingface-hub" }, - { name = "loguru" }, + { name = "huggingface-hub", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "loguru", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "safetensors" }, - { name = "tensorboard" }, - { name = "torch" }, + { name = "numpy", version = "2.4.3", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and python_full_version < '3.13') or (python_full_version >= '3.11' and sys_platform != 'win32') or (python_full_version >= '3.14' and sys_platform == 'win32')" }, + { name = "safetensors", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "tensorboard", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "torch", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/92/8d/243962b1ef50c3600cdbf02ab49919963d35c7de75305f66801a9fb65e14/twisterl-0.5.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e9ac89abaa3a5289899159f139167e1da042000dc2022086c34f0901f92ded1a", size = 428020, upload-time = "2026-01-12T09:34:44.757Z" }, @@ -5965,9 +5973,9 @@ name = "yarl" version = "1.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, + { name = "idna", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "multidict", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, + { name = "propcache", marker = "python_full_version != '3.13.*' or sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } wheels = [