diff --git a/docs/JSTPROVE_BACKEND.md b/docs/JSTPROVE_BACKEND.md new file mode 100644 index 0000000..4c37e07 --- /dev/null +++ b/docs/JSTPROVE_BACKEND.md @@ -0,0 +1,105 @@ +# JSTprove Backend Integration + +## Overview + +This document describes the integration of JSTprove as an additional ZK proof backend alongside EZKL in the Dsperse compilation pipeline. + +## Features + +### 1. JSTprove Backend Support +- New backend class `JSTprove` in `dsperse/src/backends/JSTprove.py` +- Uses JSTprove CLI (`jst` command) for circuit compilation, witness generation, proof generation, and verification +- Compatible with existing EZKL interface for seamless integration + +### 2. Flexible Backend Selection +The compiler now supports three modes: + +**Default (Fallback Mode):** +```bash +dsperse compile --path model/slices +``` +- Tries JSTprove first +- Falls back to EZKL if JSTprove fails +- Falls back to ONNX (skip ZK compilation) if both fail + +**Single Backend:** +```bash +dsperse compile --path model/slices --backend jstprove +dsperse compile --path model/slices --backend ezkl +``` + +**Per-Layer Backend Assignment:** +```bash +dsperse compile --path model/slices --backend "0,2:jstprove;3-4:ezkl" +``` +- Layer 0 and 2: Use JSTprove +- Layer 3 and 4: Use EZKL +- Unspecified layers use default backend + +## Installation + +1. Install Open MPI (required for JSTprove): + ```bash + brew install open-mpi # macOS + # or apt-get install openmpi-bin libopenmpi-dev # Linux + ``` + +2. Install JSTprove: + ```bash + uv tool install jstprove + # or: pip install jstprove + ``` + +3. Verify installation: + ```bash + jst --help + ``` + +The `install.sh` script has been updated to automatically install these dependencies. + +## File Changes + +### New Files +- `dsperse/src/backends/JSTprove.py` - JSTprove backend implementation + +### Modified Files +- `dsperse/src/cli/compile.py` - Added `--backend` argument +- `dsperse/src/compile/compiler.py` - Backend selection and fallback logic +- `dsperse/src/compile/utils/compiler_utils.py` - Support for JSTprove compilation success check +- `dsperse/src/constants.py` - Added JSTprove command constant +- `install.sh` - Added Open MPI and JSTprove installation +- `requirements.txt` - Added mpi4py dependency + +## Usage Examples + +**Compile all layers with default fallback:** +```bash +dsperse compile --path model/slices +``` + +**Compile specific layers with mixed backends:** +```bash +dsperse compile --path model/slices --layers "0-4" --backend "0,2:jstprove;3-4:ezkl" +``` + +**Compile with single backend:** +```bash +dsperse compile --path model/slices --backend jstprove +``` + +## Backend Comparison + +| Feature | JSTprove | EZKL | +|---------|----------|------| +| Circuit Format | `.txt` | `.compiled` | +| Keys | Not required | `vk.key`, `pk.key` | +| Settings | Dummy JSON | Full settings.json | +| CLI Command | `jst` | `ezkl` | + +## Notes + +- JSTprove uses CLI-only interface (no Python package import) +- Fallback logic ensures compilation continues even if preferred backend fails +- Metadata tracks which backend was used for each slice +- All changes maintain backward compatibility with existing EZKL workflows + diff --git a/dsperse/src/analyzers/runner_analyzer.py b/dsperse/src/analyzers/runner_analyzer.py index 0a68feb..630c646 100644 --- a/dsperse/src/analyzers/runner_analyzer.py +++ b/dsperse/src/analyzers/runner_analyzer.py @@ -95,16 +95,29 @@ def _process_slices_model(slices_dir: Path, slices_list: list[dict]) -> dict: dependencies = item.get("dependencies") or {} parameters = item.get("parameters", 0) - # EZKL compilation info - comp = ((item.get("compilation") or {}).get("ezkl") or {}) - files = (comp.get("files") or {}) - compiled_flag = bool(comp.get("compiled", False)) - - # Accept both keys: 'compiled_circuit' and legacy 'compiled' - compiled_rel = files.get("compiled_circuit") or files.get("compiled") - settings_rel = files.get("settings") - pk_rel = files.get("pk_key") - vk_rel = files.get("vk_key") + # Check for compilation info (JSTprove first, then EZKL) + compilation = item.get("compilation") or {} + jst_comp = compilation.get("jstprove") or {} + ezkl_comp = compilation.get("ezkl") or {} + + # Prefer JSTprove if available, otherwise EZKL + if jst_comp.get("compiled"): + backend = "jstprove" + files = jst_comp.get("files") or {} + compiled_flag = True + compiled_rel = files.get("circuit") + settings_rel = None + pk_rel = None + vk_rel = None + else: + backend = "ezkl" + files = ezkl_comp.get("files") or {} + compiled_flag = bool(ezkl_comp.get("compiled", False)) + # Accept both keys: 'compiled_circuit' and legacy 'compiled' + compiled_rel = files.get("compiled_circuit") or files.get("compiled") + settings_rel = files.get("settings") + pk_rel = files.get("pk_key") + vk_rel = files.get("vk_key") def _norm(rel: Optional[str]) -> Optional[str]: if not rel: @@ -124,6 +137,7 @@ def _norm(rel: Optional[str]) -> Optional[str]: "output_shape": output_shape, "ezkl_compatible": True, "ezkl": bool(compiled_flag), + "backend": backend, "circuit_size": 0, # unknown without touching filesystem; keep 0 "dependencies": dependencies, "parameters": parameters, @@ -171,21 +185,36 @@ def _process_slices_per_slice(slices_dir: Path, slices_data_list: list[dict]) -> dependencies = slice.get("dependencies") or {} parameters = slice.get("parameters", 0) - # EZKL compilation info - comp = ((slice.get("compilation") or {}).get("ezkl") or {}) - files = (comp.get("files") or {}) - compiled_flag = bool(comp.get("compiled", False)) - - if files: - circuit_path = os.path.join(parent_dir, files.get("compiled_circuit") or files.get("compiled")) - settings_path = os.path.join(parent_dir, files.get("settings")) - pk_path = os.path.join(parent_dir, files.get("pk_key")) - vk_path = os.path.join(parent_dir, files.get("vk_key")) - else: - circuit_path = None + # Check for compilation info (JSTprove first, then EZKL) + compilation = slice.get("compilation") or {} + jst_comp = compilation.get("jstprove") or {} + ezkl_comp = compilation.get("ezkl") or {} + + if jst_comp.get("compiled"): + backend = "jstprove" + files = jst_comp.get("files") or {} + compiled_flag = True + if files: + circuit_path = os.path.join(parent_dir, files.get("circuit")) + else: + circuit_path = None settings_path = None pk_path = None vk_path = None + else: + backend = "ezkl" + files = ezkl_comp.get("files") or {} + compiled_flag = bool(ezkl_comp.get("compiled", False)) + if files: + circuit_path = os.path.join(parent_dir, files.get("compiled_circuit") or files.get("compiled")) + settings_path = os.path.join(parent_dir, files.get("settings")) + pk_path = os.path.join(parent_dir, files.get("pk_key")) + vk_path = os.path.join(parent_dir, files.get("vk_key")) + else: + circuit_path = None + settings_path = None + pk_path = None + vk_path = None slices[slice_key] = { "path": onnx_path, @@ -193,6 +222,7 @@ def _process_slices_per_slice(slices_dir: Path, slices_data_list: list[dict]) -> "output_shape": output_shape, "ezkl_compatible": True, "ezkl": bool(compiled_flag), + "backend": backend, "circuit_size": 0, "dependencies": dependencies, "parameters": parameters, @@ -243,9 +273,11 @@ def _build_execution_chain(slices: dict): meta = slices.get(slice_key, {}) circuit_path = meta.get('circuit_path') onnx_path = meta.get('path') + backend = meta.get('backend', 'ezkl') has_circuit = circuit_path is not None and circuit_path != "" has_keys = (meta.get('pk_path') is not None) and (meta.get('vk_path') is not None) - use_circuit = bool(meta.get('ezkl')) and has_circuit and has_keys + # JSTprove doesn't require pk/vk keys; EZKL does + use_circuit = bool(meta.get('ezkl')) and has_circuit and (backend == 'jstprove' or has_keys) next_slice = ordered_keys[i + 1] if i < len(ordered_keys) - 1 else None execution_chain["nodes"][slice_key] = { diff --git a/dsperse/src/backends/JSTprove.py b/dsperse/src/backends/JSTprove.py new file mode 100644 index 0000000..ebe7593 --- /dev/null +++ b/dsperse/src/backends/JSTprove.py @@ -0,0 +1,477 @@ +""" +JSTprove backend for zero-knowledge proof generation. +This module provides a backend for generating ZK proofs using the JSTprove CLI. +""" +import json +import os +import subprocess +import torch +import logging +from pathlib import Path +from typing import Optional, Tuple, Dict, Any, Union, List + +from dsperse.src.constants import JSTPROVE_COMMAND + +# Configure logger +logger = logging.getLogger(__name__) + + +class JSTprove: + """JSTprove backend for zero-knowledge proof generation using the JSTprove CLI.""" + + # Class constants + COMMAND = JSTPROVE_COMMAND + DEFAULT_FLAGS = ["--no-banner"] + + def __init__(self, model_directory: Optional[str] = None) -> None: + """ + Initialize the JSTprove backend. + + Args: + model_directory: Optional path to the model directory for organizing artifacts. + + Raises: + RuntimeError: If JSTprove CLI is not available + """ + self.env = os.environ.copy() + self.model_directory = Path(model_directory) if model_directory else None + self._witness_format = "jstprove" # Track witness output format + + # Check if JSTprove CLI is available + try: + result = subprocess.run( + [self.COMMAND, "--help"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + if result.returncode != 0: + raise RuntimeError("JSTprove CLI not found. Please install JSTprove first.") + except FileNotFoundError: + raise RuntimeError("JSTprove CLI not found. Please install JSTprove: uv tool install jstprove") + + def _run_command( + self, + subcommand: str, + args: List[str], + check: bool = True, + capture_output: bool = True, + ) -> subprocess.CompletedProcess: + """ + Execute a JSTprove CLI command. + + Args: + subcommand: The jst subcommand (compile, witness, prove, verify) + args: Additional arguments for the subcommand + check: Whether to check return code + capture_output: Whether to capture output + + Returns: + subprocess.CompletedProcess: The completed process + + Raises: + RuntimeError: If command fails + """ + cmd = [self.COMMAND] + self.DEFAULT_FLAGS + [subcommand] + args + try: + logger.debug(f"Running JSTprove command: {' '.join(cmd)}") + process = subprocess.run( + cmd, + env=self.env, + check=check, + capture_output=capture_output, + text=True, + ) + return process + except subprocess.CalledProcessError as e: + error_msg = f"JSTprove command failed: {' '.join(cmd)}" + if e.stderr: + error_msg += f"\nError output: {e.stderr}" + logger.error(error_msg) + raise RuntimeError(error_msg) from e + + # + # High-level methods that dispatch to specific implementations + # + + def generate_witness( + self, + input_file: Union[str, Path], + model_path: Union[str, Path], # This is the circuit path in JSTprove context + output_file: Union[str, Path], + vk_path: Optional[Union[str, Path]] = None, # Kept for backward compatibility but not used + settings_path: Optional[Union[str, Path]] = None # Kept for backward compatibility but not used + ) -> Tuple[bool, Any]: + """ + Generate a witness for the given circuit and input using JSTprove. + + Args: + input_file: Path to the input JSON file + model_path: Path to the compiled circuit file (called model_path for interface compatibility) + output_file: Path where to save the model outputs JSON + vk_path: Ignored (kept for backward compatibility) + settings_path: Ignored (kept for backward compatibility) + + Returns: + Tuple of (success: bool, output: Any) where output is the processed witness data + """ + # Normalize paths + input_file = Path(input_file) + circuit_path = Path(model_path) # model_path is actually the circuit path + output_file = Path(output_file) + witness_path = output_file.parent / f"{output_file.stem}_witness.bin" + + # Validate required files exist + if not input_file.exists(): + raise FileNotFoundError(f"Input file not found: {input_file}") + + # Check if we have an ONNX model that needs compilation, or an existing circuit + onnx_model_path = None + if circuit_path.exists() and circuit_path.suffix == '.onnx': + onnx_model_path = circuit_path + circuit_path = circuit_path.parent / f"{circuit_path.stem}_jstprove_circuit.txt" + + # If we have an ONNX model, compile it first only if circuit doesn't exist + if onnx_model_path and not circuit_path.exists(): + logger.info(f"JSTprove: Compiling ONNX model {onnx_model_path} to circuit {circuit_path}") + ok, err = self.compile_circuit(onnx_model_path, circuit_path) + if not ok: + raise RuntimeError(f"Circuit compilation failed: {err}") + elif onnx_model_path and circuit_path.exists(): + logger.info(f"Using existing circuit: {circuit_path}") + elif not circuit_path.exists(): + raise FileNotFoundError(f"Circuit file not found: {circuit_path}") + + # Create output directories if they don't exist + output_file.parent.mkdir(parents=True, exist_ok=True) + witness_path.parent.mkdir(parents=True, exist_ok=True) + + try: + self._run_command("witness", [ + "-c", str(circuit_path), + "-i", str(input_file), + "-o", str(output_file), + "-w", str(witness_path), + ]) + except RuntimeError as e: + error_msg = f"Witness generation failed: {e}" + logger.error(error_msg) + return False, error_msg + + # Process the outputs + try: + with open(output_file, "r") as f: + output_data = json.load(f) + processed_output = self.process_witness_output(output_data) + return True, processed_output + except (json.JSONDecodeError, FileNotFoundError) as e: + error_msg = f"Failed to process witness output: {e}" + logger.error(error_msg) + return False, error_msg + + def prove( + self, + witness_path: Union[str, Path], + circuit_path: Union[str, Path], + proof_path: Union[str, Path], + pk_path: Optional[Union[str, Path]] = None, # Kept for backward compatibility but not used + check_mode: str = "unsafe", # Kept for backward compatibility but not used + settings_path: Optional[Union[str, Path]] = None # Kept for backward compatibility but not used + ) -> Tuple[bool, Union[str, Path]]: + """ + Generate a proof for the given witness and circuit using JSTprove. + + Args: + witness_path: Path to the witness file + circuit_path: Path to the compiled circuit + proof_path: Path where to save the proof + pk_path: Ignored (kept for backward compatibility) + check_mode: Ignored (kept for backward compatibility) + settings_path: Ignored (kept for backward compatibility) + + Returns: + Tuple of (success: bool, results: Union[str, Path]) where results is the proof path + """ + # Normalize paths + witness_path = Path(witness_path) + circuit_path = Path(circuit_path) + proof_path = Path(proof_path) + + # Validate required files exist + if not witness_path.exists(): + raise FileNotFoundError(f"Witness file not found: {witness_path}") + if not circuit_path.exists(): + raise FileNotFoundError(f"Circuit file not found: {circuit_path}") + + # Create output directory if it doesn't exist + proof_path.parent.mkdir(parents=True, exist_ok=True) + + try: + self._run_command("prove", [ + "-c", str(circuit_path), + "-w", str(witness_path), + "-p", str(proof_path), + ]) + except RuntimeError as e: + error_msg = f"Proof generation failed: {e}" + logger.error(error_msg) + return False, error_msg + + return True, proof_path + + def verify( + self, + proof_path: Union[str, Path], + circuit_path: Union[str, Path], + input_path: Union[str, Path], + output_path: Union[str, Path], + witness_path: Union[str, Path], + settings_path: Optional[Union[str, Path]] = None, # Kept for backward compatibility but not used + vk_path: Optional[Union[str, Path]] = None # Kept for backward compatibility but not used + ) -> bool: + """ + Verify a proof using JSTprove. + + Args: + proof_path: Path to the proof file + circuit_path: Path to the compiled circuit + input_path: Path to the input JSON used for the proof + output_path: Path to the expected outputs JSON + witness_path: Path to the witness file + settings_path: Ignored (kept for backward compatibility) + vk_path: Ignored (kept for backward compatibility) + + Returns: + True if verification succeeded, False otherwise + """ + # Normalize paths + proof_path = Path(proof_path) + circuit_path = Path(circuit_path) + input_path = Path(input_path) + output_path = Path(output_path) + witness_path = Path(witness_path) + + # Validate required files exist + required_files = [proof_path, circuit_path, input_path, output_path, witness_path] + for file_path in required_files: + if not file_path.exists(): + raise FileNotFoundError(f"Required file not found: {file_path}") + + try: + self._run_command("verify", [ + "-c", str(circuit_path), + "-i", str(input_path), + "-o", str(output_path), + "-w", str(witness_path), + "-p", str(proof_path), + ]) + return True + except RuntimeError as e: + logger.error(f"Proof verification failed: {e}") + return False + + def compile_circuit( + self, + model_path: Union[str, Path], + circuit_path: Union[str, Path], + settings_path: Optional[Union[str, Path]] = None # Kept for backward compatibility but not used + ) -> Tuple[bool, Optional[str]]: + """ + Compile a circuit from an ONNX model using JSTprove. + + Args: + model_path: Path to the original ONNX model + circuit_path: Path where to save the compiled circuit + settings_path: Ignored (kept for backward compatibility) + + Returns: + Tuple of (success: bool, error: Optional[str]) + """ + # Normalize paths + model_path = Path(model_path) + circuit_path = Path(circuit_path) + + # Validate required files exist + if not model_path.exists(): + raise FileNotFoundError(f"Model file not found: {model_path}") + + # Create output directory if it doesn't exist + circuit_path.parent.mkdir(parents=True, exist_ok=True) + + try: + self._run_command("compile", [ + "-m", str(model_path), + "-c", str(circuit_path), + ]) + return True, None + except Exception as e: + error_msg = f"Circuit compilation failed: {e}" + logger.error(error_msg) + return False, error_msg + + def circuitization_pipeline( + self, + model_path: Union[str, Path], + output_path: Union[str, Path], + input_file_path: Optional[Union[str, Path]] = None, + segment_details: Optional[Dict[str, Any]] = None + ) -> Dict[str, Any]: + """ + Run the JSTprove circuitization pipeline. + + In JSTprove, circuitization is a single step that compiles the model into a circuit. + The compile command handles all the necessary setup internally. + + Args: + model_path: Path to the ONNX model file. + output_path: Base path for output files. + input_file_path: Ignored (kept for backward compatibility). + segment_details: Ignored (kept for backward compatibility). + + Returns: + Dictionary containing paths to generated files and any error information. + """ + # Normalize paths + model_path = Path(model_path) + output_path = Path(output_path) + + # Ensure model_path exists + if not model_path.exists(): + raise FileNotFoundError(f"Model file not found: {model_path}") + + # Create output directory + output_path.mkdir(parents=True, exist_ok=True) + + model_name = model_path.stem + + # Define file paths (JSTprove outputs circuit and quantized model) + circuit_path = output_path / f"{model_name}_circuit.txt" + quantized_model_path = output_path / f"{model_name}_circuit_quantized_model.onnx" + witness_solver_path = output_path / f"{model_name}_circuit_witness_solver.txt" + + # Create dummy settings file for compatibility with runner analyzer + settings_path = output_path / f"{model_name}_settings.json" + + # Initialize circuitization data dictionary (match EZKL structure for compatibility) + circuitization_data: Dict[str, Any] = { + "compiled": str(circuit_path), # This is what runner_analyzer looks for + "circuit": str(circuit_path), + "quantized_model": str(quantized_model_path), + "witness_solver": str(witness_solver_path), + "calibration": input_file_path, + # Create dummy settings file for runner analyzer compatibility + "settings": str(settings_path), + # JSTprove doesn't use vk, pk in the same way as EZKL + "vk_key": None, + "pk_key": None, + } + + try: + logger.info(f"Compiling circuit for {model_name}") + # JSTprove compile command handles everything in one step + ok, err = self.compile_circuit( + model_path=model_path, + circuit_path=circuit_path, + ) + if not ok: + logger.warning("Failed to compile circuit") + circuitization_data["compile_error"] = err + else: + # Create dummy settings file for runner analyzer compatibility + dummy_settings = { + "backend": "jstprove", + "model_path": str(model_path), + "circuit_path": str(circuit_path), + "compiled_at": str(output_path), + "note": "This is a dummy settings file for dsperse compatibility. JSTprove handles settings internally." + } + with open(settings_path, 'w') as f: + json.dump(dummy_settings, f, indent=2) + logger.info(f"Circuitization pipeline completed for {model_path}") + except Exception as e: + error_msg = f"Error during circuitization: {str(e)}" + logger.exception(error_msg) + circuitization_data["error"] = error_msg + + return circuitization_data + + # Alias for backward compatibility with EZKL interface + compilation_pipeline = circuitization_pipeline + + def process_witness_output(self, witness_data: Any) -> Optional[Dict[str, Any]]: + """ + Process the witness output data to get prediction results. + + This method handles JSTprove witness output format. JSTprove outputs + a raw array of floats representing the final logits. + + Args: + witness_data: The parsed JSON data from witness output. + + Returns: + Dictionary containing processed predictions, or None if processing fails. + """ + def _to_logits(data) -> torch.Tensor: + """Helper to convert data to logits tensor with batch dimension.""" + logits = torch.tensor(data) + if logits.dim() == 1: + logits = logits.unsqueeze(0) + return logits + + try: + # JSTprove dict format with 'rescaled_output' key + if isinstance(witness_data, dict) and "rescaled_output" in witness_data: + self._witness_format = "jstprove_dict" + # NOTE: Rescaled outputs are in output.json (from -o flag), not in the witness binary file (-w flag). + # The witness binary contains only the raw quantized values needed for proof generation. + logger.warning( + "Using rescaled outputs from output.json (not witness binary). " + "These are the model's floating-point outputs after de-quantization." + ) + return {"logits": _to_logits(witness_data["rescaled_output"])} + # Raw array format + elif isinstance(witness_data, list): + self._witness_format = "jstprove_list" + return {"logits": _to_logits(witness_data)} + # EZKL-like format fallback + else: + self._witness_format = "ezkl_compat" + rescaled = witness_data["pretty_elements"]["rescaled_outputs"][0] + return {"logits": _to_logits(rescaled)} + except (KeyError, TypeError) as e: + logger.error(f"Could not process witness data: {e}") + return None + + @classmethod + def get_version(cls) -> Optional[str]: + """ + Get the JSTprove version. + + Returns: + str: JSTprove version string, or None if version cannot be determined + """ + try: + result = subprocess.run( + [cls.COMMAND, "--version"], + capture_output=True, + text=True, + timeout=5 + ) + if result.returncode == 0: + # Parse version from output + version_output = result.stdout.strip() or result.stderr.strip() + return version_output + except Exception as e: + logger.debug(f"Could not get JSTprove version: {e}") + return None + + +if __name__ == "__main__": + # Example usage with JSTprove + print("JSTprove backend example:") + print("backend = JSTprove()") + print("backend.compile_circuit('model.onnx', 'circuit.txt')") + print("backend.generate_witness('input.json', 'circuit.txt', 'output.json')") + print("backend.prove('witness.bin', 'circuit.txt', 'proof.bin')") + print("backend.verify('proof.bin', 'circuit.txt', 'input.json', 'output.json', 'witness.bin')") + diff --git a/dsperse/src/cli/compile.py b/dsperse/src/cli/compile.py index a6cae85..5561c78 100644 --- a/dsperse/src/cli/compile.py +++ b/dsperse/src/cli/compile.py @@ -115,6 +115,9 @@ def setup_parser(subparsers): compile_parser.add_argument('--input-file', '--input', '--if', '-i', dest='input_file', help='Path to input file for calibration (optional)') compile_parser.add_argument('--layers', '-l', help='Specify which layers to compile (e.g., "3, 20-22"). If not provided, all layers will be compiled.') + compile_parser.add_argument('--backend', '-b', default=None, + help='Backend specification. Can be: "jstprove", "ezkl", or per-layer like "0,2:jstprove;3-4:ezkl". ' + 'Default: try both jstprove and ezkl, fallback to onnx. Note: requires --layers to compile.') return compile_parser @@ -126,8 +129,21 @@ def compile_model(args): Args: args: The parsed command-line arguments """ - print(f"{Fore.CYAN}Compiling slices with EZKL...{Style.RESET_ALL}") - logger.info("Starting slices compilation") + backend = getattr(args, 'backend', None) + layers = getattr(args, 'layers', None) + + if not layers: + print(f"{Fore.CYAN}No layers specified. Will compile all layers with default fallback (jstprove -> ezkl -> onnx)...{Style.RESET_ALL}") + logger.info("No layers specified - compiling all layers with default fallback") + elif backend: + if ':' in backend: + print(f"{Fore.CYAN}Compiling specified layers with mixed backends...{Style.RESET_ALL}") + else: + backend_name = 'JSTprove' if backend == 'jstprove' else 'EZKL' + print(f"{Fore.CYAN}Compiling specified layers with {backend_name}...{Style.RESET_ALL}") + else: + print(f"{Fore.CYAN}Compiling specified layers (trying jstprove & ezkl, fallback to onnx)...{Style.RESET_ALL}") + logger.info(f"Starting slices compilation") # Resolve path (slices dir or .dsperse/.dslice file) target_path = getattr(args, 'path', None) or getattr(args, 'slices_path', None) @@ -172,7 +188,7 @@ def compile_model(args): # Initialize the Compiler (it supports dirs or model.onnx) try: - compiler = Compiler() + compiler = Compiler(backend=backend) logger.info(f"Compiler initialized successfully") except RuntimeError as e: error_msg = f"Failed to initialize Compiler: {e}" diff --git a/dsperse/src/compile/compiler.py b/dsperse/src/compile/compiler.py index 7ea3ccc..3b887c0 100644 --- a/dsperse/src/compile/compiler.py +++ b/dsperse/src/compile/compiler.py @@ -14,6 +14,7 @@ from typing import Optional, Dict, Any from dsperse.src.backends.ezkl import EZKL +from dsperse.src.backends.JSTprove import JSTprove from dsperse.src.compile.utils.compiler_utils import CompilerUtils from dsperse.src.slice.utils.converter import Converter from dsperse.src.utils.utils import Utils @@ -28,19 +29,119 @@ class Compiler: to the appropriate compiler implementation based on the model type. """ - def __init__(self): + def __init__(self, backend: Optional[str] = None): """ - Initialize the Compiler with a specific implementation. + Initialize the Compiler with a specific backend configuration. Args: - compiler_impl: The compiler implementation to use + backend: Backend specification. Can be: + - None: Use jstprove with fallback to ezkl then onnx (tries jstprove first) + - "jstprove" or "ezkl": Use specific backend for all layers + - "0,2:jstprove;3-4:ezkl": Per-layer backend specification """ - self.ezkl = EZKL() + self.backend_spec = backend + self.layer_backends = {} # Map layer index -> backend name + self.use_fallback = False + + # Parse backend specification + if backend is None: + # Default: use fallback logic (try both jstprove and ezkl, then onnx) + self.default_backend = None # Will try both + self.use_fallback = True + elif ':' in str(backend): + # Per-layer specification like "0,2:jstprove;3-4:ezkl" + # Unspecified layers use default fallback, specified layers try their backend first + self.default_backend = None + self.use_fallback = True # Enable fallback for both specified and unspecified layers + self._parse_layer_backends(backend) + else: + # Simple backend name - no fallback, use only this backend + self.default_backend = backend.lower() + self.use_fallback = False + + # Initialize backends (lazy loading to avoid errors if not used) + self._jstprove = None + self._ezkl = None + + def _parse_layer_backends(self, spec: str): + """Parse layer-specific backend specification like '0,2:jstprove;3-4:ezkl'""" + parts = spec.split(';') + for part in parts: + part = part.strip() + if ':' not in part: + continue + layers_str, backend_name = part.split(':', 1) + backend_name = backend_name.strip().lower() + + # Reuse existing layer parsing utility + layer_indices = CompilerUtils.parse_layers(layers_str) + if layer_indices: + for idx in layer_indices: + self.layer_backends[idx] = backend_name + + def _get_jstprove(self): + """Lazy initialization of JSTprove backend""" + if self._jstprove is None: + try: + self._jstprove = JSTprove() + except Exception as e: + logger.warning(f"Failed to initialize JSTprove: {e}") + return None + return self._jstprove + + def _get_ezkl(self): + """Lazy initialization of EZKL backend""" + if self._ezkl is None: + try: + self._ezkl = EZKL() + except Exception as e: + logger.warning(f"Failed to initialize EZKL: {e}") + return None + return self._ezkl + + def _get_backend_for_layer(self, layer_idx: int): + """Get the backend instance for a specific layer""" + # Check if layer has specific backend assigned + if layer_idx in self.layer_backends: + backend_name = self.layer_backends[layer_idx] + if backend_name == "jstprove": + return self._get_jstprove(), "jstprove" + else: + return self._get_ezkl(), "ezkl" + elif self.default_backend is None: + # Default: try both backends (will be handled in fallback logic) + return None, None + else: + # Simple backend specified + if self.default_backend == "jstprove": + return self._get_jstprove(), "jstprove" + else: + return self._get_ezkl(), "ezkl" + + # Keep backward compatibility properties + @property + def backend(self): + # Return ezkl for backward compatibility + return self._get_ezkl() + @property + def backend_name(self): + return self.default_backend or "ezkl" - def _compile_slice(self, idx, slice_data, base_path: str): + @property + def ezkl(self): + return self._get_ezkl() + + + def _compile_slice(self, idx: int, slice_data: dict, base_path: str): """ - Function for compiling a single slice. + Function for compiling a single slice with fallback support. + Tries jstprove -> ezkl -> onnx (skip) if fallback is enabled. + + Args: + idx: Slice index + slice_data: Dictionary containing slice information + base_path: Base path for resolving relative paths """ slice_path = slice_data.get('path') if slice_path and os.path.exists(slice_path): @@ -54,42 +155,159 @@ def _compile_slice(self, idx, slice_data, base_path: str): logger.error(f"No valid path found for slice") raise FileNotFoundError(f"No valid path found for slice") - slice_output_path = os.path.join(os.path.dirname(slice_path), "ezkl") - - calibration_input = os.path.join( - os.path.dirname(slice_path), - "ezkl", - f"calibration.json" - ) if os.path.exists(os.path.join(os.path.dirname(slice_path), "ezkl", "calibration.json")) else None - - compilation_data = self.ezkl.compilation_pipeline( - slice_path, - slice_output_path, - input_file_path=calibration_input - ) - - success = CompilerUtils.is_ezkl_compilation_successful(compilation_data) - file_paths = CompilerUtils.get_relative_paths(compilation_data, calibration_input) + # Get the backend for this specific layer + backend, backend_name = self._get_backend_for_layer(idx) + + # Build list of backends to try + backends_to_try = [] + if backend is not None: + # Specific backend assigned to this layer + backends_to_try = [(backend, backend_name)] + if self.use_fallback: + # Add fallback: try other backend, then onnx + if backend_name == "jstprove": + ezkl = self._get_ezkl() + if ezkl: + backends_to_try.append((ezkl, "ezkl")) + elif backend_name == "ezkl": + jst = self._get_jstprove() + if jst: + backends_to_try.append((jst, "jstprove")) + backends_to_try.append((None, "onnx")) + elif self.use_fallback: + # No specific backend for this layer, use default fallback chain + # (jstprove -> ezkl -> onnx) + jst = self._get_jstprove() + ezkl = self._get_ezkl() + if jst: + backends_to_try.append((jst, "jstprove")) + if ezkl: + backends_to_try.append((ezkl, "ezkl")) + backends_to_try.append((None, "onnx")) + else: + # No backend specified and no fallback - skip compilation (use pure ONNX) + backends_to_try = [(None, "onnx")] + + success = False + compilation_data = {} + used_backend = None + + for try_backend, try_backend_name in backends_to_try: + if try_backend is None: + # Skip compilation - will use onnx at runtime + logger.info(f"Slice {idx}: Skipping ZK compilation, will use ONNX at runtime") + success = True + used_backend = "onnx" + compilation_data = {"skipped": True, "reason": "fallback_to_onnx"} + break + + backend_dir = try_backend_name + slice_output_path = os.path.join(os.path.dirname(slice_path), backend_dir) + + calibration_input = os.path.join( + os.path.dirname(slice_path), + backend_dir, + f"calibration.json" + ) if os.path.exists(os.path.join(os.path.dirname(slice_path), backend_dir, "calibration.json")) else None + + try: + logger.info(f"Slice {idx}: Trying {try_backend_name}...") + compilation_data = try_backend.compilation_pipeline( + slice_path, + slice_output_path, + input_file_path=calibration_input + ) + success = CompilerUtils.is_ezkl_compilation_successful(compilation_data) + if success: + used_backend = try_backend_name + logger.info(f"Slice {idx}: {try_backend_name} compilation succeeded") + break + else: + logger.warning(f"Slice {idx}: {try_backend_name} compilation failed, trying fallback...") + except Exception as e: + logger.warning(f"Slice {idx}: {try_backend_name} error: {e}, trying fallback...") + if not self.use_fallback: + raise + + file_paths = CompilerUtils.get_relative_paths(compilation_data, calibration_input) if used_backend not in [None, "onnx"] else {} if slice_data.get('slice_metadata') and os.path.exists(slice_data.get('slice_metadata')): path = Path(slice_data.get('slice_metadata')) - CompilerUtils.update_slice_metadata(idx, path, success, file_paths) + CompilerUtils.update_slice_metadata(idx, path, success, file_paths, backend_name=used_backend or "onnx") elif slice_data.get('slice_metadata_relative_path') and os.path.exists(os.path.join(base_path, slice_data.get('slice_metadata_relative_path'))): path = Path(os.path.join(base_path, slice_data.get('slice_metadata_relative_path'))) - CompilerUtils.update_slice_metadata(idx, path, success, file_paths) + CompilerUtils.update_slice_metadata(idx, path, success, file_paths, backend_name=used_backend or "onnx") - return success, file_paths + return success, file_paths, used_backend def _compile_model(self, model_file_path: str, input_file_path: Optional[str] = None) -> str: + """ + Compile a single ONNX model file (not sliced) with backend fallback support. + """ if not os.path.isfile(model_file_path): raise ValueError(f"model_path must be a file: {model_file_path}") output_path_root = os.path.splitext(model_file_path)[0] - circuit_folder = os.path.join(os.path.dirname(output_path_root), "model") - os.makedirs(circuit_folder, exist_ok=True) - # Call backend pipeline - self.ezkl.compilation_pipeline(model_file_path, circuit_folder, input_file_path=input_file_path) - logger.info(f"Compilation completed. Output saved to {circuit_folder}") - return circuit_folder + + # Build list of backends to try (same logic as _compile_slice) + backends_to_try = [] + if self.default_backend: + # Specific backend requested + if self.default_backend == "jstprove": + jst = self._get_jstprove() + if jst: + backends_to_try.append((jst, "jstprove")) + else: + ezkl = self._get_ezkl() + if ezkl: + backends_to_try.append((ezkl, "ezkl")) + if self.use_fallback: + # Add fallback options + if self.default_backend == "jstprove": + ezkl = self._get_ezkl() + if ezkl: + backends_to_try.append((ezkl, "ezkl")) + else: + jst = self._get_jstprove() + if jst: + backends_to_try.append((jst, "jstprove")) + elif self.use_fallback: + # Default fallback: jstprove -> ezkl + jst = self._get_jstprove() + ezkl = self._get_ezkl() + if jst: + backends_to_try.append((jst, "jstprove")) + if ezkl: + backends_to_try.append((ezkl, "ezkl")) + else: + # No backend specified, no fallback - use EZKL as default + ezkl = self._get_ezkl() + if ezkl: + backends_to_try.append((ezkl, "ezkl")) + + if not backends_to_try: + raise RuntimeError("No backends available for compilation") + + # Try each backend until one succeeds + for try_backend, try_backend_name in backends_to_try: + circuit_folder = os.path.join(os.path.dirname(output_path_root), try_backend_name) + os.makedirs(circuit_folder, exist_ok=True) + try: + logger.info(f"Compiling model with {try_backend_name}...") + compilation_data = try_backend.compilation_pipeline( + model_file_path, circuit_folder, input_file_path=input_file_path + ) + success = CompilerUtils.is_ezkl_compilation_successful(compilation_data) + if success: + logger.info(f"Compilation completed with {try_backend_name}. Output saved to {circuit_folder}") + return circuit_folder + else: + logger.warning(f"{try_backend_name} compilation failed, trying fallback...") + except Exception as e: + logger.warning(f"{try_backend_name} error: {e}, trying fallback...") + if not self.use_fallback: + raise + + raise RuntimeError("All backends failed to compile the model") def _compile_slices(self, dir_path: str, input_file_path: Optional[str] = None, layer_indices=None): @@ -108,36 +326,54 @@ def _compile_slices(self, dir_path: str, input_file_path: Optional[str] = None, # Phase 2: Compile layers compiled_count = 0 skipped_count = 0 + backend_stats = {} # Track which backend was used for each slice for idx, slice_data in enumerate(slices_data): if layer_indices is not None and idx not in layer_indices: - logger.info(f"Skipping compilation for slice {idx} as it's not in the specified layers") + logger.info(f"Skipping ZK compilation for slice {idx} (not in specified layers) - will use pure ONNX at runtime") skipped_count += 1 continue logger.info(f"Compiling slice {idx}...") - success, file_paths = self._compile_slice(idx, slice_data, base_path) + success, file_paths, used_backend = self._compile_slice(idx, slice_data, base_path) compiled_count += 1 - logger.info(f"Completed slice {idx}") + backend_stats[idx] = used_backend + logger.info(f"Completed slice {idx} with {used_backend}") + + # Get version for the backend that was actually used + backend_version = None + if used_backend == "jstprove" and self._jstprove: + backend_version = self._jstprove.get_version() if hasattr(self._jstprove, 'get_version') else None + elif used_backend == "ezkl" and self._ezkl: + backend_version = self._ezkl.get_version() if hasattr(self._ezkl, 'get_version') else None comp_block = { "compiled": bool(success), "compilation_timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), - "ezkl_version": EZKL.get_version(), + "backend": used_backend, + "backend_version": backend_version, "files": file_paths } - # Attach under 'compilation.ezkl' + # Attach under 'compilation.' if isinstance(slice_data, dict): if 'compilation' not in slice_data or not isinstance(slice_data.get('compilation'), dict): slice_data['compilation'] = {} - slice_data['compilation']['ezkl'] = comp_block + slice_data['compilation'][used_backend] = comp_block # Save model-level metadata (or single slice metadata) Utils.save_metadata_file(metadata, os.path.dirname(metadata_path), os.path.basename(metadata_path)) - logger.info(f"Compilation of slices completed. Compiled {compiled_count} slices, skipped {skipped_count} slices.") + # Log summary + backend_summary = {} + for idx, backend in backend_stats.items(): + backend_summary[backend] = backend_summary.get(backend, 0) + 1 + summary_str = ", ".join(f"{k}: {v}" for k, v in backend_summary.items()) + if skipped_count > 0: + logger.info(f"Compilation completed. ZK compiled: {compiled_count} slices ({summary_str}). Skipped: {skipped_count} slices (will use pure ONNX at runtime)") + else: + logger.info(f"Compilation completed. ZK compiled: {compiled_count} slices. Backends used: {summary_str}") def compile(self, model_path: str, input_file: Optional[str] = None, layers: Optional[str] = None): @@ -159,7 +395,8 @@ def compile(self, model_path: str, input_file: Optional[str] = None, layers: Opt if layer_indices: logger.info(f"Will compile only layers with indices: {layer_indices}") else: - logger.info("Will compile all layers.") + # No layers specified: compile ALL layers with default fallback + logger.info("No layers specified. Will compile all layers with default fallback (jstprove -> ezkl -> onnx).") is_sliced, slice_path, type = CompilerUtils.is_sliced_model(model_path) if is_sliced: diff --git a/dsperse/src/compile/utils/compiler_utils.py b/dsperse/src/compile/utils/compiler_utils.py index 2824e41..f28c79f 100644 --- a/dsperse/src/compile/utils/compiler_utils.py +++ b/dsperse/src/compile/utils/compiler_utils.py @@ -105,12 +105,24 @@ def _with_slice_prefix(rel_path: Optional[str], slice_dirname: str) -> Optional[ def is_ezkl_compilation_successful(compilation_data: Dict[str, Any]) -> bool: """ Determine if compilation was successful based on produced file paths. - A path is considered valid if it exists and contains the 'payload' directory. + EZKL files are in payload subdirectories, JSTprove files are in backend directories. + Supports both EZKL and JSTprove backends. """ - def _ok(key: str) -> bool: + def _ok_ezkl(key: str) -> bool: p = compilation_data.get(key) return bool(p) and os.path.exists(p) and ('payload' in str(p).split(os.sep)) - return all([_ok('compiled'), _ok('vk_key'), _ok('pk_key'), _ok('settings')]) + + def _ok_jstprove(key: str) -> bool: + p = compilation_data.get(key) + return bool(p) and os.path.exists(p) # JSTprove doesn't use payload subdirs + + # Check if this is a JSTprove compilation (has 'circuit' key, no 'vk_key'/'pk_key') + if compilation_data.get('circuit') and not compilation_data.get('vk_key'): + # JSTprove requires 'compiled' (circuit) and 'settings' + return _ok_jstprove('compiled') and _ok_jstprove('settings') + + # EZKL requires compiled, vk_key, pk_key, settings + return all([_ok_ezkl('compiled'), _ok_ezkl('vk_key'), _ok_ezkl('pk_key'), _ok_ezkl('settings')]) @staticmethod def get_relative_paths(compilation_data: Dict[str, Any], calibration_input: Optional[str]) -> dict[str, str | None]: @@ -175,7 +187,7 @@ def build_model_level_ezkl(payload_rel: Dict[str, Optional[str]], calibration_re @staticmethod - def update_slice_metadata(idx, filepath: str | Path, success: bool, file_paths: Dict[str, str | None]): + def update_slice_metadata(idx: int, filepath: str | Path, success: bool, file_paths: Dict[str, str | None], backend_name: str = "ezkl"): """ Update the per-slice metadata.json file with compilation results. @@ -184,6 +196,7 @@ def update_slice_metadata(idx, filepath: str | Path, success: bool, file_paths: filepath: Path to the slice's metadata.json file success: Boolean indicating if compilation was successful file_paths: Dictionary containing file paths for compilation results + backend_name: Name of the backend used (jstprove, ezkl, or onnx) """ # Load existing slice metadata or create new if os.path.exists(filepath): @@ -192,14 +205,20 @@ def update_slice_metadata(idx, filepath: str | Path, success: bool, file_paths: else: slice_metadata = {} - # Get EZKL version - ezkl_version = EZKL.get_version() + # Get backend version based on which backend was used + if backend_name == "jstprove": + from dsperse.src.backends.JSTprove import JSTprove + backend_version = JSTprove.get_version() + elif backend_name == "ezkl": + backend_version = EZKL.get_version() + else: + backend_version = None - # Create compilation info nested under 'ezkl' - ezkl_compilation_info = { + # Create compilation info nested under the backend name + compilation_info = { "compiled": success, "compilation_timestamp": __import__('time').strftime("%Y-%m-%d %H:%M:%S"), - "ezkl_version": ezkl_version, + "backend_version": backend_version, "files": { "settings": file_paths.get('settings'), "compiled_circuit": file_paths.get('compiled'), @@ -212,7 +231,7 @@ def update_slice_metadata(idx, filepath: str | Path, success: bool, file_paths: # Add any errors if present errors = {k: v for k, v in file_paths.items() if k.endswith('_error')} if errors: - ezkl_compilation_info["errors"] = errors + compilation_info["errors"] = errors # Find the specific slice by index and update its compilation info updated = False @@ -221,18 +240,22 @@ def update_slice_metadata(idx, filepath: str | Path, success: bool, file_paths: if slice_item.get('index') == idx: if 'compilation' not in slice_item: slice_item['compilation'] = {} - slice_item['compilation']['ezkl'] = ezkl_compilation_info + slice_item['compilation'][backend_name] = compilation_info updated = True break if not updated: - logger.warning(f"Slice with index {idx} not found in metadata. Compilation info not added to slice.") + # Fallback: update at root level if slice not found in list + if 'compilation' not in slice_metadata: + slice_metadata['compilation'] = {} + slice_metadata['compilation'][backend_name] = compilation_info + logger.debug(f"Slice with index {idx} not found in slices list. Added compilation info at root level.") # Save updated slice metadata with open(filepath, 'w') as f: json.dump(slice_metadata, f, indent=2) - logger.debug(f"Updated slice metadata at {filepath}") + logger.debug(f"Updated slice metadata at {filepath} for backend {backend_name}") @staticmethod diff --git a/dsperse/src/constants.py b/dsperse/src/constants.py index a9daf1c..ece5cdf 100644 --- a/dsperse/src/constants.py +++ b/dsperse/src/constants.py @@ -3,6 +3,7 @@ """ from pathlib import Path +# EZKL configuration MIN_EZKL_VERSION = "22.0.0" EZKL_PATH = Path.home() / ".ezkl" / "ezkl" SRS_DIR = Path.home() / ".ezkl" / "srs" @@ -10,4 +11,7 @@ SRS_LOGROWS_MIN = 2 SRS_LOGROWS_MAX = 24 SRS_LOGROWS_RANGE = range(SRS_LOGROWS_MIN, SRS_LOGROWS_MAX + 1) -SRS_FILES = [f"kzg{n}.srs" for n in SRS_LOGROWS_RANGE] \ No newline at end of file +SRS_FILES = [f"kzg{n}.srs" for n in SRS_LOGROWS_RANGE] + +# JSTprove CLI command +JSTPROVE_COMMAND = "jst" \ No newline at end of file diff --git a/dsperse/src/run/runner.py b/dsperse/src/run/runner.py index 1cabb09..4852a8e 100644 --- a/dsperse/src/run/runner.py +++ b/dsperse/src/run/runner.py @@ -13,6 +13,7 @@ from dsperse.src.analyzers.runner_analyzer import RunnerAnalyzer from dsperse.src.backends.ezkl import EZKL +from dsperse.src.backends.JSTprove import JSTprove from dsperse.src.backends.onnx_models import OnnxModels from dsperse.src.run.utils.runner_utils import RunnerUtils from dsperse.src.slice.utils.converter import Converter @@ -31,6 +32,11 @@ def __init__(self, run_metadata_path: str = None, save_metadata_path: str = None self.run_metadata = None self.ezkl_runner = EZKL() + try: + self.jstprove_runner = JSTprove() + except RuntimeError: + self.jstprove_runner = None + logger.warning("JSTprove CLI not available. JSTprove backend will be disabled.") def run(self, input_json_path, slice_path: str, output_path: str = None) -> dict: @@ -151,6 +157,56 @@ def _resolve_rel_path(p: str, base_dir: Path) -> str: return success, output_tensor, exec_info + def _run_jstprove_slice(self, slice_info: dict, input_tensor_path, output_witness_path, slice_dir: Path = None): + """Run JSTprove inference for a slice with fallback to ONNX. + Accepts paths possibly formatted as `slice_#/payload/...` or `payload/...` and resolves them + under the provided `slice_dir` if necessary. + """ + if self.jstprove_runner is None: + return False, "JSTprove CLI not available", {'success': False, 'method': 'jstprove_gen_witness', 'error': 'JSTprove CLI not available'} + + def _resolve_rel_path(p: str, base_dir: Path) -> str: + path = str((base_dir / p).resolve()) + if not Path(path).exists(): + path = str((Path(base_dir).parent / Path(p)).resolve()) + return path + + circuit_path = slice_info.get("circuit_path") + settings_path = slice_info.get("settings_path") + + # Resolve possibly relative paths + if circuit_path and not os.path.isabs(str(circuit_path)): + circuit_path = _resolve_rel_path(circuit_path, slice_dir) + + start_time = time.time() + # Attempt JSTprove execution + try: + success, output_tensor = self.jstprove_runner.generate_witness( + input_file=input_tensor_path, + model_path=circuit_path, + output_file=output_witness_path, + ) + except Exception as e: + success = False + output_tensor = str(e) + + end_time = time.time() + exec_info = { + 'success': success, + 'method': 'jstprove_gen_witness', + 'execution_time': end_time - start_time, + 'witness_path': str(output_witness_path), + 'attempted_jstprove': True + } + + if success: + exec_info['input_file'] = str(input_tensor_path.resolve()) + exec_info['output_file'] = str(output_witness_path.resolve()) + else: + exec_info['error'] = output_tensor if isinstance(output_tensor, str) else "Unknown JSTprove error" + + return success, output_tensor, exec_info + def _save_inference_output(self, results, output_path): """Save inference_output.json with execution details.""" model_path = self.run_metadata.get("model_path", "unknown") diff --git a/install.sh b/install.sh index ec317bf..3e76a9f 100755 --- a/install.sh +++ b/install.sh @@ -1,9 +1,11 @@ #!/usr/bin/env bash -# install.sh - Installer for Dsperse CLI and EZKL (with lookup tables) +# install.sh - Installer for Dsperse CLI, JSTproveand EZKL (with lookup tables) # This script installs: # - Dsperse CLI (python package, console script: dsperse) # - EZKL CLI (if missing) # - EZKL lookup tables (if missing) +# - Open MPI (required for JSTprove) +# - JSTprove CLI (if missing) # It detects existing installations and will skip or prompt accordingly. set -euo pipefail @@ -198,6 +200,113 @@ ensure_ezkl() { fi } +# Install Open MPI (required for JSTprove) +install_openmpi() { + info "Checking for Open MPI installation..." + if command -v mpirun >/dev/null 2>&1; then + info "Open MPI already installed: $(command -v mpirun)" + mpirun --version 2>/dev/null | head -n1 || true + return 0 + fi + + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS - use Homebrew + if command -v brew >/dev/null 2>&1; then + info "Installing Open MPI via Homebrew..." + if brew install open-mpi; then + info "Open MPI installed successfully via Homebrew" + else + warn "Failed to install Open MPI via Homebrew" + fi + else + warn "Homebrew not found. Please install Homebrew first, then run: brew install open-mpi" + fi + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + # Linux - try apt or yum + if command -v apt-get >/dev/null 2>&1; then + info "Installing Open MPI via apt..." + if sudo apt-get update && sudo apt-get install -y openmpi-bin libopenmpi-dev; then + info "Open MPI installed successfully via apt" + else + warn "Failed to install Open MPI via apt" + fi + elif command -v yum >/dev/null 2>&1; then + info "Installing Open MPI via yum..." + if sudo yum install -y openmpi openmpi-devel; then + info "Open MPI installed successfully via yum" + else + warn "Failed to install Open MPI via yum" + fi + else + warn "Could not detect package manager. Please install Open MPI manually." + fi + else + warn "Unsupported OS for automatic Open MPI installation. Please install manually." + fi + + if command -v mpirun >/dev/null 2>&1; then + info "Open MPI is now available: $(command -v mpirun)" + else + warn "Open MPI installation may require PATH configuration. Check your shell profile." + fi +} + +# Install JSTprove via uv +install_jstprove() { + info "Checking for JSTprove installation..." + + # Add common uv tool bin paths to PATH for detection + export PATH="$HOME/.local/bin:$PATH" + + if command -v jst >/dev/null 2>&1; then + info "JSTprove already installed: $(command -v jst)" + jst --version 2>/dev/null || jst --help 2>/dev/null | head -n1 || true + if [[ "$INTERACTIVE" == true ]] && confirm "Reinstall/upgrade JSTprove?"; then + : + else + info "Skipping JSTprove install." + return 0 + fi + fi + + # Check if uv is available + if command -v uv >/dev/null 2>&1; then + info "Installing JSTprove via uv..." + if uv tool install jstprove 2>/dev/null || uv pip install jstprove 2>/dev/null; then + info "JSTprove installed successfully via uv" + # Add uv tool bin to PATH + export PATH="$HOME/.local/bin:$PATH" + info "Added $HOME/.local/bin to PATH for JSTprove" + else + warn "Failed to install JSTprove via uv. Trying pip..." + if eval $PIP_BIN install jstprove 2>/dev/null; then + info "JSTprove installed successfully via pip" + else + warn "Failed to install JSTprove. Please install manually: uv tool install jstprove" + fi + fi + else + # Fallback to pip + info "uv not found. Installing JSTprove via pip..." + if eval $PIP_BIN install jstprove 2>/dev/null; then + info "JSTprove installed successfully via pip" + else + warn "Failed to install JSTprove via pip. Please install uv first: curl -LsSf https://astral.sh/uv/install.sh | sh" + warn "Then install JSTprove: uv tool install jstprove" + fi + fi + + if command -v jst >/dev/null 2>&1; then + info "JSTprove is now available: $(command -v jst)" + jst --version 2>/dev/null || jst --help 2>/dev/null | head -n1 || true + else + warn "JSTprove CLI (jst) not found on PATH." + warn "You may need to add ~/.local/bin to your PATH:" + warn " export PATH=\"\$HOME/.local/bin:\$PATH\"" + warn "Add this line to your shell profile (~/.bashrc, ~/.zshrc, etc.) for persistence." + fi +} + # Ensure SRS files (kzg commitment) exist under ~/.ezkl/srs ensure_srs() { if ! command -v ezkl >/dev/null 2>&1; then @@ -370,6 +479,12 @@ main() { # Lookup tables (for some ezkl versions) install_lookup_tables + # Install Open MPI (required for JSTprove) + install_openmpi + + # Install JSTprove + install_jstprove + # Final verification step for EZKL and SRS verify_environment_post_install @@ -386,6 +501,12 @@ main() { warn "EZKL not detected; some features will fall back to ONNX or fail." fi + if command -v jst >/dev/null 2>&1; then + info "JSTprove is ready: jst --help" + else + warn "JSTprove not detected; JSTprove backend features will not be available." + fi + say "\nInstallation complete!" } diff --git a/requirements.txt b/requirements.txt index a14c926..99c21c4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,894 +1,15 @@ -# This file was autogenerated by uv via the following command: -# uv export -o requirements.txt --e . -colorama==0.4.6 \ - --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ - --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 - # via - # dsperse - # pytest - # tqdm -coloredlogs==15.0.1 \ - --hash=sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934 \ - --hash=sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0 - # via onnxruntime -contourpy==1.3.2 ; python_full_version < '3.11' \ - --hash=sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f \ - --hash=sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92 \ - --hash=sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16 \ - --hash=sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f \ - --hash=sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f \ - --hash=sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7 \ - --hash=sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e \ - --hash=sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08 \ - --hash=sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841 \ - --hash=sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5 \ - --hash=sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2 \ - --hash=sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415 \ - --hash=sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878 \ - --hash=sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0 \ - --hash=sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab \ - --hash=sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445 \ - --hash=sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43 \ - --hash=sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c \ - --hash=sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823 \ - --hash=sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69 \ - --hash=sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15 \ - --hash=sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef \ - --hash=sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5 \ - --hash=sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73 \ - --hash=sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9 \ - --hash=sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912 \ - --hash=sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5 \ - --hash=sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85 \ - --hash=sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d \ - --hash=sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631 \ - --hash=sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2 \ - --hash=sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54 \ - --hash=sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773 \ - --hash=sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934 \ - --hash=sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a \ - --hash=sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441 \ - --hash=sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422 \ - --hash=sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532 \ - --hash=sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739 \ - --hash=sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b \ - --hash=sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f \ - --hash=sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1 \ - --hash=sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87 \ - --hash=sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52 \ - --hash=sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1 \ - --hash=sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd \ - --hash=sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989 \ - --hash=sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb \ - --hash=sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f \ - --hash=sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad \ - --hash=sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9 \ - --hash=sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512 \ - --hash=sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd \ - --hash=sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83 \ - --hash=sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe \ - --hash=sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0 \ - --hash=sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c - # via matplotlib -contourpy==1.3.3 ; python_full_version >= '3.11' \ - --hash=sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69 \ - --hash=sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc \ - --hash=sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880 \ - --hash=sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a \ - --hash=sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8 \ - --hash=sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc \ - --hash=sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470 \ - --hash=sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5 \ - --hash=sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263 \ - --hash=sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b \ - --hash=sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5 \ - --hash=sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381 \ - --hash=sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3 \ - --hash=sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4 \ - --hash=sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e \ - --hash=sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f \ - --hash=sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772 \ - --hash=sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286 \ - --hash=sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42 \ - --hash=sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301 \ - --hash=sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77 \ - --hash=sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7 \ - --hash=sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411 \ - --hash=sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1 \ - --hash=sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9 \ - --hash=sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a \ - --hash=sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b \ - --hash=sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db \ - --hash=sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6 \ - --hash=sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620 \ - --hash=sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989 \ - --hash=sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea \ - --hash=sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67 \ - --hash=sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5 \ - --hash=sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d \ - --hash=sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36 \ - --hash=sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99 \ - --hash=sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1 \ - --hash=sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e \ - --hash=sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b \ - --hash=sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8 \ - --hash=sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d \ - --hash=sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7 \ - --hash=sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7 \ - --hash=sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339 \ - --hash=sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1 \ - --hash=sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659 \ - --hash=sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4 \ - --hash=sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f \ - --hash=sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20 \ - --hash=sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36 \ - --hash=sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb \ - --hash=sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d \ - --hash=sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8 \ - --hash=sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0 \ - --hash=sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b \ - --hash=sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7 \ - --hash=sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe \ - --hash=sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77 \ - --hash=sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497 \ - --hash=sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd \ - --hash=sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1 \ - --hash=sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216 \ - --hash=sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13 \ - --hash=sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae \ - --hash=sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae \ - --hash=sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77 \ - --hash=sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3 \ - --hash=sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f \ - --hash=sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff \ - --hash=sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9 \ - --hash=sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a - # via matplotlib -cycler==0.12.1 \ - --hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 \ - --hash=sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c - # via matplotlib -exceptiongroup==1.3.1 ; python_full_version < '3.11' \ - --hash=sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219 \ - --hash=sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598 - # via pytest -ezkl==22.2.1 \ - --hash=sha256:0a939581175fdef2fab356927d9c4395c22e99c8b00fa80c08edb86ccd6fa9c0 \ - --hash=sha256:6c2353fede3155b9b588e61824e7505b33d0f9b8716cf2b99fe1aaa022840220 \ - --hash=sha256:7b0a7aac78858934821d3cb3ec620684d28f7b679f485dd03108932f51032ca5 \ - --hash=sha256:a5db874cbb59747118a90d050eb382dea6392775ccb85cdb8b954efe5bc2201e \ - --hash=sha256:b2f6d0fb2bc037355e6f3ec3a73714f10e6a68aaf43a0f15c15d13f308b2f69c \ - --hash=sha256:b8eac3f42cd3aa3a6879925a07469f8fef7aba0279efdaabd6cb31b706b22e5b \ - --hash=sha256:c3b9fea855c11165b74f3f97bf01510ecc3249dc6e2eba02674c9f5967924df1 - # via dsperse -filelock==3.20.0 \ - --hash=sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2 \ - --hash=sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4 - # via torch -flatbuffers==25.9.23 \ - --hash=sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2 \ - --hash=sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12 - # via onnxruntime -fonttools==4.61.0 \ - --hash=sha256:0011d640afa61053bc6590f9a3394bd222de7cfde19346588beabac374e9d8ac \ - --hash=sha256:02bdf8e04d1a70476564b8640380f04bb4ac74edc1fc71f1bacb840b3e398ee9 \ - --hash=sha256:0bdcf2e29d65c26299cc3d502f4612365e8b90a939f46cd92d037b6cb7bb544a \ - --hash=sha256:13e3e20a5463bfeb77b3557d04b30bd6a96a6bb5c15c7b2e7908903e69d437a0 \ - --hash=sha256:14a290c5c93fcab76b7f451e6a4b7721b712d90b3b5ed6908f1abcf794e90d6d \ - --hash=sha256:14fafda386377b6131d9e448af42d0926bad47e038de0e5ba1d58c25d621f028 \ - --hash=sha256:1cfa2eb9bae650e58f0e8ad53c49d19a844d6034d6b259f30f197238abc1ccee \ - --hash=sha256:276f14c560e6f98d24ef7f5f44438e55ff5a67f78fa85236b218462c9f5d0635 \ - --hash=sha256:2cb5e45a824ce14b90510024d0d39dae51bd4fbb54c42a9334ea8c8cf4d95cbe \ - --hash=sha256:2de14557d113faa5fb519f7f29c3abe4d69c17fe6a5a2595cc8cda7338029219 \ - --hash=sha256:2f0bafc8a3b3749c69cc610e5aa3da832d39c2a37a68f03d18ec9a02ecaac04a \ - --hash=sha256:328a9c227984bebaf69f3ac9062265f8f6acc7ddf2e4e344c63358579af0aa3d \ - --hash=sha256:3b2065d94e5d63aafc2591c8b6ccbdb511001d9619f1bca8ad39b745ebeb5efa \ - --hash=sha256:4238120002e68296d55e091411c09eab94e111c8ce64716d17df53fd0eb3bb3d \ - --hash=sha256:46cb3d9279f758ac0cf671dc3482da877104b65682679f01b246515db03dbb72 \ - --hash=sha256:58b4f1b78dfbfe855bb8a6801b31b8cdcca0e2847ec769ad8e0b0b692832dd3b \ - --hash=sha256:59587bbe455dbdf75354a9dbca1697a35a8903e01fab4248d6b98a17032cee52 \ - --hash=sha256:5a9b78da5d5faa17e63b2404b77feeae105c1b7e75f26020ab7a27b76e02039f \ - --hash=sha256:627216062d90ab0d98215176d8b9562c4dd5b61271d35f130bcd30f6a8aaa33a \ - --hash=sha256:63c7125d31abe3e61d7bb917329b5543c5b3448db95f24081a13aaf064360fc8 \ - --hash=sha256:6781e7a4bb010be1cd69a29927b0305c86b843395f2613bdabe115f7d6ea7f34 \ - --hash=sha256:67d841aa272be5500de7f447c40d1d8452783af33b4c3599899319f6ef9ad3c1 \ - --hash=sha256:68704a8bbe0b61976262b255e90cde593dc0fe3676542d9b4d846bad2a890a76 \ - --hash=sha256:6b493c32d2555e9944ec1b911ea649ff8f01a649ad9cba6c118d6798e932b3f0 \ - --hash=sha256:6e5ca8c62efdec7972dfdfd454415c4db49b89aeaefaaacada432f3b7eea9866 \ - --hash=sha256:70e2a0c0182ee75e493ef33061bfebf140ea57e035481d2f95aa03b66c7a0e05 \ - --hash=sha256:787ef9dfd1ea9fe49573c272412ae5f479d78e671981819538143bec65863865 \ - --hash=sha256:7b446623c9cd5f14a59493818eaa80255eec2468c27d2c01b56e05357c263195 \ - --hash=sha256:7fb5b84f48a6a733ca3d7f41aa9551908ccabe8669ffe79586560abcc00a9cfd \ - --hash=sha256:9064b0f55b947e929ac669af5311ab1f26f750214db6dd9a0c97e091e918f486 \ - --hash=sha256:96dfc9bc1f2302224e48e6ee37e656eddbab810b724b52e9d9c13a57a6abad01 \ - --hash=sha256:9821ed77bb676736b88fa87a737c97b6af06e8109667e625a4f00158540ce044 \ - --hash=sha256:a32a16951cbf113d38f1dd8551b277b6e06e0f6f776fece0f99f746d739e1be3 \ - --hash=sha256:a5c5fff72bf31b0e558ed085e4fd7ed96eb85881404ecc39ed2a779e7cf724eb \ - --hash=sha256:ad751319dc532a79bdf628b8439af167181b4210a0cd28a8935ca615d9fdd727 \ - --hash=sha256:adbb4ecee1a779469a77377bbe490565effe8fce6fb2e6f95f064de58f8bac85 \ - --hash=sha256:b2b734d8391afe3c682320840c8191de9bd24e7eb85768dd4dc06ed1b63dbb1b \ - --hash=sha256:b5ca59b7417d149cf24e4c1933c9f44b2957424fc03536f132346d5242e0ebe5 \ - --hash=sha256:b6ceac262cc62bec01b3bb59abccf41b24ef6580869e306a4e88b7e56bb4bdda \ - --hash=sha256:ba774b8cbd8754f54b8eb58124e8bd45f736b2743325ab1a5229698942b9b433 \ - --hash=sha256:c53b47834ae41e8e4829171cc44fec0fdf125545a15f6da41776b926b9645a9a \ - --hash=sha256:c84b430616ed73ce46e9cafd0bf0800e366a3e02fb7e1ad7c1e214dbe3862b1f \ - --hash=sha256:dc25a4a9c1225653e4431a9413d0381b1c62317b0f543bdcec24e1991f612f33 \ - --hash=sha256:df8cbce85cf482eb01f4551edca978c719f099c623277bda8332e5dbe7dba09d \ - --hash=sha256:e074bc07c31406f45c418e17c1722e83560f181d122c412fa9e815df0ff74810 \ - --hash=sha256:e0d87e81e4d869549585ba0beb3f033718501c1095004f5e6aef598d13ebc216 \ - --hash=sha256:e24a1565c4e57111ec7f4915f8981ecbb61adf66a55f378fdc00e206059fcfef \ - --hash=sha256:e2bfacb5351303cae9f072ccf3fc6ecb437a6f359c0606bae4b1ab6715201d87 \ - --hash=sha256:e6cd0d9051b8ddaf7385f99dd82ec2a058e2b46cf1f1961e68e1ff20fcbb61af \ - --hash=sha256:ec520a1f0c7758d7a858a00f090c1745f6cde6a7c5e76fb70ea4044a15f712e7 - # via matplotlib -fsspec==2025.10.0 \ - --hash=sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d \ - --hash=sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59 - # via torch -humanfriendly==10.0 \ - --hash=sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477 \ - --hash=sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc - # via coloredlogs -iniconfig==2.3.0 \ - --hash=sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730 \ - --hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12 - # via pytest -jinja2==3.1.6 \ - --hash=sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d \ - --hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67 - # via torch -kiwisolver==1.4.9 \ - --hash=sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c \ - --hash=sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7 \ - --hash=sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21 \ - --hash=sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e \ - --hash=sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff \ - --hash=sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7 \ - --hash=sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c \ - --hash=sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26 \ - --hash=sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa \ - --hash=sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f \ - --hash=sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1 \ - --hash=sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891 \ - --hash=sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77 \ - --hash=sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543 \ - --hash=sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d \ - --hash=sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce \ - --hash=sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3 \ - --hash=sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60 \ - --hash=sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a \ - --hash=sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089 \ - --hash=sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab \ - --hash=sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78 \ - --hash=sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771 \ - --hash=sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f \ - --hash=sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b \ - --hash=sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14 \ - --hash=sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32 \ - --hash=sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527 \ - --hash=sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185 \ - --hash=sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634 \ - --hash=sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed \ - --hash=sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1 \ - --hash=sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c \ - --hash=sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11 \ - --hash=sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752 \ - --hash=sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5 \ - --hash=sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4 \ - --hash=sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58 \ - --hash=sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5 \ - --hash=sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198 \ - --hash=sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536 \ - --hash=sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134 \ - --hash=sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf \ - --hash=sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2 \ - --hash=sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2 \ - --hash=sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370 \ - --hash=sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1 \ - --hash=sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154 \ - --hash=sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b \ - --hash=sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197 \ - --hash=sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386 \ - --hash=sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a \ - --hash=sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48 \ - --hash=sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748 \ - --hash=sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c \ - --hash=sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8 \ - --hash=sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5 \ - --hash=sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999 \ - --hash=sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369 \ - --hash=sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122 \ - --hash=sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b \ - --hash=sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098 \ - --hash=sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9 \ - --hash=sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f \ - --hash=sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799 \ - --hash=sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028 \ - --hash=sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2 \ - --hash=sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525 \ - --hash=sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d \ - --hash=sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb \ - --hash=sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872 \ - --hash=sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64 \ - --hash=sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586 \ - --hash=sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf \ - --hash=sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552 \ - --hash=sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2 \ - --hash=sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415 \ - --hash=sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c \ - --hash=sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6 \ - --hash=sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64 \ - --hash=sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d \ - --hash=sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548 \ - --hash=sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07 \ - --hash=sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61 \ - --hash=sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d \ - --hash=sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771 \ - --hash=sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9 \ - --hash=sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c \ - --hash=sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3 \ - --hash=sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16 \ - --hash=sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145 \ - --hash=sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611 \ - --hash=sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2 \ - --hash=sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464 \ - --hash=sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2 \ - --hash=sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04 \ - --hash=sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54 \ - --hash=sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df \ - --hash=sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f \ - --hash=sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1 \ - --hash=sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220 - # via matplotlib -markupsafe==3.0.3 \ - --hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \ - --hash=sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a \ - --hash=sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf \ - --hash=sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19 \ - --hash=sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf \ - --hash=sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175 \ - --hash=sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219 \ - --hash=sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb \ - --hash=sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6 \ - --hash=sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab \ - --hash=sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1 \ - --hash=sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce \ - --hash=sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218 \ - --hash=sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634 \ - --hash=sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695 \ - --hash=sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad \ - --hash=sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73 \ - --hash=sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c \ - --hash=sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe \ - --hash=sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa \ - --hash=sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559 \ - --hash=sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa \ - --hash=sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37 \ - --hash=sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f \ - --hash=sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d \ - --hash=sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c \ - --hash=sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97 \ - --hash=sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a \ - --hash=sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19 \ - --hash=sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9 \ - --hash=sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9 \ - --hash=sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc \ - --hash=sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4 \ - --hash=sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354 \ - --hash=sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50 \ - --hash=sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698 \ - --hash=sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9 \ - --hash=sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b \ - --hash=sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc \ - --hash=sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115 \ - --hash=sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485 \ - --hash=sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f \ - --hash=sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12 \ - --hash=sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025 \ - --hash=sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009 \ - --hash=sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d \ - --hash=sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a \ - --hash=sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5 \ - --hash=sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f \ - --hash=sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1 \ - --hash=sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287 \ - --hash=sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6 \ - --hash=sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f \ - --hash=sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581 \ - --hash=sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed \ - --hash=sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b \ - --hash=sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c \ - --hash=sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026 \ - --hash=sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8 \ - --hash=sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676 \ - --hash=sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6 \ - --hash=sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e \ - --hash=sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d \ - --hash=sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d \ - --hash=sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01 \ - --hash=sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419 \ - --hash=sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795 \ - --hash=sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1 \ - --hash=sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5 \ - --hash=sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d \ - --hash=sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe \ - --hash=sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda \ - --hash=sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e \ - --hash=sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737 \ - --hash=sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523 \ - --hash=sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591 \ - --hash=sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a \ - --hash=sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50 - # via jinja2 -matplotlib==3.10.7 \ - --hash=sha256:07124afcf7a6504eafcb8ce94091c5898bbdd351519a1beb5c45f7a38c67e77f \ - --hash=sha256:09d7945a70ea43bf9248f4b6582734c2fe726723204a76eca233f24cffc7ef67 \ - --hash=sha256:0d8c32b7ea6fb80b1aeff5a2ceb3fb9778e2759e899d9beff75584714afcc5ee \ - --hash=sha256:11ae579ac83cdf3fb72573bb89f70e0534de05266728740d478f0f818983c695 \ - --hash=sha256:15112bcbaef211bd663fa935ec33313b948e214454d949b723998a43357b17b0 \ - --hash=sha256:1d9d3713a237970569156cfb4de7533b7c4eacdd61789726f444f96a0d28f57f \ - --hash=sha256:1e4bbad66c177a8fdfa53972e5ef8be72a5f27e6a607cec0d8579abd0f3102b1 \ - --hash=sha256:2222c7ba2cbde7fe63032769f6eb7e83ab3227f47d997a8453377709b7fe3a5a \ - --hash=sha256:22df30ffaa89f6643206cf13877191c63a50e8f800b038bc39bee9d2d4957632 \ - --hash=sha256:31963603041634ce1a96053047b40961f7a29eb8f9a62e80cc2c0427aa1d22a2 \ - --hash=sha256:37a1fea41153dd6ee061d21ab69c9cf2cf543160b1b85d89cd3d2e2a7902ca4c \ - --hash=sha256:3886e47f64611046bc1db523a09dd0a0a6bed6081e6f90e13806dd1d1d1b5e91 \ - --hash=sha256:4645fc5d9d20ffa3a39361fcdbcec731382763b623b72627806bf251b6388866 \ - --hash=sha256:4a11c2e9e72e7de09b7b72e62f3df23317c888299c875e2b778abf1eda8c0a42 \ - --hash=sha256:4a74f79fafb2e177f240579bc83f0b60f82cc47d2f1d260f422a0627207008ca \ - --hash=sha256:4c14b6acd16cddc3569a2d515cfdd81c7a68ac5639b76548cfc1a9e48b20eb65 \ - --hash=sha256:53b492410a6cd66c7a471de6c924f6ede976e963c0f3097a3b7abfadddc67d0a \ - --hash=sha256:53cc80662dd197ece414dd5b66e07370201515a3eaf52e7c518c68c16814773b \ - --hash=sha256:5c09cf8f2793f81368f49f118b6f9f937456362bee282eac575cca7f84cda537 \ - --hash=sha256:5e38c2d581d62ee729a6e144c47a71b3f42fb4187508dbbf4fe71d5612c3433b \ - --hash=sha256:5f3f6d315dcc176ba7ca6e74c7768fb7e4cf566c49cb143f6bc257b62e634ed8 \ - --hash=sha256:6516ce375109c60ceec579e699524e9d504cd7578506f01150f7a6bc174a775e \ - --hash=sha256:667ecd5d8d37813a845053d8f5bf110b534c3c9f30e69ebd25d4701385935a6d \ - --hash=sha256:6f1851eab59ca082c95df5a500106bad73672645625e04538b3ad0f69471ffcc \ - --hash=sha256:702590829c30aada1e8cef0568ddbffa77ca747b4d6e36c6d173f66e301f89cc \ - --hash=sha256:7146d64f561498764561e9cd0ed64fcf582e570fc519e6f521e2d0cfd43365e1 \ - --hash=sha256:744991e0cc863dd669c8dc9136ca4e6e0082be2070b9d793cbd64bec872a6815 \ - --hash=sha256:786656bb13c237bbcebcd402f65f44dd61ead60ee3deb045af429d889c8dbc67 \ - --hash=sha256:7a0edb7209e21840e8361e91ea84ea676658aa93edd5f8762793dec77a4a6748 \ - --hash=sha256:7ac81eee3b7c266dd92cee1cd658407b16c57eed08c7421fa354ed68234de380 \ - --hash=sha256:90ad854c0a435da3104c01e2c6f0028d7e719b690998a2333d7218db80950722 \ - --hash=sha256:9257be2f2a03415f9105c486d304a321168e61ad450f6153d77c69504ad764bb \ - --hash=sha256:932c55d1fa7af4423422cb6a492a31cbcbdbe68fd1a9a3f545aa5e7a143b5355 \ - --hash=sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7 \ - --hash=sha256:aebed7b50aa6ac698c90f60f854b47e48cd2252b30510e7a1feddaf5a3f72cbf \ - --hash=sha256:b172db79759f5f9bc13ef1c3ef8b9ee7b37b0247f987fbbbdaa15e4f87fd46a9 \ - --hash=sha256:b3c4ea4948d93c9c29dc01c0c23eef66f2101bf75158c291b88de6525c55c3d1 \ - --hash=sha256:b498e9e4022f93de2d5a37615200ca01297ceebbb56fe4c833f46862a490f9e3 \ - --hash=sha256:b4d41379b05528091f00e1728004f9a8d7191260f3862178b88e8fd770206318 \ - --hash=sha256:b69676845a0a66f9da30e87f48be36734d6748024b525ec4710be40194282c84 \ - --hash=sha256:c17398b709a6cce3d9fdb1595c33e356d91c098cd9486cb2cc21ea2ea418e715 \ - --hash=sha256:c380371d3c23e0eadf8ebff114445b9f970aff2010198d498d4ab4c3b41eea4f \ - --hash=sha256:cb783436e47fcf82064baca52ce748af71725d0352e1d31564cbe9c95df92b9c \ - --hash=sha256:cc1c51b846aca49a5a8b44fbba6a92d583a35c64590ad9e1e950dc88940a4297 \ - --hash=sha256:d0b181e9fa8daf1d9f2d4c547527b167cb8838fc587deabca7b5c01f97199e84 \ - --hash=sha256:d2a959c640cdeecdd2ec3136e8ea0441da59bcaf58d67e9c590740addba2cb68 \ - --hash=sha256:d5f256d49fea31f40f166a5e3131235a5d2f4b7f44520b1cf0baf1ce568ccff0 \ - --hash=sha256:d883460c43e8c6b173fef244a2341f7f7c0e9725c7fe68306e8e44ed9c8fb100 \ - --hash=sha256:d8eb7194b084b12feb19142262165832fc6ee879b945491d1c3d4660748020c4 \ - --hash=sha256:d9749313deb729f08207718d29c86246beb2ea3fdba753595b55901dee5d2fd6 \ - --hash=sha256:de66744b2bb88d5cd27e80dfc2ec9f0517d0a46d204ff98fe9e5f2864eb67657 \ - --hash=sha256:e91f61a064c92c307c5a9dc8c05dc9f8a68f0a3be199d9a002a0622e13f874a1 \ - --hash=sha256:f19410b486fdd139885ace124e57f938c1e6a3210ea13dd29cab58f5d4bc12c7 \ - --hash=sha256:f79d5de970fc90cd5591f60053aecfce1fcd736e0303d9f0bf86be649fa68fb8 \ - --hash=sha256:fba2974df0bf8ce3c995fa84b79cde38326e0f7b5409e7a3a481c1141340bcf7 - # via dsperse -mpmath==1.3.0 \ - --hash=sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f \ - --hash=sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c - # via sympy -networkx==3.4.2 \ - --hash=sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1 \ - --hash=sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f - # via - # dsperse - # torch -numpy==2.2.6 \ - --hash=sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff \ - --hash=sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47 \ - --hash=sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84 \ - --hash=sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d \ - --hash=sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6 \ - --hash=sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f \ - --hash=sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b \ - --hash=sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49 \ - --hash=sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163 \ - --hash=sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571 \ - --hash=sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42 \ - --hash=sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff \ - --hash=sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491 \ - --hash=sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4 \ - --hash=sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566 \ - --hash=sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf \ - --hash=sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40 \ - --hash=sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd \ - --hash=sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06 \ - --hash=sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282 \ - --hash=sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680 \ - --hash=sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db \ - --hash=sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3 \ - --hash=sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90 \ - --hash=sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1 \ - --hash=sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289 \ - --hash=sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab \ - --hash=sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c \ - --hash=sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d \ - --hash=sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb \ - --hash=sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d \ - --hash=sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a \ - --hash=sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf \ - --hash=sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1 \ - --hash=sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2 \ - --hash=sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a \ - --hash=sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543 \ - --hash=sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00 \ - --hash=sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c \ - --hash=sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f \ - --hash=sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd \ - --hash=sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868 \ - --hash=sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303 \ - --hash=sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83 \ - --hash=sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3 \ - --hash=sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d \ - --hash=sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87 \ - --hash=sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa \ - --hash=sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f \ - --hash=sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae \ - --hash=sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda \ - --hash=sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915 \ - --hash=sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249 \ - --hash=sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de \ - --hash=sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8 - # via - # contourpy - # dsperse - # matplotlib - # onnx - # onnxruntime -nvidia-cublas-cu12==12.6.4.1 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:08ed2686e9875d01b58e3cb379c6896df8e76c75e0d4a7f7dace3d7b6d9ef8eb - # via - # nvidia-cudnn-cu12 - # nvidia-cusolver-cu12 - # torch -nvidia-cuda-cupti-cu12==12.6.80 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:6768bad6cab4f19e8292125e5f1ac8aa7d1718704012a0e3272a6f61c4bce132 \ - --hash=sha256:a3eff6cdfcc6a4c35db968a06fcadb061cbc7d6dde548609a941ff8701b98b73 - # via torch -nvidia-cuda-nvrtc-cu12==12.6.77 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:35b0cc6ee3a9636d5409133e79273ce1f3fd087abb0532d2d2e8fff1fe9efc53 - # via torch -nvidia-cuda-runtime-cu12==12.6.77 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:a84d15d5e1da416dd4774cb42edf5e954a3e60cc945698dc1d5be02321c44dc8 \ - --hash=sha256:ba3b56a4f896141e25e19ab287cd71e52a6a0f4b29d0d31609f60e3b4d5219b7 - # via torch -nvidia-cudnn-cu12==9.5.1.17 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:30ac3869f6db17d170e0e556dd6cc5eee02647abc31ca856634d5a40f82c15b2 - # via torch -nvidia-cufft-cu12==11.3.0.4 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:768160ac89f6f7b459bee747e8d175dbf53619cfe74b2a5636264163138013ca \ - --hash=sha256:ccba62eb9cef5559abd5e0d54ceed2d9934030f51163df018532142a8ec533e5 - # via torch -nvidia-cufile-cu12==1.11.1.6 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:cc23469d1c7e52ce6c1d55253273d32c565dd22068647f3aa59b3c6b005bf159 - # via torch -nvidia-curand-cu12==10.3.7.77 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:99f1a32f1ac2bd134897fc7a203f779303261268a65762a623bf30cc9fe79117 \ - --hash=sha256:a42cd1344297f70b9e39a1e4f467a4e1c10f1da54ff7a85c12197f6c652c8bdf - # via torch -nvidia-cusolver-cu12==11.7.1.2 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:6cf28f17f64107a0c4d7802be5ff5537b2130bfc112f25d5a30df227058ca0e6 \ - --hash=sha256:e9e49843a7707e42022babb9bcfa33c29857a93b88020c4e4434656a655b698c - # via torch -nvidia-cusparse-cu12==12.5.4.2 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:23749a6571191a215cb74d1cdbff4a86e7b19f1200c071b3fcf844a5bea23a2f \ - --hash=sha256:7556d9eca156e18184b94947ade0fba5bb47d69cec46bf8660fd2c71a4b48b73 - # via - # nvidia-cusolver-cu12 - # torch -nvidia-cusparselt-cu12==0.6.3 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:e5c8a26c36445dd2e6812f1177978a24e2d37cacce7e090f297a688d1ec44f46 - # via torch -nvidia-nccl-cu12==2.26.2 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:694cf3879a206553cc9d7dbda76b13efaf610fdb70a50cba303de1b0d1530ac6 - # via torch -nvidia-nvjitlink-cu12==12.6.85 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:eedc36df9e88b682efe4309aa16b5b4e78c2407eac59e8c10a6a47535164369a - # via - # nvidia-cufft-cu12 - # nvidia-cusolver-cu12 - # nvidia-cusparse-cu12 - # torch -nvidia-nvtx-cu12==12.6.77 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:6574241a3ec5fdc9334353ab8c479fe75841dbe8f4532a8fc97ce63503330ba1 \ - --hash=sha256:b90bed3df379fa79afbd21be8e04a0314336b8ae16768b58f2d34cb1d04cd7d2 - # via torch -onnx==1.18.0 \ - --hash=sha256:030d9f5f878c5f4c0ff70a4545b90d7812cd6bfe511de2f3e469d3669c8cff95 \ - --hash=sha256:102c04edc76b16e9dfeda5a64c1fccd7d3d2913b1544750c01d38f1ac3c04e05 \ - --hash=sha256:230b0fb615e5b798dc4a3718999ec1828360bc71274abd14f915135eab0255f1 \ - --hash=sha256:2f4d37b0b5c96a873887652d1cbf3f3c70821b8c66302d84b0f0d89dd6e47653 \ - --hash=sha256:3c137eecf6bc618c2f9398bcc381474b55c817237992b169dfe728e169549e8f \ - --hash=sha256:3d8dbf9e996629131ba3aa1afd1d8239b660d1f830c6688dd7e03157cccd6b9c \ - --hash=sha256:4a3b50d94620e2c7c1404d1d59bc53e665883ae3fecbd856cc86da0639fd0fc3 \ - --hash=sha256:4c8c4bbda760c654e65eaffddb1a7de71ec02e60092d33f9000521f897c99be9 \ - --hash=sha256:521bac578448667cbb37c50bf05b53c301243ede8233029555239930996a625b \ - --hash=sha256:6acafb3823238bbe8f4340c7ac32fb218689442e074d797bee1c5c9a02fdae75 \ - --hash=sha256:6c093ffc593e07f7e33862824eab9225f86aa189c048dd43ffde207d7041a55f \ - --hash=sha256:6f91930c1a284135db0f891695a263fc876466bf2afbd2215834ac08f600cfca \ - --hash=sha256:73160799472e1a86083f786fecdf864cf43d55325492a9b5a1cfa64d8a523ecc \ - --hash=sha256:735e06d8d0cf250dc498f54038831401063c655a8d6e5975b2527a4e7d24be3e \ - --hash=sha256:8521544987d713941ee1e591520044d35e702f73dc87e91e6d4b15a064ae813d \ - --hash=sha256:911b37d724a5d97396f3c2ef9ea25361c55cbc9aa18d75b12a52b620b67145af \ - --hash=sha256:9235b3493951e11e75465d56f4cd97e3e9247f096160dd3466bfabe4cbc938bc \ - --hash=sha256:99afac90b4cdb1471432203c3c1f74e16549c526df27056d39f41a9a47cfb4af \ - --hash=sha256:a5810194f0f6be2e58c8d6dedc6119510df7a14280dd07ed5f0f0a85bd74816a \ - --hash=sha256:a69afd0baa372162948b52c13f3aa2730123381edf926d7ef3f68ca7cec6d0d0 \ - --hash=sha256:aa1b7483fac6cdec26922174fc4433f8f5c2f239b1133c5625063bb3b35957d0 \ - --hash=sha256:bfb1f271b1523b29f324bfd223f6a4cfbdc5a2f2f16e73563671932d33663365 \ - --hash=sha256:e03071041efd82e0317b3c45433b2f28146385b80f26f82039bc68048ac1a7a0 \ - --hash=sha256:e189652dad6e70a0465035c55cc565c27aa38803dd4f4e74e4b952ee1c2de94b \ - --hash=sha256:e4da451bf1c5ae381f32d430004a89f0405bc57a8471b0bddb6325a5b334aa40 \ - --hash=sha256:ee159b41a3ae58d9c7341cf432fc74b96aaf50bd7bb1160029f657b40dc69715 - # via dsperse -onnxruntime==1.21.0 \ - --hash=sha256:19b630c6a8956ef97fb7c94948b17691167aa1aaf07b5f214fa66c3e4136c108 \ - --hash=sha256:1d970dff1e2fa4d9c53f2787b3b7d0005596866e6a31997b41169017d1362dd0 \ - --hash=sha256:36b18b8f39c0f84e783902112a0dd3c102466897f96d73bb83f6a6bff283a423 \ - --hash=sha256:37b7445c920a96271a8dfa16855e258dc5599235b41c7bbde0d262d55bcc105f \ - --hash=sha256:3995c4a2d81719623c58697b9510f8de9fa42a1da6b4474052797b0d712324fe \ - --hash=sha256:635d4ab13ae0f150dd4c6ff8206fd58f1c6600636ecc796f6f0c42e4c918585b \ - --hash=sha256:7d06bfa0dd5512bd164f25a2bf594b2e7c9eabda6fc064b684924f3e81bdab1b \ - --hash=sha256:7f801318476cd7003d636a5b392f7a37c08b6c8d2f829773f3c3887029e03f32 \ - --hash=sha256:7f9156cf6f8ee133d07a751e6518cf6f84ed37fbf8243156bd4a2c4ee6e073c8 \ - --hash=sha256:85718cbde1c2912d3a03e3b3dc181b1480258a229c32378408cace7c450f7f23 \ - --hash=sha256:893d67c68ca9e7a58202fa8d96061ed86a5815b0925b5a97aef27b8ba246a20b \ - --hash=sha256:8a5d09815a9e209fa0cb20c2985b34ab4daeba7aea94d0f96b8751eb10403201 \ - --hash=sha256:8e16f8a79df03919810852fb46ffcc916dc87a9e9c6540a58f20c914c575678c \ - --hash=sha256:94dff3a61538f3b7b0ea9a06bc99e1410e90509c76e3a746f039e417802a12ae \ - --hash=sha256:95513c9302bc8dd013d84148dcf3168e782a80cdbf1654eddc948a23147ccd3d \ - --hash=sha256:9a04aafb802c1e5573ba4552f8babcb5021b041eb4cfa802c9b7644ca3510eca \ - --hash=sha256:b0fc22d219791e0284ee1d9c26724b8ee3fbdea28128ef25d9507ad3b9621f23 \ - --hash=sha256:c1e704b0eda5f2bbbe84182437315eaec89a450b08854b5a7762c85d04a28a0a - # via dsperse -packaging==25.0 \ - --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ - --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f - # via - # matplotlib - # onnxruntime - # pytest -pillow==12.0.0 \ - --hash=sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643 \ - --hash=sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e \ - --hash=sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e \ - --hash=sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc \ - --hash=sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642 \ - --hash=sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6 \ - --hash=sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1 \ - --hash=sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b \ - --hash=sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399 \ - --hash=sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba \ - --hash=sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad \ - --hash=sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47 \ - --hash=sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739 \ - --hash=sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b \ - --hash=sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f \ - --hash=sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10 \ - --hash=sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52 \ - --hash=sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d \ - --hash=sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b \ - --hash=sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a \ - --hash=sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9 \ - --hash=sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d \ - --hash=sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098 \ - --hash=sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905 \ - --hash=sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b \ - --hash=sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3 \ - --hash=sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371 \ - --hash=sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953 \ - --hash=sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01 \ - --hash=sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca \ - --hash=sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e \ - --hash=sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7 \ - --hash=sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27 \ - --hash=sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082 \ - --hash=sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e \ - --hash=sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d \ - --hash=sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8 \ - --hash=sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a \ - --hash=sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad \ - --hash=sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3 \ - --hash=sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a \ - --hash=sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d \ - --hash=sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353 \ - --hash=sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee \ - --hash=sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b \ - --hash=sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b \ - --hash=sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a \ - --hash=sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7 \ - --hash=sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef \ - --hash=sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a \ - --hash=sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a \ - --hash=sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257 \ - --hash=sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07 \ - --hash=sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4 \ - --hash=sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c \ - --hash=sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c \ - --hash=sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4 \ - --hash=sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe \ - --hash=sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8 \ - --hash=sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5 \ - --hash=sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6 \ - --hash=sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e \ - --hash=sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8 \ - --hash=sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e \ - --hash=sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275 \ - --hash=sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3 \ - --hash=sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76 \ - --hash=sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227 \ - --hash=sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9 \ - --hash=sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5 \ - --hash=sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79 \ - --hash=sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca \ - --hash=sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa \ - --hash=sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b \ - --hash=sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e \ - --hash=sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197 \ - --hash=sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab \ - --hash=sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79 \ - --hash=sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2 \ - --hash=sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363 \ - --hash=sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0 \ - --hash=sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e \ - --hash=sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782 \ - --hash=sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925 \ - --hash=sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0 \ - --hash=sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b \ - --hash=sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced \ - --hash=sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c \ - --hash=sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344 \ - --hash=sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9 \ - --hash=sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1 - # via matplotlib -pluggy==1.6.0 \ - --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \ - --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 - # via pytest -protobuf==6.33.1 \ - --hash=sha256:0f4cf01222c0d959c2b399142deb526de420be8236f22c71356e2a544e153c53 \ - --hash=sha256:8fd7d5e0eb08cd5b87fd3df49bc193f5cfd778701f47e11d127d0afc6c39f1d1 \ - --hash=sha256:923aa6d27a92bf44394f6abf7ea0500f38769d4b07f4be41cb52bd8b1123b9ed \ - --hash=sha256:97f65757e8d09870de6fd973aeddb92f85435607235d20b2dfed93405d00c85b \ - --hash=sha256:d595a9fd694fdeb061a62fbe10eb039cc1e444df81ec9bb70c7fc59ebcb1eafa \ - --hash=sha256:f8adba2e44cde2d7618996b3fc02341f03f5bc3f2748be72dc7b063319276178 \ - --hash=sha256:f8d3fdbc966aaab1d05046d0240dd94d40f2a8c62856d41eaa141ff64a79de6b \ - --hash=sha256:fe34575f2bdde76ac429ec7b570235bf0c788883e70aee90068e9981806f2490 - # via - # onnx - # onnxruntime -pygments==2.19.2 \ - --hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \ - --hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b - # via pytest -pyparsing==3.2.5 \ - --hash=sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6 \ - --hash=sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e - # via matplotlib -pyreadline3==3.5.4 ; sys_platform == 'win32' \ - --hash=sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7 \ - --hash=sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6 - # via humanfriendly -pytest==9.0.1 \ - --hash=sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8 \ - --hash=sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad - # via dsperse -python-dateutil==2.9.0.post0 \ - --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ - --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 - # via matplotlib -setuptools==80.9.0 ; (python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform != 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux') \ - --hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \ - --hash=sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c - # via - # torch - # triton -six==1.17.0 \ - --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ - --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 - # via python-dateutil -sympy==1.14.0 \ - --hash=sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517 \ - --hash=sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5 - # via - # onnxruntime - # torch -tomli==2.3.0 ; python_full_version < '3.11' \ - --hash=sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456 \ - --hash=sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845 \ - --hash=sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999 \ - --hash=sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0 \ - --hash=sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878 \ - --hash=sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf \ - --hash=sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3 \ - --hash=sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be \ - --hash=sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52 \ - --hash=sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b \ - --hash=sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67 \ - --hash=sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549 \ - --hash=sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba \ - --hash=sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22 \ - --hash=sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c \ - --hash=sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f \ - --hash=sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6 \ - --hash=sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba \ - --hash=sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45 \ - --hash=sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f \ - --hash=sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77 \ - --hash=sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606 \ - --hash=sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441 \ - --hash=sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0 \ - --hash=sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f \ - --hash=sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530 \ - --hash=sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05 \ - --hash=sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8 \ - --hash=sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005 \ - --hash=sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879 \ - --hash=sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae \ - --hash=sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc \ - --hash=sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b \ - --hash=sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b \ - --hash=sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e \ - --hash=sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf \ - --hash=sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac \ - --hash=sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8 \ - --hash=sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b \ - --hash=sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf \ - --hash=sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463 \ - --hash=sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876 - # via pytest -torch==2.7.1 \ - --hash=sha256:03563603d931e70722dce0e11999d53aa80a375a3d78e6b39b9f6805ea0a8d28 \ - --hash=sha256:06eea61f859436622e78dd0cdd51dbc8f8c6d76917a9cf0555a333f9eac31ec1 \ - --hash=sha256:0da4f4dba9f65d0d203794e619fe7ca3247a55ffdcbd17ae8fb83c8b2dc9b585 \ - --hash=sha256:23660443e13995ee93e3d844786701ea4ca69f337027b05182f5ba053ce43b38 \ - --hash=sha256:236f501f2e383f1cb861337bdf057712182f910f10aeaf509065d54d339e49b2 \ - --hash=sha256:27ea1e518df4c9de73af7e8a720770f3628e7f667280bce2be7a16292697e3fa \ - --hash=sha256:30207f672328a42df4f2174b8f426f354b2baa0b7cca3a0adb3d6ab5daf00dc8 \ - --hash=sha256:787687087412c4bd68d315e39bc1223f08aae1d16a9e9771d95eabbb04ae98fb \ - --hash=sha256:79042feca1c634aaf6603fe6feea8c6b30dfa140a6bbc0b973e2260c7e79a22e \ - --hash=sha256:8273145a2e0a3c6f9fd2ac36762d6ee89c26d430e612b95a99885df083b04e52 \ - --hash=sha256:885453d6fba67d9991132143bf7fa06b79b24352f4506fd4d10b309f53454162 \ - --hash=sha256:988b0cbc4333618a1056d2ebad9eb10089637b659eb645434d0809d8d937b946 \ - --hash=sha256:a103b5d782af5bd119b81dbcc7ffc6fa09904c423ff8db397a1e6ea8fd71508f \ - --hash=sha256:aea4fc1bf433d12843eb2c6b2204861f43d8364597697074c8d38ae2507f8730 \ - --hash=sha256:c33360cfc2edd976c2633b3b66c769bdcbbf0e0b6550606d188431c81e7dd1fc \ - --hash=sha256:d632f5417b6980f61404a125b999ca6ebd0b8b4bbdbb5fbbba44374ab619a412 \ - --hash=sha256:d72acfdb86cee2a32c0ce0101606f3758f0d8bb5f8f31e7920dc2809e963aa7c \ - --hash=sha256:d8bf6e1856ddd1807e79dc57e54d3335f2b62e6f316ed13ed3ecfe1fc1df3d8b \ - --hash=sha256:e08d7e6f21a617fe38eeb46dd2213ded43f27c072e9165dc27300c9ef9570934 \ - --hash=sha256:fe955951bdf32d182ee8ead6c3186ad54781492bf03d547d31771a01b3d6fb7d - # via dsperse -tqdm==4.67.1 \ - --hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2 \ - --hash=sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2 - # via dsperse -triton==3.3.1 ; platform_machine == 'x86_64' and sys_platform == 'linux' \ - --hash=sha256:9999e83aba21e1a78c1f36f21bce621b77bcaa530277a50484a7cb4a822f6e43 \ - --hash=sha256:a3198adb9d78b77818a5388bff89fa72ff36f9da0bc689db2f0a651a67ce6a42 \ - --hash=sha256:b31e3aa26f8cb3cc5bf4e187bf737cbacf17311e1112b781d4a059353dfd731b \ - --hash=sha256:b74db445b1c562844d3cfad6e9679c72e93fdfb1a90a24052b03bb5c49d1242e \ - --hash=sha256:b89d846b5a4198317fec27a5d3a609ea96b6d557ff44b56c23176546023c4240 - # via torch -typing-extensions==4.15.0 \ - --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \ - --hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548 - # via - # exceptiongroup - # onnx - # torch +torch==2.6.0 +onnx==1.18.0 +pytest==8.3.5 +ezkl==22.2.1 +networkx~=3.4.2 +matplotlib~=3.10.1 +numpy~=2.2.3 +tqdm~=4.67.1 +onnxruntime==1.21.0 +colorama~=0.4.6 + +# JSTprove backend requirements +# Note: jstprove is installed via 'uv tool install jstprove' (see install.sh) +# mpi4py requires Open MPI to be installed first: brew install open-mpi +mpi4py>=3.1.0