From c2d79a61de089a3318bef96d7ed878c86496039c Mon Sep 17 00:00:00 2001 From: jenswehner Date: Wed, 12 Aug 2026 12:18:24 +0200 Subject: [PATCH 1/4] Add AO screening benchmarks --- benchmarks/.gitignore | 1 + .../pyscf_ao_screening_performance.ipynb | 818 ++++++++++ ...scf_ao_screening_rotation_comparison.ipynb | 1395 +++++++++++++++++ .../run_pyscf_ao_screening_benchmark.py | 1130 +++++++++++++ ...n_pyscf_ao_screening_rotation_benchmark.py | 409 +++++ benchmarks/vxc_accuracy_grid_grouping.ipynb | 703 +++++++++ pixi.lock | 242 +-- pixi.toml | 6 +- skala/tests/utils.py | 8 +- 9 files changed, 4609 insertions(+), 103 deletions(-) create mode 100644 benchmarks/.gitignore create mode 100644 benchmarks/pyscf_ao_screening_performance.ipynb create mode 100644 benchmarks/pyscf_ao_screening_rotation_comparison.ipynb create mode 100644 benchmarks/run_pyscf_ao_screening_benchmark.py create mode 100644 benchmarks/run_pyscf_ao_screening_rotation_benchmark.py create mode 100644 benchmarks/vxc_accuracy_grid_grouping.ipynb diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore new file mode 100644 index 00000000..fbca2253 --- /dev/null +++ b/benchmarks/.gitignore @@ -0,0 +1 @@ +results/ diff --git a/benchmarks/pyscf_ao_screening_performance.ipynb b/benchmarks/pyscf_ao_screening_performance.ipynb new file mode 100644 index 00000000..d7114c2d --- /dev/null +++ b/benchmarks/pyscf_ao_screening_performance.ipynb @@ -0,0 +1,818 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "236c0ac1", + "metadata": {}, + "source": [ + "# Skala PySCF / GPU4PySCF Benchmark Results\n", + "\n", + "This notebook loads and compares JSON produced by `benchmarks/run_pyscf_ao_screening_benchmark.py`. It does not construct molecules, load Skala, or execute benchmark workloads.\n", + "\n", + "Generate result files from a shell before opening the analysis cells:\n", + "\n", + "```bash\n", + "python benchmarks/run_pyscf_ao_screening_benchmark.py --label mr\n", + "python benchmarks/run_pyscf_ao_screening_benchmark.py \\\n", + " --label main \\\n", + " --source-root /path/to/main-worktree\n", + "```\n", + "\n", + "Add `--smoke` to run only C4H10, or `--preflight-only` to validate the selected checkout and environment without collecting measurements." + ] + }, + { + "cell_type": "markdown", + "id": "e758ba91", + "metadata": {}, + "source": [ + "## Select Result Files\n", + "\n", + "By default, every compatible molecule-benchmark result in `benchmarks/results` is loaded. Results with other schemas, such as rotation comparisons, are reported and ignored. Replace `SELECTED_RESULT_FILES` with an explicit list when comparing only particular labels or commits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d6909409", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "from pathlib import Path\n", + "from typing import Any\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "MODES = (\"cpu\", \"cpu_dense\", \"gpu\")\n", + "MEASUREMENTS = (\"runtime\", \"memory\")\n", + "TERMINAL_STATUSES = {\"ok\", \"timeout\", \"oom\", \"error\", \"skipped_after_resource_failure\"}\n", + "SCIENTIFIC_CONFIG_KEYS = (\n", + " \"functional\",\n", + " \"basis\",\n", + " \"grid_level\",\n", + " \"grid_alignment\",\n", + " \"max_memory_mb\",\n", + " \"cpu_threads\",\n", + " \"full_carbon_counts\",\n", + " \"expected_ao_counts\",\n", + ")\n", + "\n", + "\n", + "def find_repository_root(start: Path) -> Path:\n", + " for candidate in (start.resolve(), *start.resolve().parents):\n", + " if (candidate / \"pyproject.toml\").is_file() and (\n", + " candidate / \"benchmarks\"\n", + " ).is_dir():\n", + " return candidate\n", + " raise FileNotFoundError(f\"Could not find the Skala repository above {start}\")\n", + "\n", + "\n", + "def is_molecule_benchmark_result(path: Path) -> bool:\n", + " document = json.loads(path.read_text(encoding=\"utf-8\"))\n", + " return isinstance(document.get(\"molecules\"), dict)\n", + "\n", + "\n", + "REPOSITORY_ROOT = find_repository_root(Path.cwd())\n", + "RESULTS_DIR = REPOSITORY_ROOT / \"benchmarks\" / \"results\"\n", + "CANDIDATE_RESULT_FILES = sorted(RESULTS_DIR.glob(\"skala-pyscf-ao-screening-*.json\"))\n", + "SELECTED_RESULT_FILES = [\n", + " path for path in CANDIDATE_RESULT_FILES if is_molecule_benchmark_result(path)\n", + "]\n", + "IGNORED_RESULT_FILES = [\n", + " path for path in CANDIDATE_RESULT_FILES if path not in SELECTED_RESULT_FILES\n", + "]\n", + "\n", + "print(f\"Selected {len(SELECTED_RESULT_FILES)} result file(s) from {RESULTS_DIR}\")\n", + "for result_file in SELECTED_RESULT_FILES:\n", + " print(f\" {result_file.name}\")\n", + "if IGNORED_RESULT_FILES:\n", + " print(\"Ignored incompatible result file(s):\")\n", + " for result_file in IGNORED_RESULT_FILES:\n", + " print(f\" {result_file.name}\")" + ] + }, + { + "cell_type": "markdown", + "id": "8284d45b", + "metadata": {}, + "source": [ + "## Load and Validate\n", + "\n", + "The checks below surface incompatible schemas, scientific settings, hardware, routing implementations, dirty checkouts, unexpected statuses, AO counts, and production-versus-CPU-dense fingerprint differences." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4de7a3a", + "metadata": {}, + "outputs": [], + "source": [ + "def validate_result_document(document: dict[str, Any]) -> list[str]:\n", + " errors: list[str] = []\n", + " if document.get(\"schema_version\") != 1:\n", + " errors.append(f\"Unsupported schema version: {document.get('schema_version')}\")\n", + " for formula, molecule in document.get(\"molecules\", {}).items():\n", + " observed = molecule.get(\"observed\")\n", + " if observed is not None:\n", + " if observed.get(\"actual_aos\") != molecule.get(\"expected_aos\"):\n", + " errors.append(\n", + " f\"{formula}: expected {molecule.get('expected_aos')} AOs, \"\n", + " f\"observed {observed.get('actual_aos')}\"\n", + " )\n", + " carbon_count = int(molecule[\"carbon_count\"])\n", + " expected_electrons = 8 * carbon_count + 2\n", + " if observed.get(\"electron_count\") != expected_electrons:\n", + " errors.append(\n", + " f\"{formula}: expected {expected_electrons} electrons, \"\n", + " f\"observed {observed.get('electron_count')}\"\n", + " )\n", + " for mode, mode_record in molecule.get(\"modes\", {}).items():\n", + " for measurement in MEASUREMENTS:\n", + " result = mode_record.get(measurement)\n", + " if result is not None and result.get(\"status\") not in TERMINAL_STATUSES:\n", + " errors.append(\n", + " f\"{formula} {mode} {measurement}: unknown status {result.get('status')}\"\n", + " )\n", + " return errors\n", + "\n", + "\n", + "def preferred_fingerprint(mode_record: dict[str, Any]) -> dict[str, float] | None:\n", + " for measurement in MEASUREMENTS:\n", + " result = mode_record.get(measurement, {})\n", + " if result.get(\"status\") == \"ok\" and \"fingerprint\" in result:\n", + " return result[\"fingerprint\"]\n", + " return None\n", + "\n", + "\n", + "def fingerprint_warnings(document: dict[str, Any]) -> list[str]:\n", + " messages: list[str] = []\n", + " for formula, molecule in document[\"molecules\"].items():\n", + " reference = preferred_fingerprint(molecule[\"modes\"][\"cpu_dense\"])\n", + " if reference is None:\n", + " continue\n", + " for production_mode, rtol, atol in (\n", + " (\"cpu\", 1e-8, 5e-8),\n", + " (\"gpu\", 1e-7, 2e-7),\n", + " ):\n", + " production = preferred_fingerprint(molecule[\"modes\"][production_mode])\n", + " if production is None:\n", + " continue\n", + " for key in production:\n", + " if not np.isclose(\n", + " production[key], reference[key], rtol=rtol, atol=atol\n", + " ):\n", + " messages.append(\n", + " f\"{formula} {production_mode}/cpu_dense: {key} differs \"\n", + " f\"({production[key]:.12g} vs {reference[key]:.12g})\"\n", + " )\n", + " return messages\n", + "\n", + "\n", + "def comparison_warnings(documents: list[dict[str, Any]]) -> list[str]:\n", + " messages: list[str] = []\n", + " if not documents:\n", + " return [\"No result documents were selected\"]\n", + " reference = documents[0]\n", + " reference_config = reference[\"configuration\"]\n", + " reference_environment = reference[\"environment\"]\n", + " for document in documents:\n", + " label = document[\"run_label\"]\n", + " if document[\"source\"].get(\"dirty\"):\n", + " messages.append(f\"{label}: source checkout is dirty\")\n", + " messages.extend(\n", + " f\"{label}: {error}\" for error in validate_result_document(document)\n", + " )\n", + " messages.extend(\n", + " f\"{label}: {warning}\" for warning in fingerprint_warnings(document)\n", + " )\n", + " for document in documents[1:]:\n", + " label = document[\"run_label\"]\n", + " for key in SCIENTIFIC_CONFIG_KEYS:\n", + " if document[\"configuration\"].get(key) != reference_config.get(key):\n", + " messages.append(f\"{label}: configuration differs for {key}\")\n", + " for key_path in ((\"hostname\",), (\"platform\",), (\"cuda\", \"device_name\")):\n", + " left: Any = reference_environment\n", + " right: Any = document[\"environment\"]\n", + " for key in key_path:\n", + " left = left.get(key) if isinstance(left, dict) else None\n", + " right = right.get(key) if isinstance(right, dict) else None\n", + " if left != right:\n", + " messages.append(\n", + " f\"{label}: environment differs for {'.'.join(key_path)}\"\n", + " )\n", + "\n", + " route_implementations: dict[str, set[str]] = {mode: set() for mode in MODES}\n", + " for document in documents:\n", + " for molecule in document[\"molecules\"].values():\n", + " for mode in MODES:\n", + " implementation = (\n", + " molecule[\"modes\"][mode].get(\"route\", {}).get(\"implementation\")\n", + " )\n", + " if implementation:\n", + " route_implementations[mode].add(implementation)\n", + " for mode, implementations in route_implementations.items():\n", + " if len(implementations) > 1:\n", + " messages.append(\n", + " f\"{mode}: routing implementations differ: {sorted(implementations)}\"\n", + " )\n", + " return messages\n", + "\n", + "\n", + "def load_result_documents(paths: list[Path]) -> list[dict[str, Any]]:\n", + " documents = [json.loads(path.read_text(encoding=\"utf-8\")) for path in paths]\n", + " messages = comparison_warnings(documents)\n", + " if messages:\n", + " print(\"Comparison warnings:\")\n", + " for message in messages:\n", + " print(f\" WARNING: {message}\")\n", + " return documents\n", + "\n", + "\n", + "def print_status_table(documents: list[dict[str, Any]]) -> None:\n", + " header = f\"{'label':10s} {'formula':9s} {'AOs':>5s} {'mode':10s} {'runtime':12s} {'memory':12s}\"\n", + " print(header)\n", + " print(\"-\" * len(header))\n", + " for document in documents:\n", + " for molecule in document[\"molecules\"].values():\n", + " observed = molecule.get(\"observed\") or {}\n", + " aos = observed.get(\"actual_aos\", molecule[\"expected_aos\"])\n", + " for mode in MODES:\n", + " mode_record = molecule[\"modes\"][mode]\n", + " runtime_status = mode_record.get(\"runtime\", {}).get(\"status\", \"pending\")\n", + " memory_status = mode_record.get(\"memory\", {}).get(\"status\", \"pending\")\n", + " print(\n", + " f\"{document['run_label'][:10]:10s} {molecule['formula']:9s} {aos:5d} \"\n", + " f\"{mode:10s} {runtime_status:12s} {memory_status:12s}\"\n", + " )\n", + "\n", + "\n", + "SELECTED_DOCUMENTS = (\n", + " load_result_documents(SELECTED_RESULT_FILES) if SELECTED_RESULT_FILES else []\n", + ")\n", + "if SELECTED_DOCUMENTS:\n", + " print_status_table(SELECTED_DOCUMENTS)\n", + "else:\n", + " print(\"No benchmark result files were found. Run the benchmark script first.\")" + ] + }, + { + "cell_type": "markdown", + "id": "57fda27a", + "metadata": {}, + "source": [ + "## Visualize\n", + "\n", + "Each metric is rendered in its own notebook output with a single y-axis. Runtime curves show the median of the recorded samples with error bars spanning the observed minimum and maximum; one-sample legacy results therefore have zero-width bounds. Successful observations are plotted against actual spherical AO counts. Failed or timed-out points stay absent from curves and remain visible in the status table." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "caf55d9d", + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib.axes import Axes\n", + "\n", + "MODE_COLORS = {\n", + " \"cpu\": \"#006D77\",\n", + " \"cpu_dense\": \"#83C5BE\",\n", + " \"gpu\": \"#C44536\",\n", + "}\n", + "REVISION_LINESTYLES = (\"-\", \"--\", \":\", \"-.\")\n", + "RESULT_MARKERS = (\"o\", \"s\", \"^\", \"D\", \"v\", \"P\", \"X\")\n", + "MARKER_SIZE = 5\n", + "LEGEND_MARKER_SCALE = 1.8\n", + "LEGEND_HANDLE_LENGTH = 3.0\n", + "\n", + "\n", + "def measurement_samples(mode_record: dict[str, Any], measurement: str) -> list[float]:\n", + " result = mode_record.get(measurement, {})\n", + " if result.get(\"status\") != \"ok\":\n", + " return []\n", + " if measurement == \"runtime\":\n", + " return [float(value) for value in result.get(\"runtime_samples_seconds\", [])]\n", + " peak_bytes = result.get(\"incremental_peak_bytes\")\n", + " return [float(peak_bytes) / 1024**3] if peak_bytes is not None else []\n", + "\n", + "\n", + "def sample_summary(samples: list[float]) -> tuple[float, float, float] | None:\n", + " if not samples:\n", + " return None\n", + " values = np.asarray(samples, dtype=float)\n", + " center = float(np.median(values))\n", + " return center, center - float(values.min()), float(values.max()) - center\n", + "\n", + "\n", + "def measurement_value(mode_record: dict[str, Any], measurement: str) -> float | None:\n", + " summary = sample_summary(measurement_samples(mode_record, measurement))\n", + " return summary[0] if summary is not None else None\n", + "\n", + "\n", + "def measurement_series(\n", + " document: dict[str, Any], mode: str, measurement: str\n", + ") -> tuple[list[int], list[float], list[float], list[float]]:\n", + " points: list[tuple[int, float, float, float]] = []\n", + " for molecule in document[\"molecules\"].values():\n", + " observed = molecule.get(\"observed\") or {}\n", + " aos = int(observed.get(\"actual_aos\", molecule[\"expected_aos\"]))\n", + " summary = sample_summary(\n", + " measurement_samples(molecule[\"modes\"][mode], measurement)\n", + " )\n", + " if summary is not None and summary[0] > 0.0:\n", + " points.append((aos, *summary))\n", + " points.sort()\n", + " return (\n", + " [point[0] for point in points],\n", + " [point[1] for point in points],\n", + " [point[2] for point in points],\n", + " [point[3] for point in points],\n", + " )\n", + "\n", + "\n", + "def cpu_reference_ratio_series(\n", + " document: dict[str, Any], measurement: str\n", + ") -> tuple[list[int], list[float], list[float], list[float]]:\n", + " points: list[tuple[int, float, float, float]] = []\n", + " for molecule in document[\"molecules\"].values():\n", + " observed = molecule.get(\"observed\") or {}\n", + " aos = int(observed.get(\"actual_aos\", molecule[\"expected_aos\"]))\n", + " production_samples = measurement_samples(molecule[\"modes\"][\"cpu\"], measurement)\n", + " dense_samples = measurement_samples(molecule[\"modes\"][\"cpu_dense\"], measurement)\n", + " production_summary = sample_summary(production_samples)\n", + " dense_summary = sample_summary(dense_samples)\n", + " if (\n", + " production_summary is None\n", + " or dense_summary is None\n", + " or min(production_samples) <= 0.0\n", + " ):\n", + " continue\n", + " center = dense_summary[0] / production_summary[0]\n", + " lower_bound = min(dense_samples) / max(production_samples)\n", + " upper_bound = max(dense_samples) / min(production_samples)\n", + " points.append((aos, center, center - lower_bound, upper_bound - center))\n", + " points.sort()\n", + " return (\n", + " [point[0] for point in points],\n", + " [point[1] for point in points],\n", + " [point[2] for point in points],\n", + " [point[3] for point in points],\n", + " )\n", + "\n", + "\n", + "def endpoint_label(label: str, x_values: list[int]) -> str:\n", + " return (\n", + " f\"{label} (last: {x_values[-1]} AOs)\"\n", + " if x_values\n", + " else f\"{label} (no successful points)\"\n", + " )\n", + "\n", + "\n", + "def style_benchmark_axis(\n", + " axis: Axes, *, title: str, ylabel: str, logarithmic: bool = False\n", + ") -> None:\n", + " axis.set(title=title, xlabel=\"Spherical AO count\", ylabel=ylabel)\n", + " if logarithmic:\n", + " axis.set_yscale(\"log\")\n", + " axis.grid(True, which=\"both\", color=\"#D9D9D9\", linewidth=0.6)\n", + " axis.legend(\n", + " fontsize=8,\n", + " loc=\"upper left\",\n", + " bbox_to_anchor=(1.02, 1.0),\n", + " borderaxespad=0.0,\n", + " markerscale=LEGEND_MARKER_SCALE,\n", + " handlelength=LEGEND_HANDLE_LENGTH,\n", + " )\n", + "\n", + "\n", + "def plot_measurement(documents: list[dict[str, Any]], measurement: str) -> None:\n", + " if not documents:\n", + " print(f\"No result files selected; the {measurement} plot was not created.\")\n", + " return\n", + " _, axis = plt.subplots(figsize=(11, 6), constrained_layout=True)\n", + " for document_index, document in enumerate(documents):\n", + " label = document[\"run_label\"]\n", + " line_style = REVISION_LINESTYLES[document_index % len(REVISION_LINESTYLES)]\n", + " marker = RESULT_MARKERS[document_index % len(RESULT_MARKERS)]\n", + " for mode in MODES:\n", + " x_values, y_values, lower_errors, upper_errors = measurement_series(\n", + " document, mode, measurement\n", + " )\n", + " curve_label = f\"{label} {mode}\"\n", + " plot_arguments = {\n", + " \"color\": MODE_COLORS[mode],\n", + " \"linestyle\": line_style,\n", + " \"marker\": marker,\n", + " \"markersize\": MARKER_SIZE,\n", + " \"label\": endpoint_label(curve_label, x_values),\n", + " }\n", + " if measurement == \"runtime\":\n", + " axis.errorbar(\n", + " x_values,\n", + " y_values,\n", + " yerr=np.asarray([lower_errors, upper_errors]),\n", + " capsize=3,\n", + " **plot_arguments,\n", + " )\n", + " else:\n", + " axis.plot(x_values, y_values, **plot_arguments)\n", + " if measurement == \"runtime\":\n", + " title = \"One XC/Vxc evaluation (median and min-max)\"\n", + " ylabel = \"Runtime (s)\"\n", + " elif measurement == \"memory\":\n", + " title = \"Incremental allocation peak\"\n", + " ylabel = \"Memory (GiB)\"\n", + " else:\n", + " raise ValueError(f\"Unknown measurement: {measurement}\")\n", + " style_benchmark_axis(axis, title=title, ylabel=ylabel, logarithmic=True)\n", + " plt.show()\n", + "\n", + "\n", + "def plot_cpu_reference_ratio(documents: list[dict[str, Any]], measurement: str) -> None:\n", + " if not documents:\n", + " print(\n", + " f\"No result files selected; the {measurement} ratio plot was not created.\"\n", + " )\n", + " return\n", + " _, axis = plt.subplots(figsize=(11, 6), constrained_layout=True)\n", + " for document_index, document in enumerate(documents):\n", + " x_values, y_values, lower_errors, upper_errors = cpu_reference_ratio_series(\n", + " document, measurement\n", + " )\n", + " line_style = REVISION_LINESTYLES[document_index % len(REVISION_LINESTYLES)]\n", + " marker = RESULT_MARKERS[document_index % len(RESULT_MARKERS)]\n", + " plot_arguments = {\n", + " \"color\": MODE_COLORS[\"cpu\"],\n", + " \"linestyle\": line_style,\n", + " \"marker\": marker,\n", + " \"markersize\": MARKER_SIZE,\n", + " \"label\": f\"{document['run_label']} cpu\",\n", + " }\n", + " if measurement == \"runtime\":\n", + " axis.errorbar(\n", + " x_values,\n", + " y_values,\n", + " yerr=np.asarray([lower_errors, upper_errors]),\n", + " capsize=3,\n", + " **plot_arguments,\n", + " )\n", + " else:\n", + " axis.plot(x_values, y_values, **plot_arguments)\n", + " if measurement == \"runtime\":\n", + " title = \"CPU production speedup (median and min-max)\"\n", + " ylabel = \"CPU dense runtime / production runtime\"\n", + " elif measurement == \"memory\":\n", + " title = \"CPU production memory reduction\"\n", + " ylabel = \"CPU dense peak / production peak\"\n", + " else:\n", + " raise ValueError(f\"Unknown measurement: {measurement}\")\n", + " style_benchmark_axis(axis, title=title, ylabel=ylabel)\n", + " axis.axhline(1.0, color=\"#777777\", linewidth=0.8, linestyle=\":\")\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "165b8f50", + "metadata": {}, + "outputs": [], + "source": [ + "plot_measurement(SELECTED_DOCUMENTS, \"runtime\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b923074a", + "metadata": {}, + "outputs": [], + "source": [ + "plot_measurement(SELECTED_DOCUMENTS, \"memory\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce3a086b", + "metadata": {}, + "outputs": [], + "source": [ + "plot_cpu_reference_ratio(SELECTED_DOCUMENTS, \"runtime\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fded2dd7", + "metadata": {}, + "outputs": [], + "source": [ + "plot_cpu_reference_ratio(SELECTED_DOCUMENTS, \"memory\")" + ] + }, + { + "cell_type": "markdown", + "id": "58750d35", + "metadata": {}, + "source": [ + "## Numerical Differences\n", + "\n", + "Production CPU and GPU fingerprints are compared molecule-by-molecule with the CPU-dense reference. The summary reports maximum absolute and relative errors and counts values outside the existing acceptance tolerances. Each per-fingerprint plot shows the signed difference `production - cpu_dense`; the dotted zero line is the CPU-dense reference.\n", + "\n", + "The final six-panel figure compares CPU-dense references across result files. The first selected result is the baseline, and each curve shows `comparison cpu_dense - baseline cpu_dense`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4de2998", + "metadata": {}, + "outputs": [], + "source": [ + "FINGERPRINT_LABELS = {\n", + " \"electron_integral\": \"Electron integral\",\n", + " \"xc_energy\": \"XC energy\",\n", + " \"vxc_sum\": \"Vxc sum\",\n", + " \"vxc_trace\": \"Vxc trace\",\n", + " \"vxc_frobenius_norm\": \"Vxc Frobenius norm\",\n", + " \"vxc_max_abs\": \"Vxc max abs\",\n", + "}\n", + "ERROR_TOLERANCES = {\n", + " \"cpu\": (1e-8, 5e-8),\n", + " \"gpu\": (1e-7, 2e-7),\n", + "}\n", + "\n", + "\n", + "def fingerprint_error_records(\n", + " document: dict[str, Any], production_mode: str, fingerprint_key: str\n", + ") -> list[dict[str, Any]]:\n", + " rtol, atol = ERROR_TOLERANCES[production_mode]\n", + " records: list[dict[str, Any]] = []\n", + " for formula, molecule in document[\"molecules\"].items():\n", + " reference = preferred_fingerprint(molecule[\"modes\"][\"cpu_dense\"])\n", + " production = preferred_fingerprint(molecule[\"modes\"][production_mode])\n", + " if (\n", + " reference is None\n", + " or production is None\n", + " or fingerprint_key not in reference\n", + " or fingerprint_key not in production\n", + " ):\n", + " continue\n", + " reference_value = float(reference[fingerprint_key])\n", + " production_value = float(production[fingerprint_key])\n", + " difference = production_value - reference_value\n", + " absolute_error = abs(difference)\n", + " relative_error = absolute_error / max(\n", + " abs(reference_value), np.finfo(float).tiny\n", + " )\n", + " tolerance_scale = atol + rtol * abs(reference_value)\n", + " observed = molecule.get(\"observed\") or {}\n", + " records.append(\n", + " {\n", + " \"formula\": formula,\n", + " \"aos\": int(observed.get(\"actual_aos\", molecule[\"expected_aos\"])),\n", + " \"difference\": difference,\n", + " \"absolute_error\": absolute_error,\n", + " \"relative_error\": relative_error,\n", + " \"tolerance_ratio\": absolute_error / tolerance_scale,\n", + " }\n", + " )\n", + " records.sort(key=lambda record: record[\"aos\"])\n", + " return records\n", + "\n", + "\n", + "def dense_reference_difference_records(\n", + " reference_document: dict[str, Any],\n", + " comparison_document: dict[str, Any],\n", + " fingerprint_key: str,\n", + ") -> list[dict[str, Any]]:\n", + " records: list[dict[str, Any]] = []\n", + " for formula, reference_molecule in reference_document[\"molecules\"].items():\n", + " comparison_molecule = comparison_document[\"molecules\"].get(formula)\n", + " if comparison_molecule is None:\n", + " continue\n", + " reference = preferred_fingerprint(reference_molecule[\"modes\"][\"cpu_dense\"])\n", + " comparison = preferred_fingerprint(comparison_molecule[\"modes\"][\"cpu_dense\"])\n", + " if (\n", + " reference is None\n", + " or comparison is None\n", + " or fingerprint_key not in reference\n", + " or fingerprint_key not in comparison\n", + " ):\n", + " continue\n", + " observed = comparison_molecule.get(\"observed\") or {}\n", + " records.append(\n", + " {\n", + " \"formula\": formula,\n", + " \"aos\": int(\n", + " observed.get(\"actual_aos\", comparison_molecule[\"expected_aos\"])\n", + " ),\n", + " \"difference\": float(comparison[fingerprint_key])\n", + " - float(reference[fingerprint_key]),\n", + " }\n", + " )\n", + " records.sort(key=lambda record: record[\"aos\"])\n", + " return records\n", + "\n", + "\n", + "def print_fingerprint_error_summary(documents: list[dict[str, Any]]) -> None:\n", + " header = (\n", + " f\"{'label':10s} {'mode':4s} {'fingerprint':22s} \"\n", + " f\"{'max abs':>11s} {'max rel':>11s} {'outside':>8s} {'at':>8s}\"\n", + " )\n", + " print(header)\n", + " print(\"-\" * len(header))\n", + " for document in documents:\n", + " for production_mode in ERROR_TOLERANCES:\n", + " for fingerprint_key, fingerprint_label in FINGERPRINT_LABELS.items():\n", + " records = fingerprint_error_records(\n", + " document, production_mode, fingerprint_key\n", + " )\n", + " if not records:\n", + " continue\n", + " max_absolute_error = max(record[\"absolute_error\"] for record in records)\n", + " worst_relative = max(\n", + " records, key=lambda record: record[\"relative_error\"]\n", + " )\n", + " outside_tolerance = sum(\n", + " record[\"tolerance_ratio\"] > 1.0 for record in records\n", + " )\n", + " print(\n", + " f\"{document['run_label'][:10]:10s} {production_mode:4s} \"\n", + " f\"{fingerprint_label:22s} {max_absolute_error:11.3e} \"\n", + " f\"{worst_relative['relative_error']:11.3e} \"\n", + " f\"{outside_tolerance:3d}/{len(records):<4d} \"\n", + " f\"{worst_relative['formula']:>8s}\"\n", + " )\n", + "\n", + "\n", + "def plot_fingerprint_differences(\n", + " documents: list[dict[str, Any]], fingerprint_key: str\n", + ") -> None:\n", + " if fingerprint_key not in FINGERPRINT_LABELS:\n", + " raise ValueError(f\"Unknown fingerprint: {fingerprint_key}\")\n", + " if not documents:\n", + " print(f\"No result files selected; the {fingerprint_key} plot was not created.\")\n", + " return\n", + " _, axis = plt.subplots(figsize=(11, 6), constrained_layout=True)\n", + " for document_index, document in enumerate(documents):\n", + " line_style = REVISION_LINESTYLES[document_index % len(REVISION_LINESTYLES)]\n", + " marker = RESULT_MARKERS[document_index % len(RESULT_MARKERS)]\n", + " for production_mode in ERROR_TOLERANCES:\n", + " records = fingerprint_error_records(\n", + " document, production_mode, fingerprint_key\n", + " )\n", + " x_values = [record[\"aos\"] for record in records]\n", + " curve_label = f\"{document['run_label']} {production_mode}\"\n", + " axis.plot(\n", + " x_values,\n", + " [record[\"difference\"] for record in records],\n", + " color=MODE_COLORS[production_mode],\n", + " linestyle=line_style,\n", + " marker=marker,\n", + " markersize=MARKER_SIZE,\n", + " label=endpoint_label(curve_label, x_values),\n", + " )\n", + " fingerprint_label = FINGERPRINT_LABELS[fingerprint_key]\n", + " axis.axhline(\n", + " 0.0,\n", + " color=MODE_COLORS[\"cpu_dense\"],\n", + " linewidth=1.0,\n", + " linestyle=\":\",\n", + " label=\"CPU dense reference\",\n", + " )\n", + " style_benchmark_axis(\n", + " axis,\n", + " title=f\"{fingerprint_label} difference from CPU dense\",\n", + " ylabel=f\"{fingerprint_label} - CPU dense reference\",\n", + " )\n", + " axis.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(0, 0))\n", + " plt.show()\n", + "\n", + "\n", + "def plot_dense_reference_differences(documents: list[dict[str, Any]]) -> None:\n", + " if len(documents) < 2:\n", + " print(\"At least two result files are required to compare CPU-dense references.\")\n", + " return\n", + " reference_document = documents[0]\n", + " figure, axes = plt.subplots(2, 3, figsize=(16, 9), constrained_layout=True)\n", + " for axis, (fingerprint_key, fingerprint_label) in zip(\n", + " axes.flat, FINGERPRINT_LABELS.items(), strict=True\n", + " ):\n", + " plotted_differences: list[float] = []\n", + " for document_index, document in enumerate(documents[1:], start=1):\n", + " records = dense_reference_difference_records(\n", + " reference_document, document, fingerprint_key\n", + " )\n", + " x_values = [record[\"aos\"] for record in records]\n", + " differences = [record[\"difference\"] for record in records]\n", + " plotted_differences.extend(differences)\n", + " curve_label = f\"{document['run_label']} - {reference_document['run_label']}\"\n", + " axis.plot(\n", + " x_values,\n", + " differences,\n", + " color=MODE_COLORS[\"cpu_dense\"],\n", + " linestyle=REVISION_LINESTYLES[\n", + " document_index % len(REVISION_LINESTYLES)\n", + " ],\n", + " marker=RESULT_MARKERS[document_index % len(RESULT_MARKERS)],\n", + " markersize=MARKER_SIZE,\n", + " label=endpoint_label(curve_label, x_values),\n", + " )\n", + " axis.axhline(0.0, color=\"#777777\", linewidth=0.8, linestyle=\":\")\n", + " axis.set(\n", + " title=fingerprint_label,\n", + " xlabel=\"Spherical AO count\",\n", + " ylabel=\"CPU-dense difference\",\n", + " )\n", + " if plotted_differences and all(value == 0.0 for value in plotted_differences):\n", + " axis.set_ylim(-0.5, 0.5)\n", + " axis.set_yticks([0.0])\n", + " axis.text(\n", + " 0.5,\n", + " 0.54,\n", + " \"All matched differences are exactly zero\",\n", + " color=\"#555555\",\n", + " fontsize=8,\n", + " ha=\"center\",\n", + " transform=axis.transAxes,\n", + " )\n", + " else:\n", + " axis.ticklabel_format(axis=\"y\", style=\"sci\", scilimits=(0, 0))\n", + " axis.grid(True, which=\"both\", color=\"#D9D9D9\", linewidth=0.6)\n", + " handles, labels = axes.flat[0].get_legend_handles_labels()\n", + " figure.legend(\n", + " handles,\n", + " labels,\n", + " fontsize=8,\n", + " loc=\"center left\",\n", + " bbox_to_anchor=(1.01, 0.5),\n", + " borderaxespad=0.0,\n", + " markerscale=LEGEND_MARKER_SCALE,\n", + " handlelength=LEGEND_HANDLE_LENGTH,\n", + " )\n", + " figure.suptitle(\n", + " f\"CPU-dense reference differences from {reference_document['run_label']}\"\n", + " )\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "db731370", + "metadata": {}, + "outputs": [], + "source": [ + "print_fingerprint_error_summary(SELECTED_DOCUMENTS)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "148309a1", + "metadata": {}, + "outputs": [], + "source": [ + "for fingerprint_key in FINGERPRINT_LABELS:\n", + " plot_fingerprint_differences(SELECTED_DOCUMENTS, fingerprint_key)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16648b0a", + "metadata": {}, + "outputs": [], + "source": [ + "plot_dense_reference_differences(SELECTED_DOCUMENTS)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/benchmarks/pyscf_ao_screening_rotation_comparison.ipynb b/benchmarks/pyscf_ao_screening_rotation_comparison.ipynb new file mode 100644 index 00000000..bf938326 --- /dev/null +++ b/benchmarks/pyscf_ao_screening_rotation_comparison.ipynb @@ -0,0 +1,1395 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "ac79c661", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "c081221d", + "metadata": {}, + "source": [ + "# Skala AO Screening Rotation Comparison\n", + "\n", + "This notebook loads JSON written by `benchmarks/run_pyscf_ao_screening_rotation_benchmark.py`. It does not construct molecules, load Skala, or execute benchmark workloads.\n", + "\n", + "Generate a full result file before running the analysis:\n", + "\n", + "```bash\n", + "/home/jenswehner/micromamba/envs/skala_gpu_python/bin/python \\\n", + " benchmarks/run_pyscf_ao_screening_rotation_benchmark.py \\\n", + " --label screening\n", + "```\n", + "\n", + "The default run records runtime and incremental peak memory for 72 orientations in each of `gpu`, `cpu_dense`, and `cpu_screened`. Add `--smoke` for one orientation per mode or `--preflight-only` to validate geometry and dependencies without measurements.\n", + "\n", + "## 1. Import Analysis Libraries and Configure Paths\n", + "\n", + "Select one or more rotation result files. Runtime is reported in seconds and incremental peak memory in GiB; CPU dense is the numerical and ratio reference." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3bb528e2", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import statistics\n", + "from collections import Counter\n", + "from datetime import UTC, datetime\n", + "from pathlib import Path\n", + "from typing import Any\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "\n", + "MODES = (\"gpu\", \"cpu_dense\", \"cpu_screened\")\n", + "MEASUREMENTS = (\"runtime\", \"memory\")\n", + "REFERENCE_MODE = \"cpu_dense\"\n", + "EXPECTED_AOS = 879\n", + "EXPECTED_ROUTES = {\n", + " \"gpu\": \"global_ao_screening\",\n", + " \"cpu_dense\": \"dense\",\n", + " \"cpu_screened\": \"global_ao_screening\",\n", + "}\n", + "TERMINAL_STATUSES = {\n", + " \"ok\",\n", + " \"timeout\",\n", + " \"oom\",\n", + " \"error\",\n", + " \"skipped_after_resource_failure\",\n", + "}\n", + "FINGERPRINT_LABELS = {\n", + " \"electron_integral\": \"Electron integral\",\n", + " \"xc_energy\": \"XC energy\",\n", + " \"vxc_sum\": \"Vxc sum\",\n", + " \"vxc_trace\": \"Vxc trace\",\n", + " \"vxc_frobenius_norm\": \"Vxc Frobenius norm\",\n", + " \"vxc_max_abs\": \"Vxc max abs\",\n", + "}\n", + "ERROR_TOLERANCES = {\n", + " \"cpu_screened\": (5e-8, 1e-8),\n", + " \"gpu\": (2e-7, 1e-7),\n", + "}\n", + "MODE_COLORS = {\n", + " \"gpu\": \"#C44536\",\n", + " \"cpu_dense\": \"#83C5BE\",\n", + " \"cpu_screened\": \"#006D77\",\n", + "}\n", + "\n", + "\n", + "def find_repository_root(start: Path) -> Path:\n", + " for candidate in (start.resolve(), *start.resolve().parents):\n", + " if (candidate / \"pyproject.toml\").is_file() and (\n", + " candidate / \"benchmarks\"\n", + " ).is_dir():\n", + " return candidate\n", + " raise FileNotFoundError(f\"Could not find the Skala repository above {start}\")\n", + "\n", + "\n", + "REPOSITORY_ROOT = find_repository_root(Path.cwd())\n", + "RESULTS_DIR = REPOSITORY_ROOT / \"benchmarks\" / \"results\"\n", + "ARTIFACT_DIR = RESULTS_DIR / \"rotation_comparison\"\n", + "FIGURE_DIR = ARTIFACT_DIR / \"figures\"\n", + "TABLE_DIR = ARTIFACT_DIR / \"tables\"\n", + "COMPARISON_JSON = ARTIFACT_DIR / \"comparison.json\"\n", + "\n", + "# Replace this list with explicit paths to compare a subset of result files.\n", + "SELECTED_RESULT_FILES = sorted(\n", + " RESULTS_DIR.glob(\"skala-pyscf-ao-screening-rotations-*.json\")\n", + ")\n", + "\n", + "sns.set_theme(style=\"whitegrid\", context=\"notebook\")\n", + "print(f\"Selected {len(SELECTED_RESULT_FILES)} rotation result file(s)\")\n", + "for result_file in SELECTED_RESULT_FILES:\n", + " print(f\" {result_file.name}\")" + ] + }, + { + "cell_type": "markdown", + "id": "556eb2a0", + "metadata": {}, + "source": [ + "## 2. Load and Validate Benchmark JSON Files\n", + "\n", + "Each file is checked for the rotation schema, provenance, configuration, environment, timestamps, and runner hashes. Malformed and partially completed files remain visible in the validation table.\n", + "\n", + "## 3. Normalize Molecule and Execution-Mode Results\n", + "\n", + "The molecule is fixed at C7H16, so normalization produces one row per result file, orientation, and execution mode. Rows include geometry, AO and grid sizes, routes, statuses, measurements, allocator baselines, and both runtime and memory fingerprints.\n", + "\n", + "## 4. Validate Benchmark Completeness and Status\n", + "\n", + "A full run requires 72 orientations, three modes, and successful runtime and memory records. Smoke and partial runs are accepted but explicitly reported.\n", + "\n", + "## 5. Verify AO Counts, Routes, and Screening Thresholds\n", + "\n", + "Observed AO counts must remain 879. Dense CPU must report `dense`; screened CPU and GPU must report `global_ao_screening`, which is expected because 879 exceeds PySCF's switch size of 800." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50a0ade9", + "metadata": {}, + "outputs": [], + "source": [ + "NORMALIZED_COLUMNS = [\n", + " \"run_label\",\n", + " \"commit\",\n", + " \"branch\",\n", + " \"dirty\",\n", + " \"orientation_key\",\n", + " \"orientation_index\",\n", + " \"azimuth_degrees\",\n", + " \"polar_degrees\",\n", + " \"formula\",\n", + " \"carbon_count\",\n", + " \"expected_aos\",\n", + " \"actual_aos\",\n", + " \"electron_count\",\n", + " \"grid_points\",\n", + " \"mode\",\n", + " \"selected_route\",\n", + " \"route_request\",\n", + " \"switch_size\",\n", + " \"implementation_sha256\",\n", + " \"runtime_status\",\n", + " \"memory_status\",\n", + " \"runtime_samples_seconds\",\n", + " \"runtime_seconds\",\n", + " \"incremental_peak_bytes\",\n", + " \"incremental_peak_gib\",\n", + " \"allocator_baseline_bytes\",\n", + " \"allocator_baseline_gib\",\n", + "] + [\n", + " f\"{measurement}_{fingerprint}\"\n", + " for measurement in MEASUREMENTS\n", + " for fingerprint in FINGERPRINT_LABELS\n", + "]\n", + "\n", + "\n", + "def validate_document(path: Path, document: dict[str, Any]) -> list[str]:\n", + " failures: list[str] = []\n", + " required_fields = {\n", + " \"configuration\",\n", + " \"created_at\",\n", + " \"environment\",\n", + " \"orientations\",\n", + " \"runner_hashes\",\n", + " \"schema_version\",\n", + " \"source\",\n", + " \"updated_at\",\n", + " }\n", + " missing_fields = sorted(required_fields - document.keys())\n", + " if missing_fields:\n", + " failures.append(f\"missing top-level fields: {missing_fields}\")\n", + " if document.get(\"schema_version\") != 1:\n", + " failures.append(f\"unsupported schema version {document.get('schema_version')}\")\n", + " if document.get(\"benchmark\") != \"pyscf_ao_screening_rotations\":\n", + " failures.append(f\"unexpected benchmark marker {document.get('benchmark')!r}\")\n", + "\n", + " configuration = document.get(\"configuration\", {})\n", + " configured_modes = tuple(configuration.get(\"modes\", ()))\n", + " configured_measurements = tuple(configuration.get(\"measurements\", ()))\n", + " if configured_modes and configured_modes != MODES:\n", + " failures.append(f\"configured modes are {configured_modes}, expected {MODES}\")\n", + " if configured_measurements and configured_measurements != MEASUREMENTS:\n", + " failures.append(\n", + " f\"configured measurements are {configured_measurements}, expected {MEASUREMENTS}\"\n", + " )\n", + "\n", + " orientations = document.get(\"orientations\", {})\n", + " expected_count = int(configuration.get(\"orientation_count\", len(orientations)))\n", + " if len(orientations) != expected_count:\n", + " failures.append(\n", + " f\"contains {len(orientations)} orientations, configuration requests {expected_count}\"\n", + " )\n", + " if not configuration.get(\"smoke_run\", False) and len(orientations) != 72:\n", + " failures.append(\n", + " f\"full run contains {len(orientations)} orientations, expected 72\"\n", + " )\n", + " coordinate_hashes = [\n", + " orientation.get(\"coordinate_sha256\") for orientation in orientations.values()\n", + " ]\n", + " if len(set(coordinate_hashes)) != len(coordinate_hashes):\n", + " failures.append(\"orientation coordinate hashes are not unique\")\n", + "\n", + " for orientation_key, orientation in orientations.items():\n", + " observed = orientation.get(\"observed\") or {}\n", + " actual_aos = observed.get(\"actual_aos\")\n", + " if actual_aos is not None and int(actual_aos) != EXPECTED_AOS:\n", + " failures.append(\n", + " f\"{orientation_key}: observed {actual_aos} AOs, expected {EXPECTED_AOS}\"\n", + " )\n", + " modes = orientation.get(\"modes\", {})\n", + " missing_modes = sorted(set(MODES) - modes.keys())\n", + " if missing_modes:\n", + " failures.append(f\"{orientation_key}: missing modes {missing_modes}\")\n", + " for mode in MODES:\n", + " mode_record = modes.get(mode, {})\n", + " route = mode_record.get(\"route\", {})\n", + " selected_route = route.get(\"selected_route\")\n", + " if selected_route is not None and selected_route != EXPECTED_ROUTES[mode]:\n", + " failures.append(\n", + " f\"{orientation_key} {mode}: selected {selected_route}, \"\n", + " f\"expected {EXPECTED_ROUTES[mode]}\"\n", + " )\n", + " switch_size = route.get(\"pyscf_switch_size\")\n", + " if switch_size is not None and EXPECTED_AOS <= int(switch_size):\n", + " failures.append(\n", + " f\"{orientation_key} {mode}: {EXPECTED_AOS} AOs do not exceed \"\n", + " f\"reported switch size {switch_size}\"\n", + " )\n", + " for measurement in MEASUREMENTS:\n", + " result = mode_record.get(measurement)\n", + " if result is None:\n", + " failures.append(f\"{orientation_key} {mode}: missing {measurement}\")\n", + " continue\n", + " status = result.get(\"status\")\n", + " if status not in TERMINAL_STATUSES:\n", + " failures.append(\n", + " f\"{orientation_key} {mode} {measurement}: unknown status {status!r}\"\n", + " )\n", + " elif status != \"ok\":\n", + " failures.append(\n", + " f\"{orientation_key} {mode} {measurement}: status {status}\"\n", + " )\n", + " if (\n", + " measurement == \"runtime\"\n", + " and status == \"ok\"\n", + " and not result.get(\"runtime_samples_seconds\")\n", + " ):\n", + " failures.append(\n", + " f\"{orientation_key} {mode}: successful runtime has no samples\"\n", + " )\n", + " return failures\n", + "\n", + "\n", + "def normalize_document(path: Path, document: dict[str, Any]) -> list[dict[str, Any]]:\n", + " base_molecule = document.get(\"geometry\", {}).get(\"base_molecule\", {})\n", + " source = document.get(\"source\", {})\n", + " run_label = str(document.get(\"run_label\") or path.stem)\n", + " rows: list[dict[str, Any]] = []\n", + " for orientation_key, orientation in document.get(\"orientations\", {}).items():\n", + " observed = orientation.get(\"observed\") or {}\n", + " for mode in MODES:\n", + " mode_record = orientation.get(\"modes\", {}).get(mode, {})\n", + " runtime = mode_record.get(\"runtime\", {})\n", + " memory = mode_record.get(\"memory\", {})\n", + " route = mode_record.get(\"route\", {})\n", + " runtime_samples = [\n", + " float(value) for value in runtime.get(\"runtime_samples_seconds\", [])\n", + " ]\n", + " row: dict[str, Any] = {\n", + " \"run_label\": run_label,\n", + " \"commit\": source.get(\"commit\"),\n", + " \"branch\": source.get(\"branch\"),\n", + " \"dirty\": source.get(\"dirty\"),\n", + " \"orientation_key\": orientation_key,\n", + " \"orientation_index\": orientation.get(\"index\"),\n", + " \"azimuth_degrees\": orientation.get(\"azimuth_degrees\"),\n", + " \"polar_degrees\": orientation.get(\"polar_degrees\"),\n", + " \"formula\": base_molecule.get(\"formula\", observed.get(\"formula\")),\n", + " \"carbon_count\": base_molecule.get(\n", + " \"carbon_count\", observed.get(\"carbon_count\")\n", + " ),\n", + " \"expected_aos\": base_molecule.get(\"expected_aos\", EXPECTED_AOS),\n", + " \"actual_aos\": observed.get(\"actual_aos\"),\n", + " \"electron_count\": observed.get(\"electron_count\"),\n", + " \"grid_points\": observed.get(\"grid_points\"),\n", + " \"mode\": mode,\n", + " \"selected_route\": route.get(\"selected_route\"),\n", + " \"route_request\": route.get(\"request\"),\n", + " \"switch_size\": route.get(\"pyscf_switch_size\"),\n", + " \"implementation_sha256\": route.get(\"implementation_sha256\"),\n", + " \"runtime_status\": runtime.get(\"status\", \"missing\"),\n", + " \"memory_status\": memory.get(\"status\", \"missing\"),\n", + " \"runtime_samples_seconds\": runtime_samples,\n", + " \"runtime_seconds\": (\n", + " statistics.median(runtime_samples) if runtime_samples else np.nan\n", + " ),\n", + " \"incremental_peak_bytes\": memory.get(\"incremental_peak_bytes\"),\n", + " \"incremental_peak_gib\": (\n", + " float(memory[\"incremental_peak_bytes\"]) / 1024**3\n", + " if memory.get(\"incremental_peak_bytes\") is not None\n", + " else np.nan\n", + " ),\n", + " \"allocator_baseline_bytes\": memory.get(\"allocator_baseline_bytes\"),\n", + " \"allocator_baseline_gib\": (\n", + " float(memory[\"allocator_baseline_bytes\"]) / 1024**3\n", + " if memory.get(\"allocator_baseline_bytes\") is not None\n", + " else np.nan\n", + " ),\n", + " }\n", + " for measurement, result in ((\"runtime\", runtime), (\"memory\", memory)):\n", + " fingerprint = result.get(\"fingerprint\", {})\n", + " for fingerprint_key in FINGERPRINT_LABELS:\n", + " row[f\"{measurement}_{fingerprint_key}\"] = fingerprint.get(\n", + " fingerprint_key, np.nan\n", + " )\n", + " rows.append(row)\n", + " return rows\n", + "\n", + "\n", + "DOCUMENTS: list[tuple[Path, dict[str, Any]]] = []\n", + "validation_rows: list[dict[str, str]] = []\n", + "normalized_rows: list[dict[str, Any]] = []\n", + "for result_file in SELECTED_RESULT_FILES:\n", + " try:\n", + " document = json.loads(result_file.read_text(encoding=\"utf-8\"))\n", + " except (OSError, json.JSONDecodeError) as error:\n", + " validation_rows.append(\n", + " {\"run_label\": result_file.stem, \"failure\": f\"could not load: {error}\"}\n", + " )\n", + " continue\n", + " DOCUMENTS.append((result_file, document))\n", + " normalized_rows.extend(normalize_document(result_file, document))\n", + " failures = validate_document(result_file, document)\n", + " run_label = str(document.get(\"run_label\") or result_file.stem)\n", + " validation_rows.extend(\n", + " {\"run_label\": run_label, \"failure\": failure} for failure in failures\n", + " )\n", + "\n", + "run_labels = [\n", + " str(document.get(\"run_label\") or path.stem) for path, document in DOCUMENTS\n", + "]\n", + "duplicate_run_labels = sorted(\n", + " label for label, count in Counter(run_labels).items() if count > 1\n", + ")\n", + "if duplicate_run_labels:\n", + " raise ValueError(f\"Run labels must be unique: {duplicate_run_labels}\")\n", + "\n", + "normalized_df = pd.DataFrame(normalized_rows, columns=NORMALIZED_COLUMNS)\n", + "validation_df = pd.DataFrame(validation_rows, columns=[\"run_label\", \"failure\"])\n", + "if DOCUMENTS:\n", + " print(\n", + " f\"Loaded {len(DOCUMENTS)} document(s) and {len(normalized_df)} normalized rows\"\n", + " )\n", + "else:\n", + " print(\"No rotation benchmark JSON files found. Run the benchmark first.\")\n", + "display(\n", + " validation_df\n", + " if not validation_df.empty\n", + " else pd.DataFrame({\"validation\": [\"passed\"]})\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c20ff5e3", + "metadata": {}, + "outputs": [], + "source": [ + "if normalized_df.empty:\n", + " status_summary_df = pd.DataFrame()\n", + " route_summary_df = pd.DataFrame()\n", + "else:\n", + " status_rows: list[dict[str, Any]] = []\n", + " for status_column in (\"runtime_status\", \"memory_status\"):\n", + " measurement = status_column.removesuffix(\"_status\")\n", + " grouped = normalized_df.groupby(\n", + " [\"run_label\", \"mode\", status_column], dropna=False\n", + " ).size()\n", + " for (run_label, mode, status), count in grouped.items():\n", + " status_rows.append(\n", + " {\n", + " \"run_label\": run_label,\n", + " \"mode\": mode,\n", + " \"measurement\": measurement,\n", + " \"status\": status,\n", + " \"count\": int(count),\n", + " }\n", + " )\n", + " status_summary_df = pd.DataFrame(status_rows)\n", + " route_summary_df = (\n", + " normalized_df.groupby([\"run_label\", \"mode\", \"selected_route\"], dropna=False)\n", + " .size()\n", + " .rename(\"orientation_count\")\n", + " .reset_index()\n", + " )\n", + "\n", + "print(\"Measurement status counts\")\n", + "display(status_summary_df)\n", + "print(\"Selected route counts\")\n", + "display(route_summary_df)" + ] + }, + { + "cell_type": "markdown", + "id": "b0a59c29", + "metadata": {}, + "source": [ + "## 6. Compare Numerical Fingerprints\n", + "\n", + "For every orientation, the runtime and memory workers are compared within each mode. The runtime fingerprints for GPU and screened CPU are also compared with CPU dense at the same orientation. The table reports signed, absolute, and relative differences for all six recorded quantities and applies configurable mode-specific tolerances." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d5affd6", + "metadata": {}, + "outputs": [], + "source": [ + "NUMERICAL_COLUMNS = [\n", + " \"run_label\",\n", + " \"orientation_key\",\n", + " \"orientation_index\",\n", + " \"azimuth_degrees\",\n", + " \"polar_degrees\",\n", + " \"comparison\",\n", + " \"mode\",\n", + " \"fingerprint\",\n", + " \"reference_value\",\n", + " \"comparison_value\",\n", + " \"difference\",\n", + " \"absolute_error\",\n", + " \"relative_error\",\n", + " \"tolerance\",\n", + " \"within_tolerance\",\n", + "]\n", + "\n", + "\n", + "def numerical_difference(\n", + " row: pd.Series,\n", + " *,\n", + " comparison: str,\n", + " mode: str,\n", + " fingerprint: str,\n", + " reference_value: float,\n", + " comparison_value: float,\n", + " rtol: float,\n", + " atol: float,\n", + ") -> dict[str, Any] | None:\n", + " if not np.isfinite(reference_value) or not np.isfinite(comparison_value):\n", + " return None\n", + " difference = float(comparison_value - reference_value)\n", + " absolute_error = abs(difference)\n", + " relative_error = absolute_error / max(\n", + " abs(float(reference_value)), np.finfo(float).tiny\n", + " )\n", + " tolerance = atol + rtol * abs(float(reference_value))\n", + " return {\n", + " \"run_label\": row[\"run_label\"],\n", + " \"orientation_key\": row[\"orientation_key\"],\n", + " \"orientation_index\": row[\"orientation_index\"],\n", + " \"azimuth_degrees\": row[\"azimuth_degrees\"],\n", + " \"polar_degrees\": row[\"polar_degrees\"],\n", + " \"comparison\": comparison,\n", + " \"mode\": mode,\n", + " \"fingerprint\": fingerprint,\n", + " \"reference_value\": float(reference_value),\n", + " \"comparison_value\": float(comparison_value),\n", + " \"difference\": difference,\n", + " \"absolute_error\": absolute_error,\n", + " \"relative_error\": relative_error,\n", + " \"tolerance\": tolerance,\n", + " \"within_tolerance\": absolute_error <= tolerance,\n", + " }\n", + "\n", + "\n", + "numerical_rows: list[dict[str, Any]] = []\n", + "for _, row in normalized_df.iterrows():\n", + " mode = str(row[\"mode\"])\n", + " rtol, atol = ERROR_TOLERANCES.get(mode, (5e-8, 1e-8))\n", + " for fingerprint in FINGERPRINT_LABELS:\n", + " record = numerical_difference(\n", + " row,\n", + " comparison=\"runtime_vs_memory\",\n", + " mode=mode,\n", + " fingerprint=fingerprint,\n", + " reference_value=float(row[f\"runtime_{fingerprint}\"]),\n", + " comparison_value=float(row[f\"memory_{fingerprint}\"]),\n", + " rtol=rtol,\n", + " atol=atol,\n", + " )\n", + " if record is not None:\n", + " numerical_rows.append(record)\n", + "\n", + "if not normalized_df.empty:\n", + " indexed = normalized_df.set_index(\n", + " [\"run_label\", \"orientation_key\", \"mode\"], drop=False\n", + " )\n", + " for (run_label, orientation_key), _ in normalized_df.groupby(\n", + " [\"run_label\", \"orientation_key\"]\n", + " ):\n", + " dense_key = (run_label, orientation_key, REFERENCE_MODE)\n", + " if dense_key not in indexed.index:\n", + " continue\n", + " dense_row = indexed.loc[dense_key]\n", + " for mode in (\"cpu_screened\", \"gpu\"):\n", + " production_key = (run_label, orientation_key, mode)\n", + " if production_key not in indexed.index:\n", + " continue\n", + " production_row = indexed.loc[production_key]\n", + " rtol, atol = ERROR_TOLERANCES[mode]\n", + " for fingerprint in FINGERPRINT_LABELS:\n", + " record = numerical_difference(\n", + " production_row,\n", + " comparison=\"mode_vs_cpu_dense\",\n", + " mode=mode,\n", + " fingerprint=fingerprint,\n", + " reference_value=float(dense_row[f\"runtime_{fingerprint}\"]),\n", + " comparison_value=float(production_row[f\"runtime_{fingerprint}\"]),\n", + " rtol=rtol,\n", + " atol=atol,\n", + " )\n", + " if record is not None:\n", + " numerical_rows.append(record)\n", + "\n", + "numerical_df = pd.DataFrame(numerical_rows, columns=NUMERICAL_COLUMNS)\n", + "if numerical_df.empty:\n", + " numerical_summary_df = pd.DataFrame()\n", + "else:\n", + " numerical_summary_df = (\n", + " numerical_df.groupby([\"run_label\", \"comparison\", \"mode\", \"fingerprint\"])\n", + " .agg(\n", + " compared=(\"absolute_error\", \"size\"),\n", + " max_absolute_error=(\"absolute_error\", \"max\"),\n", + " max_relative_error=(\"relative_error\", \"max\"),\n", + " outside_tolerance=(\"within_tolerance\", lambda values: int((~values).sum())),\n", + " )\n", + " .reset_index()\n", + " )\n", + "display(numerical_summary_df)" + ] + }, + { + "cell_type": "markdown", + "id": "1c54906d", + "metadata": {}, + "source": [ + "## 7. Calculate Runtime Metrics and Speedups\n", + "\n", + "Runtime summaries use the median sample as the representative value. The comparison table includes dense-to-screened, dense-to-GPU, screened-CPU-to-GPU, and cross-run speedups at matched orientations.\n", + "\n", + "## 8. Calculate Memory Metrics and Reductions\n", + "\n", + "Incremental peaks and GPU allocator baselines are converted to GiB. Reduction factors use CPU dense as the numerator so values above one indicate improvement.\n", + "\n", + "## 9. Analyze Scaling with Molecular Size\n", + "\n", + "This benchmark intentionally fixes molecular size at C7H16 and 879 AOs, so molecular-size fitting is not meaningful. Instead, a harmonic least-squares model summarizes orientation sensitivity and records fit coefficients, $R^2$, and residual RMSE for runtime and memory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56dee578", + "metadata": {}, + "outputs": [], + "source": [ + "def summarize_metric(frame: pd.DataFrame, metric: str, value_name: str) -> pd.DataFrame:\n", + " rows: list[dict[str, Any]] = []\n", + " for (run_label, mode), group in frame.groupby([\"run_label\", \"mode\"]):\n", + " values = group[metric].dropna().astype(float).to_numpy()\n", + " if values.size == 0:\n", + " continue\n", + " mean_value = float(values.mean())\n", + " rows.append(\n", + " {\n", + " \"run_label\": run_label,\n", + " \"mode\": mode,\n", + " \"observation_count\": int(values.size),\n", + " \"minimum\": float(values.min()),\n", + " \"median\": float(np.median(values)),\n", + " \"mean\": mean_value,\n", + " \"standard_deviation\": (\n", + " float(values.std(ddof=1)) if values.size > 1 else 0.0\n", + " ),\n", + " \"coefficient_of_variation\": (\n", + " float(values.std(ddof=1) / mean_value)\n", + " if values.size > 1 and mean_value != 0.0\n", + " else 0.0\n", + " ),\n", + " \"representative\": float(np.median(values)),\n", + " \"unit\": value_name,\n", + " }\n", + " )\n", + " return pd.DataFrame(rows)\n", + "\n", + "\n", + "runtime_statistics_df = summarize_metric(normalized_df, \"runtime_seconds\", \"seconds\")\n", + "if not runtime_statistics_df.empty:\n", + " runtime_sample_counts = (\n", + " normalized_df.assign(\n", + " runtime_sample_count=normalized_df[\"runtime_samples_seconds\"].map(len)\n", + " )\n", + " .groupby([\"run_label\", \"mode\"])[\"runtime_sample_count\"]\n", + " .sum()\n", + " .reset_index()\n", + " )\n", + " runtime_statistics_df = runtime_statistics_df.merge(\n", + " runtime_sample_counts,\n", + " on=[\"run_label\", \"mode\"],\n", + " how=\"left\",\n", + " )\n", + "memory_statistics_df = summarize_metric(normalized_df, \"incremental_peak_gib\", \"GiB\")\n", + "\n", + "\n", + "def finite_ratio(numerator: Any, denominator: Any) -> float:\n", + " numerator_value = float(numerator)\n", + " denominator_value = float(denominator)\n", + " if (\n", + " np.isfinite(numerator_value)\n", + " and np.isfinite(denominator_value)\n", + " and denominator_value > 0.0\n", + " ):\n", + " return numerator_value / denominator_value\n", + " return np.nan\n", + "\n", + "\n", + "comparison_rows: list[dict[str, Any]] = []\n", + "for (run_label, orientation_key), group in normalized_df.groupby(\n", + " [\"run_label\", \"orientation_key\"]\n", + "):\n", + " by_mode = group.set_index(\"mode\")\n", + " if any(mode not in by_mode.index for mode in MODES):\n", + " continue\n", + " dense = by_mode.loc[\"cpu_dense\"]\n", + " screened = by_mode.loc[\"cpu_screened\"]\n", + " gpu = by_mode.loc[\"gpu\"]\n", + " comparison_rows.append(\n", + " {\n", + " \"run_label\": run_label,\n", + " \"orientation_key\": orientation_key,\n", + " \"orientation_index\": dense[\"orientation_index\"],\n", + " \"azimuth_degrees\": dense[\"azimuth_degrees\"],\n", + " \"polar_degrees\": dense[\"polar_degrees\"],\n", + " \"dense_to_screened_runtime_speedup\": finite_ratio(\n", + " dense[\"runtime_seconds\"], screened[\"runtime_seconds\"]\n", + " ),\n", + " \"dense_to_gpu_runtime_speedup\": finite_ratio(\n", + " dense[\"runtime_seconds\"], gpu[\"runtime_seconds\"]\n", + " ),\n", + " \"screened_cpu_to_gpu_runtime_speedup\": finite_ratio(\n", + " screened[\"runtime_seconds\"], gpu[\"runtime_seconds\"]\n", + " ),\n", + " \"dense_to_screened_memory_reduction\": finite_ratio(\n", + " dense[\"incremental_peak_gib\"], screened[\"incremental_peak_gib\"]\n", + " ),\n", + " \"dense_to_gpu_memory_reduction\": finite_ratio(\n", + " dense[\"incremental_peak_gib\"], gpu[\"incremental_peak_gib\"]\n", + " ),\n", + " \"screened_cpu_to_gpu_memory_ratio\": finite_ratio(\n", + " screened[\"incremental_peak_gib\"], gpu[\"incremental_peak_gib\"]\n", + " ),\n", + " }\n", + " )\n", + "comparison_metrics_df = pd.DataFrame(comparison_rows)\n", + "\n", + "cross_run_rows: list[dict[str, Any]] = []\n", + "if len(DOCUMENTS) > 1 and not normalized_df.empty:\n", + " baseline_path, baseline_document = DOCUMENTS[0]\n", + " baseline_run_label = str(baseline_document.get(\"run_label\") or baseline_path.stem)\n", + " baseline = normalized_df[\n", + " normalized_df[\"run_label\"] == baseline_run_label\n", + " ].set_index([\"orientation_key\", \"mode\"])\n", + " for current_path, document in DOCUMENTS[1:]:\n", + " current_run_label = str(document.get(\"run_label\") or current_path.stem)\n", + " current = normalized_df[\n", + " normalized_df[\"run_label\"] == current_run_label\n", + " ].set_index([\"orientation_key\", \"mode\"])\n", + " for key in baseline.index.intersection(current.index):\n", + " baseline_row = baseline.loc[key]\n", + " current_row = current.loc[key]\n", + " cross_run_rows.append(\n", + " {\n", + " \"baseline_run_label\": baseline_run_label,\n", + " \"comparison_run_label\": current_run_label,\n", + " \"orientation_key\": key[0],\n", + " \"mode\": key[1],\n", + " \"runtime_speedup\": finite_ratio(\n", + " baseline_row[\"runtime_seconds\"],\n", + " current_row[\"runtime_seconds\"],\n", + " ),\n", + " \"memory_reduction\": finite_ratio(\n", + " baseline_row[\"incremental_peak_gib\"],\n", + " current_row[\"incremental_peak_gib\"],\n", + " ),\n", + " }\n", + " )\n", + "cross_run_df = pd.DataFrame(cross_run_rows)\n", + "\n", + "orientation_fit_rows: list[dict[str, Any]] = []\n", + "for (run_label, mode), group in normalized_df.groupby([\"run_label\", \"mode\"]):\n", + " for metric in (\"runtime_seconds\", \"incremental_peak_gib\"):\n", + " fit_data = group.dropna(subset=[\"azimuth_degrees\", \"polar_degrees\", metric])\n", + " if len(fit_data) < 5:\n", + " continue\n", + " azimuth = np.radians(fit_data[\"azimuth_degrees\"].to_numpy(float))\n", + " polar = np.radians(fit_data[\"polar_degrees\"].to_numpy(float))\n", + " design = np.column_stack(\n", + " [\n", + " np.ones(len(fit_data)),\n", + " np.sin(azimuth),\n", + " np.cos(azimuth),\n", + " np.sin(polar),\n", + " np.cos(polar),\n", + " ]\n", + " )\n", + " values = fit_data[metric].to_numpy(float)\n", + " coefficients, _, _, _ = np.linalg.lstsq(design, values, rcond=None)\n", + " residuals = values - design @ coefficients\n", + " total_variation = float(np.square(values - values.mean()).sum())\n", + " residual_variation = float(np.square(residuals).sum())\n", + " orientation_fit_rows.append(\n", + " {\n", + " \"run_label\": run_label,\n", + " \"mode\": mode,\n", + " \"metric\": metric,\n", + " \"intercept\": float(coefficients[0]),\n", + " \"sin_azimuth\": float(coefficients[1]),\n", + " \"cos_azimuth\": float(coefficients[2]),\n", + " \"sin_polar\": float(coefficients[3]),\n", + " \"cos_polar\": float(coefficients[4]),\n", + " \"r_squared\": (\n", + " 1.0 - residual_variation / total_variation\n", + " if total_variation > 0.0\n", + " else 1.0\n", + " ),\n", + " \"residual_rmse\": float(np.sqrt(np.mean(np.square(residuals)))),\n", + " }\n", + " )\n", + "orientation_fit_df = pd.DataFrame(orientation_fit_rows)\n", + "\n", + "print(\"Runtime statistics\")\n", + "display(runtime_statistics_df)\n", + "print(\"Memory statistics\")\n", + "display(memory_statistics_df)\n", + "print(\"Per-orientation speedup and reduction metrics\")\n", + "display(comparison_metrics_df)\n", + "print(\"Cross-run changes\")\n", + "display(cross_run_df)\n", + "print(\"Orientation-sensitivity fits\")\n", + "display(orientation_fit_df)" + ] + }, + { + "cell_type": "markdown", + "id": "bf4b225f", + "metadata": {}, + "source": [ + "## 10. Visualize Runtime Comparisons\n", + "\n", + "Runtime is shown by orientation index, as mode/revision distributions, and as 12-by-6 azimuth/polar heatmaps. Since AO count is fixed, route labels replace a screening-threshold marker.\n", + "\n", + "## 11. Visualize Memory Comparisons\n", + "\n", + "Incremental peak memory uses the same views, with GPU allocator baseline retained in the normalized table and exported metadata.\n", + "\n", + "## 12. Visualize Speedup and Memory Reduction\n", + "\n", + "Dense-to-screened and dense-to-GPU factors are rendered on the same angular grid. Values above one indicate faster execution or lower peak memory than CPU dense.\n", + "\n", + "## 13. Visualize Numerical Differences\n", + "\n", + "Signed fingerprint differences use CPU dense as zero. Change `FINGERPRINT_TO_PLOT` to inspect any of the six recorded fingerprint quantities." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea347d87", + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "\n", + "from matplotlib.figure import Figure\n", + "\n", + "LINE_STYLES = (\"-\", \"--\", \"-.\", \":\")\n", + "MARKERS = (\"o\", \"s\", \"^\", \"D\")\n", + "PLOT_STYLES = tuple(zip(LINE_STYLES, MARKERS, strict=True))\n", + "if len(DOCUMENTS) > len(PLOT_STYLES):\n", + " raise ValueError(f\"At most {len(PLOT_STYLES)} distinct run labels can be plotted\")\n", + "LABEL_PLOT_STYLES = {\n", + " str(document.get(\"run_label\") or path.stem): PLOT_STYLES[index]\n", + " for index, (path, document) in enumerate(DOCUMENTS)\n", + "}\n", + "\n", + "\n", + "def safe_filename(value: str) -> str:\n", + " return re.sub(r\"[^A-Za-z0-9_.-]+\", \"-\", value).strip(\"-.\") or \"result\"\n", + "\n", + "\n", + "def orientation_matrix(frame: pd.DataFrame, value_column: str) -> pd.DataFrame:\n", + " if frame.empty:\n", + " return pd.DataFrame()\n", + " return (\n", + " frame.pivot(\n", + " index=\"polar_degrees\",\n", + " columns=\"azimuth_degrees\",\n", + " values=value_column,\n", + " )\n", + " .sort_index()\n", + " .sort_index(axis=1)\n", + " )\n", + "\n", + "\n", + "def finite_value_range(values: Any) -> tuple[float, float] | None:\n", + " numeric = np.asarray(values, dtype=float)\n", + " finite = numeric[np.isfinite(numeric)]\n", + " if finite.size == 0:\n", + " return None\n", + " minimum = float(finite.min())\n", + " maximum = float(finite.max())\n", + " if minimum == maximum:\n", + " padding = max(abs(minimum) * 1e-9, np.finfo(float).eps)\n", + " return minimum - padding, maximum + padding\n", + " return minimum, maximum\n", + "\n", + "\n", + "def observed_range_errors(samples: Any, center: float) -> tuple[float, float]:\n", + " numeric = np.asarray(samples, dtype=float)\n", + " finite = numeric[np.isfinite(numeric)]\n", + " if finite.size == 0:\n", + " return 0.0, 0.0\n", + " return (\n", + " max(0.0, center - float(finite.min())),\n", + " max(0.0, float(finite.max()) - center),\n", + " )\n", + "\n", + "\n", + "def finish_figure(figure: Figure, output_path: Path | None = None) -> None:\n", + " if output_path is not None:\n", + " output_path.parent.mkdir(parents=True, exist_ok=True)\n", + " figure.savefig(output_path, dpi=180, bbox_inches=\"tight\")\n", + " plt.show()\n", + "\n", + "\n", + "def plot_orientation_lines(\n", + " value_column: str,\n", + " ylabel: str,\n", + " output_path: Path | None = None,\n", + " error_samples_column: str | None = None,\n", + ") -> None:\n", + " data = normalized_df.dropna(subset=[\"orientation_index\", value_column])\n", + " if data.empty:\n", + " print(f\"No successful values available for {value_column}\")\n", + " return\n", + " figure, axis = plt.subplots(figsize=(12, 6), constrained_layout=True)\n", + " for (run_label, mode), group in data.groupby([\"run_label\", \"mode\"]):\n", + " ordered = group.sort_values(\"orientation_index\")\n", + " x_values = ordered[\"orientation_index\"].to_numpy(float)\n", + " centers = ordered[value_column].to_numpy(float)\n", + " line_style, marker = LABEL_PLOT_STYLES[str(run_label)]\n", + " plot_options = {\n", + " \"color\": MODE_COLORS[mode],\n", + " \"linewidth\": 1.2,\n", + " \"alpha\": 0.85,\n", + " \"label\": f\"{run_label} {mode}\",\n", + " \"linestyle\": line_style,\n", + " \"marker\": marker,\n", + " \"markersize\": 3.5,\n", + " \"markevery\": max(1, len(ordered) // 12),\n", + " }\n", + " if error_samples_column is None:\n", + " axis.plot(x_values, centers, **plot_options)\n", + " else:\n", + " errors = np.asarray(\n", + " [\n", + " observed_range_errors(samples, center)\n", + " for samples, center in zip(\n", + " ordered[error_samples_column], centers, strict=True\n", + " )\n", + " ],\n", + " dtype=float,\n", + " ).T\n", + " axis.errorbar(\n", + " x_values,\n", + " centers,\n", + " yerr=errors,\n", + " capsize=2,\n", + " elinewidth=0.7,\n", + " **plot_options,\n", + " )\n", + " title = f\"{ylabel} across molecular orientations\"\n", + " if error_samples_column is not None:\n", + " title += \" (median and observed min-max)\"\n", + " axis.set(\n", + " title=title,\n", + " xlabel=\"Orientation index (azimuth-major, then polar)\",\n", + " ylabel=ylabel,\n", + " )\n", + " axis.grid(True, color=\"#D9D9D9\", linewidth=0.6)\n", + " axis.legend(fontsize=8, ncol=2)\n", + " finish_figure(figure, output_path)\n", + "\n", + "\n", + "def plot_mode_distribution(\n", + " value_column: str, ylabel: str, output_path: Path | None = None\n", + ") -> None:\n", + " data = normalized_df.dropna(subset=[value_column])\n", + " if data.empty:\n", + " print(f\"No successful values available for {value_column}\")\n", + " return\n", + " figure, axis = plt.subplots(figsize=(10, 6), constrained_layout=True)\n", + " sns.boxplot(\n", + " data=data,\n", + " x=\"mode\",\n", + " y=value_column,\n", + " hue=\"run_label\",\n", + " order=MODES,\n", + " showfliers=True,\n", + " ax=axis,\n", + " )\n", + " axis.set(title=f\"{ylabel} distribution by mode\", xlabel=\"Mode\", ylabel=ylabel)\n", + " axis.grid(True, axis=\"y\", color=\"#D9D9D9\", linewidth=0.6)\n", + " finish_figure(figure, output_path)\n", + "\n", + "\n", + "def plot_measurement_heatmaps(\n", + " value_column: str,\n", + " colorbar_label: str,\n", + " output_dir: Path | None = None,\n", + ") -> None:\n", + " if normalized_df[value_column].dropna().empty:\n", + " print(f\"No successful values available for {value_column}\")\n", + " return\n", + " for path, document in DOCUMENTS:\n", + " run_label = str(document.get(\"run_label\") or path.stem)\n", + " run_data = normalized_df[normalized_df[\"run_label\"] == run_label]\n", + " figure, axes = plt.subplots(\n", + " 1, len(MODES), figsize=(18, 4.8), constrained_layout=True\n", + " )\n", + " for axis, mode in zip(axes, MODES, strict=True):\n", + " matrix = orientation_matrix(\n", + " run_data[run_data[\"mode\"] == mode], value_column\n", + " )\n", + " value_range = finite_value_range(matrix)\n", + " if value_range is None:\n", + " axis.text(0.5, 0.5, \"No successful data\", ha=\"center\", va=\"center\")\n", + " axis.set_axis_off()\n", + " continue\n", + " minimum, maximum = value_range\n", + " sns.heatmap(\n", + " matrix,\n", + " mask=matrix.isna(),\n", + " cmap=\"viridis\",\n", + " vmin=minimum,\n", + " vmax=maximum,\n", + " cbar_kws={\"label\": colorbar_label},\n", + " ax=axis,\n", + " )\n", + " route_values = (\n", + " run_data.loc[run_data[\"mode\"] == mode, \"selected_route\"]\n", + " .dropna()\n", + " .unique()\n", + " )\n", + " route_label = \", \".join(str(value) for value in route_values) or \"no route\"\n", + " axis.set(\n", + " title=f\"{mode} ({route_label})\",\n", + " xlabel=\"Azimuth (degrees)\",\n", + " ylabel=\"Polar angle (degrees)\",\n", + " )\n", + " figure.suptitle(f\"{run_label} {colorbar_label} by orientation\")\n", + " output_path = (\n", + " output_dir\n", + " / f\"{safe_filename(run_label)}-{safe_filename(value_column)}-heatmap.png\"\n", + " if output_dir is not None\n", + " else None\n", + " )\n", + " finish_figure(figure, output_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f41656f2", + "metadata": {}, + "outputs": [], + "source": [ + "RATIO_LABELS = {\n", + " \"dense_to_screened_runtime_speedup\": \"CPU dense / CPU screened runtime\",\n", + " \"dense_to_gpu_runtime_speedup\": \"CPU dense / GPU runtime\",\n", + " \"dense_to_screened_memory_reduction\": \"CPU dense / CPU screened peak\",\n", + " \"dense_to_gpu_memory_reduction\": \"CPU dense / GPU peak\",\n", + "}\n", + "\n", + "\n", + "def plot_ratio_heatmaps(\n", + " ratio_columns: tuple[str, ...],\n", + " title: str,\n", + " output_dir: Path | None = None,\n", + ") -> None:\n", + " if comparison_metrics_df.empty:\n", + " print(f\"No matched mode data available for {title}\")\n", + " return\n", + " for path, document in DOCUMENTS:\n", + " run_label = str(document.get(\"run_label\") or path.stem)\n", + " run_data = comparison_metrics_df[\n", + " comparison_metrics_df[\"run_label\"] == run_label\n", + " ]\n", + " figure, axes = plt.subplots(\n", + " 1, len(ratio_columns), figsize=(12, 4.8), constrained_layout=True\n", + " )\n", + " axes_array = np.atleast_1d(axes)\n", + " for axis, ratio_column in zip(axes_array, ratio_columns, strict=True):\n", + " matrix = orientation_matrix(run_data, ratio_column)\n", + " value_range = finite_value_range(matrix)\n", + " if value_range is None:\n", + " axis.text(0.5, 0.5, \"No successful data\", ha=\"center\", va=\"center\")\n", + " axis.set_axis_off()\n", + " continue\n", + " minimum, maximum = value_range\n", + " heatmap_options: dict[str, Any] = {\n", + " \"cmap\": \"RdYlGn\",\n", + " \"vmin\": minimum,\n", + " \"vmax\": maximum,\n", + " }\n", + " if minimum < 1.0 < maximum:\n", + " heatmap_options[\"center\"] = 1.0\n", + " sns.heatmap(\n", + " matrix,\n", + " mask=matrix.isna(),\n", + " cbar_kws={\"label\": \"Factor\"},\n", + " ax=axis,\n", + " **heatmap_options,\n", + " )\n", + " axis.set(\n", + " title=RATIO_LABELS[ratio_column],\n", + " xlabel=\"Azimuth (degrees)\",\n", + " ylabel=\"Polar angle (degrees)\",\n", + " )\n", + " figure.suptitle(f\"{run_label} {title}\")\n", + " output_path = (\n", + " output_dir / f\"{safe_filename(run_label)}-{safe_filename(title)}.png\"\n", + " if output_dir is not None\n", + " else None\n", + " )\n", + " finish_figure(figure, output_path)\n", + "\n", + "\n", + "def plot_fingerprint_heatmaps(fingerprint: str, output_dir: Path | None = None) -> None:\n", + " if fingerprint not in FINGERPRINT_LABELS:\n", + " raise ValueError(f\"Unknown fingerprint {fingerprint!r}\")\n", + " data = numerical_df[\n", + " (numerical_df[\"comparison\"] == \"mode_vs_cpu_dense\")\n", + " & (numerical_df[\"fingerprint\"] == fingerprint)\n", + " ]\n", + " if data.empty:\n", + " print(f\"No matched numerical data available for {fingerprint}\")\n", + " return\n", + " for run_label, run_data in data.groupby(\"run_label\"):\n", + " figure, axes = plt.subplots(1, 2, figsize=(12, 4.8), constrained_layout=True)\n", + " for axis, mode in zip(axes, (\"cpu_screened\", \"gpu\"), strict=True):\n", + " matrix = orientation_matrix(\n", + " run_data[run_data[\"mode\"] == mode], \"difference\"\n", + " )\n", + " value_range = finite_value_range(matrix)\n", + " if value_range is None:\n", + " axis.text(0.5, 0.5, \"No successful data\", ha=\"center\", va=\"center\")\n", + " axis.set_axis_off()\n", + " continue\n", + " minimum, maximum = value_range\n", + " heatmap_options = {\n", + " \"cmap\": \"coolwarm\",\n", + " \"vmin\": minimum,\n", + " \"vmax\": maximum,\n", + " }\n", + " if minimum < 0.0 < maximum:\n", + " heatmap_options[\"center\"] = 0.0\n", + " sns.heatmap(\n", + " matrix,\n", + " mask=matrix.isna(),\n", + " cbar_kws={\"label\": \"Mode - CPU dense\"},\n", + " ax=axis,\n", + " **heatmap_options,\n", + " )\n", + " axis.set(\n", + " title=mode,\n", + " xlabel=\"Azimuth (degrees)\",\n", + " ylabel=\"Polar angle (degrees)\",\n", + " )\n", + " figure.suptitle(f\"{run_label} {FINGERPRINT_LABELS[fingerprint]} difference\")\n", + " output_path = (\n", + " output_dir\n", + " / f\"{safe_filename(str(run_label))}-{safe_filename(fingerprint)}-difference.png\"\n", + " if output_dir is not None\n", + " else None\n", + " )\n", + " finish_figure(figure, output_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "942e3acc", + "metadata": {}, + "outputs": [], + "source": [ + "FINGERPRINT_TO_PLOT = \"xc_energy\"\n", + "\n", + "plot_orientation_lines(\n", + " \"runtime_seconds\",\n", + " \"Runtime (s)\",\n", + " error_samples_column=\"runtime_samples_seconds\",\n", + ")\n", + "plot_mode_distribution(\"runtime_seconds\", \"Runtime (s)\")\n", + "plot_measurement_heatmaps(\"runtime_seconds\", \"Runtime (s)\")\n", + "\n", + "plot_orientation_lines(\"incremental_peak_gib\", \"Incremental peak memory (GiB)\")\n", + "plot_mode_distribution(\"incremental_peak_gib\", \"Incremental peak memory (GiB)\")\n", + "plot_measurement_heatmaps(\"incremental_peak_gib\", \"Incremental peak memory (GiB)\")\n", + "\n", + "plot_ratio_heatmaps(\n", + " (\"dense_to_screened_runtime_speedup\", \"dense_to_gpu_runtime_speedup\"),\n", + " \"runtime speedup\",\n", + ")\n", + "plot_ratio_heatmaps(\n", + " (\"dense_to_screened_memory_reduction\", \"dense_to_gpu_memory_reduction\"),\n", + " \"memory reduction\",\n", + ")\n", + "plot_fingerprint_heatmaps(FINGERPRINT_TO_PLOT)" + ] + }, + { + "cell_type": "markdown", + "id": "be0bdf30", + "metadata": {}, + "source": [ + "## 14. Record Environment and Source Metadata\n", + "\n", + "This table keeps hardware, package versions, CUDA details, thread settings, scientific configuration, source commit, dirty state, implementation hash, and both runner hashes alongside every comparison.\n", + "\n", + "## 15. Export Comparison Results to JSON\n", + "\n", + "The comparison artifact contains JSON-safe configuration summaries, normalized rows, runtime and memory statistics, speedups, numerical differences, validation failures, angular fits, environment metadata, and source provenance.\n", + "\n", + "## 16. Save Tables and Figures\n", + "\n", + "The final cell writes CSV tables and deterministic PNG files below `benchmarks/results/rotation_comparison`. Re-running the cell refreshes the report artifacts from the currently selected input files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c530c585", + "metadata": {}, + "outputs": [], + "source": [ + "metadata_rows: list[dict[str, Any]] = []\n", + "validation_failure_counts = Counter(row[\"run_label\"] for row in validation_rows)\n", + "for path, document in DOCUMENTS:\n", + " environment = document.get(\"environment\", {})\n", + " packages = environment.get(\"packages\", {})\n", + " cuda = environment.get(\"cuda\", {})\n", + " configuration = document.get(\"configuration\", {})\n", + " source = document.get(\"source\", {})\n", + " hashes = document.get(\"runner_hashes\", {})\n", + " run_label = str(document.get(\"run_label\") or path.stem)\n", + " document_rows = normalized_df[normalized_df[\"run_label\"] == run_label]\n", + " implementation_hashes = sorted(\n", + " str(value) for value in document_rows[\"implementation_sha256\"].dropna().unique()\n", + " )\n", + " metadata_rows.append(\n", + " {\n", + " \"run_label\": run_label,\n", + " \"created_at\": document.get(\"created_at\"),\n", + " \"updated_at\": document.get(\"updated_at\"),\n", + " \"python\": environment.get(\"python\"),\n", + " \"python_executable\": environment.get(\"python_executable\"),\n", + " \"pyscf\": packages.get(\"pyscf\"),\n", + " \"skala\": packages.get(\"skala\"),\n", + " \"torch\": packages.get(\"torch\"),\n", + " \"cupy\": packages.get(\"cupy\"),\n", + " \"gpu4pyscf\": packages.get(\"gpu4pyscf\"),\n", + " \"memray\": packages.get(\"memray\"),\n", + " \"cuda_available\": cuda.get(\"available\"),\n", + " \"torch_cuda_version\": cuda.get(\"torch_cuda_version\"),\n", + " \"device_name\": cuda.get(\"device_name\"),\n", + " \"cpu_threads\": configuration.get(\"cpu_threads\"),\n", + " \"thread_environment\": environment.get(\"thread_environment\"),\n", + " \"basis\": configuration.get(\"basis\"),\n", + " \"functional\": configuration.get(\"functional\"),\n", + " \"grid_level\": configuration.get(\"grid_level\"),\n", + " \"grid_alignment\": configuration.get(\"grid_alignment\"),\n", + " \"max_memory_mb\": configuration.get(\"max_memory_mb\"),\n", + " \"orientation_count\": configuration.get(\"orientation_count\"),\n", + " \"commit\": source.get(\"commit\"),\n", + " \"branch\": source.get(\"branch\"),\n", + " \"dirty\": source.get(\"dirty\"),\n", + " \"implementation_hashes\": implementation_hashes,\n", + " \"worker_sha256\": hashes.get(\"worker_sha256\"),\n", + " \"rotation_runner_sha256\": hashes.get(\"rotation_runner_sha256\"),\n", + " \"validation_failure_count\": validation_failure_counts[run_label],\n", + " }\n", + " )\n", + "metadata_df = pd.DataFrame(metadata_rows)\n", + "display(metadata_df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e35df038", + "metadata": {}, + "outputs": [], + "source": [ + "def records(frame: pd.DataFrame) -> list[dict[str, Any]]:\n", + " return frame.to_dict(orient=\"records\") if not frame.empty else []\n", + "\n", + "\n", + "def json_safe(value: Any) -> Any:\n", + " if isinstance(value, dict):\n", + " return {str(key): json_safe(item) for key, item in value.items()}\n", + " if isinstance(value, (list, tuple)):\n", + " return [json_safe(item) for item in value]\n", + " if isinstance(value, np.generic):\n", + " value = value.item()\n", + " if isinstance(value, float) and not np.isfinite(value):\n", + " return None\n", + " if value is pd.NA:\n", + " return None\n", + " return value\n", + "\n", + "\n", + "comparison_document = {\n", + " \"schema_version\": 1,\n", + " \"benchmark\": \"pyscf_ao_screening_rotation_comparison\",\n", + " \"generated_at\": datetime.now(UTC).isoformat(),\n", + " \"selected_run_labels\": [\n", + " str(document.get(\"run_label\") or path.stem) for path, document in DOCUMENTS\n", + " ],\n", + " \"configuration_summaries\": [\n", + " {\n", + " \"run_label\": str(document.get(\"run_label\") or path.stem),\n", + " \"configuration\": document.get(\"configuration\"),\n", + " }\n", + " for path, document in DOCUMENTS\n", + " ],\n", + " \"normalized_measurements\": records(normalized_df),\n", + " \"runtime_statistics\": records(runtime_statistics_df),\n", + " \"memory_statistics\": records(memory_statistics_df),\n", + " \"speedups_and_memory_reductions\": records(comparison_metrics_df),\n", + " \"cross_run_changes\": records(cross_run_df),\n", + " \"numerical_differences\": records(numerical_df),\n", + " \"numerical_summary\": records(numerical_summary_df),\n", + " \"orientation_sensitivity_fits\": records(orientation_fit_df),\n", + " \"validation_failures\": records(validation_df),\n", + " \"environment_metadata\": records(metadata_df),\n", + " \"source_provenance\": [\n", + " {\n", + " \"run_label\": str(document.get(\"run_label\") or path.stem),\n", + " \"source\": document.get(\"source\"),\n", + " \"runner_hashes\": document.get(\"runner_hashes\"),\n", + " }\n", + " for path, document in DOCUMENTS\n", + " ],\n", + "}\n", + "comparison_document = json_safe(comparison_document)\n", + "print(\n", + " f\"Prepared comparison JSON with \"\n", + " f\"{len(comparison_document['normalized_measurements'])} normalized rows\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b9024b3", + "metadata": {}, + "outputs": [], + "source": [ + "ARTIFACT_DIR.mkdir(parents=True, exist_ok=True)\n", + "FIGURE_DIR.mkdir(parents=True, exist_ok=True)\n", + "TABLE_DIR.mkdir(parents=True, exist_ok=True)\n", + "\n", + "with COMPARISON_JSON.open(\"w\", encoding=\"utf-8\") as stream:\n", + " json.dump(comparison_document, stream, indent=2, sort_keys=True, allow_nan=False)\n", + " stream.write(\"\\n\")\n", + "\n", + "tables = {\n", + " \"normalized-measurements.csv\": normalized_df,\n", + " \"validation-failures.csv\": validation_df,\n", + " \"status-summary.csv\": status_summary_df,\n", + " \"route-summary.csv\": route_summary_df,\n", + " \"runtime-statistics.csv\": runtime_statistics_df,\n", + " \"memory-statistics.csv\": memory_statistics_df,\n", + " \"speedups-and-memory-reductions.csv\": comparison_metrics_df,\n", + " \"cross-run-changes.csv\": cross_run_df,\n", + " \"numerical-differences.csv\": numerical_df,\n", + " \"numerical-summary.csv\": numerical_summary_df,\n", + " \"orientation-sensitivity-fits.csv\": orientation_fit_df,\n", + " \"environment-and-source-metadata.csv\": metadata_df,\n", + "}\n", + "for filename, table in tables.items():\n", + " table.to_csv(TABLE_DIR / filename, index=False)\n", + "\n", + "plot_orientation_lines(\n", + " \"runtime_seconds\",\n", + " \"Runtime (s)\",\n", + " FIGURE_DIR / \"runtime-by-orientation.png\",\n", + ")\n", + "plot_mode_distribution(\n", + " \"runtime_seconds\",\n", + " \"Runtime (s)\",\n", + " FIGURE_DIR / \"runtime-by-mode.png\",\n", + ")\n", + "plot_measurement_heatmaps(\"runtime_seconds\", \"Runtime (s)\", FIGURE_DIR)\n", + "plot_orientation_lines(\n", + " \"incremental_peak_gib\",\n", + " \"Incremental peak memory (GiB)\",\n", + " FIGURE_DIR / \"memory-by-orientation.png\",\n", + ")\n", + "plot_mode_distribution(\n", + " \"incremental_peak_gib\",\n", + " \"Incremental peak memory (GiB)\",\n", + " FIGURE_DIR / \"memory-by-mode.png\",\n", + ")\n", + "plot_measurement_heatmaps(\n", + " \"incremental_peak_gib\", \"Incremental peak memory (GiB)\", FIGURE_DIR\n", + ")\n", + "plot_ratio_heatmaps(\n", + " (\"dense_to_screened_runtime_speedup\", \"dense_to_gpu_runtime_speedup\"),\n", + " \"runtime speedup\",\n", + " FIGURE_DIR,\n", + ")\n", + "plot_ratio_heatmaps(\n", + " (\"dense_to_screened_memory_reduction\", \"dense_to_gpu_memory_reduction\"),\n", + " \"memory reduction\",\n", + " FIGURE_DIR,\n", + ")\n", + "for fingerprint in FINGERPRINT_LABELS:\n", + " plot_fingerprint_heatmaps(fingerprint, FIGURE_DIR)\n", + "\n", + "print(f\"Comparison JSON: {COMPARISON_JSON}\")\n", + "print(f\"Tables: {TABLE_DIR}\")\n", + "print(f\"Figures: {FIGURE_DIR}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/benchmarks/run_pyscf_ao_screening_benchmark.py b/benchmarks/run_pyscf_ao_screening_benchmark.py new file mode 100644 index 00000000..af2c4117 --- /dev/null +++ b/benchmarks/run_pyscf_ao_screening_benchmark.py @@ -0,0 +1,1130 @@ +"""Run isolated Skala PySCF and GPU4PySCF AO-screening benchmarks.""" + +from __future__ import annotations + +import argparse +import hashlib +import importlib.metadata +import inspect +import json +import math +import os +import platform +import re +import socket +import subprocess +import sys +import tempfile +import time +import traceback +from contextlib import AbstractContextManager, nullcontext +from dataclasses import asdict, dataclass +from datetime import UTC, datetime +from itertools import pairwise +from pathlib import Path +from typing import Any, cast +from unittest.mock import patch + +FULL_CARBON_COUNTS = (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) +EXPECTED_AO_COUNTS = ( + 294, + 411, + 528, + 645, + 762, + 879, + 996, + 1113, + 1230, + 1347, + 1464, +) +MODES = ("cpu", "cpu_dense", "gpu") +MEASUREMENTS = ("runtime", "memory") +TERMINAL_STATUSES = {"ok", "timeout", "oom", "error", "skipped_after_resource_failure"} +WORKER_RESULT_PREFIX = "SKALA_BENCHMARK_RESULT=" +THREAD_ENVIRONMENT_VARIABLES = ( + "OMP_NUM_THREADS", + "MKL_NUM_THREADS", + "OPENBLAS_NUM_THREADS", + "NUMEXPR_NUM_THREADS", +) + +Vector = tuple[float, float, float] +Atom = tuple[str, float, float, float] + +CARBON_CARBON_BOND_ANGSTROM = 1.54 +CARBON_HYDROGEN_BOND_ANGSTROM = 1.09 +CARBON_BOND_ANGLE_DEGREES = 112.0 +COORDINATE_PRECISION = 12 +GEOMETRY_PARAMETERS = { + "version": "zigzag-alkane-v1", + "carbon_carbon_bond_angstrom": CARBON_CARBON_BOND_ANGSTROM, + "carbon_hydrogen_bond_angstrom": CARBON_HYDROGEN_BOND_ANGSTROM, + "carbon_bond_angle_degrees": CARBON_BOND_ANGLE_DEGREES, + "hydrogen_dot_product": -1.0 / 3.0, + "coordinate_precision": COORDINATE_PRECISION, +} +EXPECTED_AOS_BY_CARBON: dict[int, int] = dict( + zip(FULL_CARBON_COUNTS, EXPECTED_AO_COUNTS, strict=True) +) + + +def find_repository_root(start: Path) -> Path: + for candidate in (start.resolve(), *start.resolve().parents): + if (candidate / "pyproject.toml").is_file() and ( + candidate / "LICENSE.txt" + ).is_file(): + return candidate + raise FileNotFoundError(f"Could not find the Skala repository above {start}") + + +RUNNER_ROOT = find_repository_root(Path(__file__).resolve()) +DEFAULT_SOURCE_ROOT = RUNNER_ROOT / "skala" + + +@dataclass(frozen=True) +class BenchmarkConfig: + source_root: Path + results_dir: Path + run_label: str + functional: str = "skala-1.1" + basis: str = "def2-qzvpp" + grid_level: int = 1 + grid_alignment: int = 1 + max_memory_mb: int = 2000 + cpu_threads: int = 4 + runtime_repetitions: int = 3 + worker_timeout_seconds: int = 30 * 60 + smoke_run: bool = False + + @property + def carbon_counts(self) -> tuple[int, ...]: + return FULL_CARBON_COUNTS[:1] if self.smoke_run else FULL_CARBON_COUNTS + + @property + def worker_thread_environment(self) -> dict[str, str]: + thread_count = str(self.cpu_threads) + return {name: thread_count for name in THREAD_ENVIRONMENT_VARIABLES} + + def as_json(self) -> dict[str, Any]: + data = asdict(self) + data["source_root"] = str(self.source_root) + data["results_dir"] = str(self.results_dir) + data["carbon_counts"] = list(self.carbon_counts) + data["full_carbon_counts"] = list(FULL_CARBON_COUNTS) + data["expected_ao_counts"] = list(EXPECTED_AO_COUNTS) + data["worker_thread_environment"] = self.worker_thread_environment + return data + + +def vector_add(left: Vector, right: Vector) -> Vector: + return tuple(a + b for a, b in zip(left, right, strict=True)) # type: ignore[return-value] + + +def vector_subtract(left: Vector, right: Vector) -> Vector: + return tuple(a - b for a, b in zip(left, right, strict=True)) # type: ignore[return-value] + + +def vector_scale(scale: float, vector: Vector) -> Vector: + return tuple(scale * value for value in vector) # type: ignore[return-value] + + +def vector_dot(left: Vector, right: Vector) -> float: + return sum(a * b for a, b in zip(left, right, strict=True)) + + +def vector_cross(left: Vector, right: Vector) -> Vector: + return ( + left[1] * right[2] - left[2] * right[1], + left[2] * right[0] - left[0] * right[2], + left[0] * right[1] - left[1] * right[0], + ) + + +def vector_normalize(vector: Vector) -> Vector: + norm = math.sqrt(vector_dot(vector, vector)) + if norm == 0.0: + raise ValueError("Cannot normalize a zero vector") + return vector_scale(1.0 / norm, vector) + + +def carbon_backbone(carbon_count: int) -> tuple[Vector, ...]: + if carbon_count < 2: + raise ValueError("The benchmark requires at least two carbon atoms") + half_turn = math.radians((180.0 - CARBON_BOND_ANGLE_DEGREES) / 2.0) + positions: list[Vector] = [(0.0, 0.0, 0.0)] + for bond_index in range(carbon_count - 1): + angle = half_turn if bond_index % 2 == 0 else -half_turn + direction = (math.cos(angle), math.sin(angle), 0.0) + positions.append( + vector_add( + positions[-1], vector_scale(CARBON_CARBON_BOND_ANGSTROM, direction) + ) + ) + + center = tuple( + sum(position[axis] for position in positions) / carbon_count + for axis in range(3) + ) + return tuple(vector_subtract(position, center) for position in positions) # type: ignore[arg-type] + + +def terminal_hydrogen_directions( + carbon: Vector, neighbor: Vector +) -> tuple[Vector, ...]: + neighbor_direction = vector_normalize(vector_subtract(neighbor, carbon)) + perpendicular = (0.0, 0.0, 1.0) + second_perpendicular = vector_normalize( + vector_cross(neighbor_direction, perpendicular) + ) + radial_scale = math.sqrt(8.0 / 9.0) + directions = [] + for index in range(3): + phase = 2.0 * math.pi * index / 3.0 + radial = vector_add( + vector_scale(math.cos(phase), perpendicular), + vector_scale(math.sin(phase), second_perpendicular), + ) + directions.append( + vector_add( + vector_scale(-1.0 / 3.0, neighbor_direction), + vector_scale(radial_scale, radial), + ) + ) + return tuple(directions) + + +def internal_hydrogen_directions( + carbon: Vector, previous_carbon: Vector, next_carbon: Vector +) -> tuple[Vector, Vector]: + previous_direction = vector_normalize(vector_subtract(previous_carbon, carbon)) + next_direction = vector_normalize(vector_subtract(next_carbon, carbon)) + neighbor_dot = vector_dot(previous_direction, next_direction) + in_plane_scale = (-1.0 / 3.0) / (1.0 + neighbor_dot) + in_plane = vector_scale( + in_plane_scale, vector_add(previous_direction, next_direction) + ) + normal = vector_normalize(vector_cross(previous_direction, next_direction)) + normal_scale = math.sqrt(max(0.0, 1.0 - vector_dot(in_plane, in_plane))) + return ( + vector_add(in_plane, vector_scale(normal_scale, normal)), + vector_subtract(in_plane, vector_scale(normal_scale, normal)), + ) + + +def generate_alkane_atoms(carbon_count: int) -> tuple[Atom, ...]: + carbons = carbon_backbone(carbon_count) + atoms: list[Atom] = [("C", *position) for position in carbons] + for index, carbon in enumerate(carbons): + if index == 0: + directions = terminal_hydrogen_directions(carbon, carbons[1]) + elif index == carbon_count - 1: + directions = terminal_hydrogen_directions(carbon, carbons[-2]) + else: + directions = internal_hydrogen_directions( + carbon, carbons[index - 1], carbons[index + 1] + ) + atoms.extend( + ( + "H", + *vector_add( + carbon, vector_scale(CARBON_HYDROGEN_BOND_ANGSTROM, direction) + ), + ) + for direction in directions + ) + return tuple(atoms) + + +def atoms_to_pyscf(atoms: tuple[Atom, ...]) -> str: + return "\n".join( + f"{element} {x:.{COORDINATE_PRECISION}f} " + f"{y:.{COORDINATE_PRECISION}f} {z:.{COORDINATE_PRECISION}f}" + for element, x, y, z in atoms + ) + + +@dataclass(frozen=True) +class MoleculeSpec: + carbon_count: int + expected_aos: int + formula: str + atoms: tuple[Atom, ...] + + @property + def atom_text(self) -> str: + return atoms_to_pyscf(self.atoms) + + @property + def coordinate_sha256(self) -> str: + return hashlib.sha256(self.atom_text.encode()).hexdigest() + + def as_json(self) -> dict[str, Any]: + return { + "carbon_count": self.carbon_count, + "expected_aos": self.expected_aos, + "formula": self.formula, + "atoms": [ + {"element": element, "xyz_angstrom": [x, y, z]} + for element, x, y, z in self.atoms + ], + "coordinate_sha256": self.coordinate_sha256, + } + + +def make_molecule_spec(carbon_count: int) -> MoleculeSpec: + hydrogen_count = 2 * carbon_count + 2 + return MoleculeSpec( + carbon_count=carbon_count, + expected_aos=EXPECTED_AOS_BY_CARBON[carbon_count], + formula=f"C{carbon_count}H{hydrogen_count}", + atoms=generate_alkane_atoms(carbon_count), + ) + + +FULL_MOLECULE_LADDER = tuple(make_molecule_spec(count) for count in FULL_CARBON_COUNTS) + + +def package_version(distribution: str) -> str | None: + try: + return importlib.metadata.version(distribution) + except importlib.metadata.PackageNotFoundError: + return None + + +def verify_skala_import(source_root: Path) -> str: + import skala + + imported_path = Path(skala.__file__).resolve() + expected_root = (source_root / "src").resolve() + try: + imported_path.relative_to(expected_root) + except ValueError as error: + raise RuntimeError( + f"Imported Skala from {imported_path}, expected a module below {expected_root}" + ) from error + return str(imported_path) + + +def collect_environment(payload: dict[str, Any]) -> dict[str, Any]: + import torch + + import pyscf + + source_root = Path(payload["source_root"]).resolve() + imported_skala = verify_skala_import(source_root) + cuda_available = torch.cuda.is_available() + gpu_name = torch.cuda.get_device_name(0) if cuda_available else None + cupy_version = package_version("cupy-cuda12x") or package_version("cupy") + torch_cuda_version = getattr(getattr(torch, "version", None), "cuda", None) + return { + "python": sys.version, + "python_executable": sys.executable, + "platform": platform.platform(), + "hostname": socket.gethostname(), + "processor": platform.processor(), + "logical_cpu_count": os.cpu_count(), + "source_root": str(source_root), + "imported_skala": imported_skala, + "packages": { + "skala": package_version("skala"), + "pyscf": pyscf.__version__, + "gpu4pyscf": package_version("gpu4pyscf-cuda12x") + or package_version("gpu4pyscf"), + "torch": torch.__version__, + "cupy": cupy_version, + "memray": package_version("memray"), + }, + "cuda": { + "available": cuda_available, + "torch_cuda_version": torch_cuda_version, + "device_name": gpu_name, + "device_count": torch.cuda.device_count() if cuda_available else 0, + }, + "thread_environment": { + name: os.environ.get(name) for name in THREAD_ENVIRONMENT_VARIABLES + }, + } + + +def find_route_controller(numint: Any) -> tuple[Any, Any, Any]: + candidates = (numint, getattr(numint, "integrator", None)) + control_symbols = {"_should_screen_aos", "_functional_supports_atom_chunking"} + for candidate in candidates: + if candidate is None: + continue + route_callable = inspect.unwrap(type(candidate).__call__) + referenced_names = set(route_callable.__code__.co_names) + if referenced_names & control_symbols: + route_module = inspect.getmodule(route_callable) + if route_module is None: + raise RuntimeError( + f"Cannot identify the module defining {route_callable.__qualname__}" + ) + return candidate, route_callable, route_module + raise RuntimeError("Cannot find the Skala route-selection implementation") + + +def force_dense_route(numint: Any) -> AbstractContextManager[Any]: + route_owner, route_callable, route_module = find_route_controller(numint) + referenced_names = set(route_callable.__code__.co_names) + if "_should_screen_aos" in referenced_names and hasattr( + route_module, "_should_screen_aos" + ): + return patch.object(route_module, "_should_screen_aos", return_value=False) + if "_functional_supports_atom_chunking" in referenced_names and hasattr( + type(route_owner), "_functional_supports_atom_chunking" + ): + return patch.object( + type(route_owner), + "_functional_supports_atom_chunking", + return_value=False, + ) + raise RuntimeError( + "Cannot force dense evaluation through " + f"{route_module.__name__}.{route_callable.__qualname__}" + ) + + +def route_metadata(numint: Any, mol: Any, forced_dense: bool) -> dict[str, Any]: + from pyscf.dft import numint as pyscf_numint + + route_owner, route_callable, route_module = find_route_controller(numint) + routing_source = inspect.getsource(route_callable) + routing_sha256 = hashlib.sha256(routing_source.encode()).hexdigest() + referenced_names = set(route_callable.__code__.co_names) + if "_should_screen_aos" in referenced_names and hasattr( + route_module, "_should_screen_aos" + ): + route_decision_callable = route_module._should_screen_aos + route_decision = bool(route_decision_callable(mol)) + supports_screened_evaluation = bool( + route_owner.feature_spec.supports_spatial_decomposition + ) + route_selector = "ao_threshold" + elif "_functional_supports_atom_chunking" in referenced_names and hasattr( + type(route_owner), "_functional_supports_atom_chunking" + ): + route_decision_callable = route_owner._functional_supports_atom_chunking + route_decision = bool(route_decision_callable()) + supports_screened_evaluation = route_decision + route_selector = "functional_capability" + else: + raise RuntimeError("Unrecognized Skala route-selection API") + route_decision_source = inspect.getsource(route_decision_callable) + if "_should_screen_aos" in routing_source and ( + "_global_screened_features" in routing_source + or "_integrate_screened" in routing_source + ): + implementation = "threshold_gated_global_ao_screening" + elif "chunked_features" in routing_source: + implementation = "legacy_atom_chunking" + else: + implementation = "unclassified" + + switch_size = int(pyscf_numint.SWITCH_SIZE) + if forced_dense or not supports_screened_evaluation: + selected_route = "dense" + elif implementation == "threshold_gated_global_ao_screening": + selected_route = "global_ao_screening" if route_decision else "dense" + elif implementation == "legacy_atom_chunking": + selected_route = "atom_chunking" + else: + selected_route = "unknown" + return { + "request": "forced_dense" if forced_dense else "natural", + "implementation": implementation, + "implementation_sha256": routing_sha256, + "implementation_target": ( + f"{route_module.__name__}.{route_callable.__qualname__}" + ), + "route_selector": route_selector, + "route_decision": { + "target": ( + f"{route_decision_callable.__module__}." + f"{route_decision_callable.__qualname__}" + ), + "source": route_decision_source, + "source_sha256": hashlib.sha256(route_decision_source.encode()).hexdigest(), + "result": route_decision, + }, + "functional_supports_screened_evaluation": supports_screened_evaluation, + "pyscf_switch_size": switch_size, + "selected_route": selected_route, + } + + +def build_case(payload: dict[str, Any]) -> dict[str, Any]: + import numpy as np + import torch + + from pyscf import dft, gto, lib + + source_root = Path(payload["source_root"]).resolve() + imported_skala = verify_skala_import(source_root) + thread_count = int(payload["cpu_threads"]) + lib.num_threads(thread_count) + torch.set_num_threads(thread_count) + + molecule = payload["molecule"] + mol = gto.M( + atom=molecule["atom_text"], + basis=payload["basis"], + charge=0, + spin=0, + unit="Angstrom", + cart=False, + verbose=0, + ) + initial_dm = dft.RKS(mol).get_init_guess() + backend = payload["backend"] + if backend == "cpu": + from skala.pyscf import SkalaKS as CpuSkalaKS + + ks = CpuSkalaKS(mol, xc=payload["functional"], with_dftd3=False) + dm = initial_dm + + def synchronize() -> None: + return None + + to_numpy = np.asarray + elif backend == "gpu": + if not torch.cuda.is_available(): + raise RuntimeError("CUDA is not available") + import cupy + from skala.gpu4pyscf import SkalaKS as GpuSkalaKS + + ks = GpuSkalaKS(mol, xc=payload["functional"], with_dftd3=False) + dm = cupy.asarray(initial_dm) + synchronize = torch.cuda.synchronize + to_numpy = cupy.asnumpy + else: + raise ValueError(f"Unknown backend: {backend}") + + ks.grids.level = int(payload["grid_level"]) + ks.grids.alignment = int(payload["grid_alignment"]) + ks.grids.build(sort_grids=False) + grid_weights = ks.grids.weights + if grid_weights is None: + raise RuntimeError("Grid construction did not produce weights") + numint = ks._numint + forced_dense = bool(payload["forced_dense"]) + route = route_metadata(numint, mol, forced_dense) + system = { + "formula": molecule["formula"], + "carbon_count": int(molecule["carbon_count"]), + "electron_count": int(mol.nelectron), + "actual_aos": int(mol.nao_nr()), + "grid_points": int(cast(Any, grid_weights).size), + "coordinate_sha256": molecule["coordinate_sha256"], + "imported_skala": imported_skala, + } + return { + "mol": mol, + "grids": ks.grids, + "dm": dm, + "numint": numint, + "backend": backend, + "synchronize": synchronize, + "to_numpy": to_numpy, + "route": route, + "system": system, + } + + +def fingerprint(result: tuple[Any, Any, Any], to_numpy: Any) -> dict[str, float]: + import numpy as np + + electron_integral, xc_energy, vxc = result + matrix = np.asarray(to_numpy(vxc), dtype=np.float64) + return { + "electron_integral": float(electron_integral), + "xc_energy": float(xc_energy), + "vxc_sum": float(matrix.sum()), + "vxc_trace": float(np.trace(matrix)), + "vxc_frobenius_norm": float(np.linalg.norm(matrix)), + "vxc_max_abs": float(np.max(np.abs(matrix))), + } + + +def run_measurement(payload: dict[str, Any]) -> dict[str, Any]: + import torch + + case = build_case(payload) + numint = case["numint"] + dense_route_override: AbstractContextManager[Any] + if not payload["forced_dense"]: + dense_route_override = nullcontext() + else: + dense_route_override = force_dense_route(numint) + + def evaluate() -> tuple[Any, Any, Any]: + return numint.nr_rks( + case["mol"], + case["grids"], + None, + case["dm"], + max_memory=int(payload["max_memory_mb"]), + ) + + result: tuple[Any, Any, Any] | None = None + with dense_route_override: + measurement = payload["measurement"] + if measurement == "runtime": + case["synchronize"]() + started = time.perf_counter() + result = evaluate() + case["synchronize"]() + elapsed_seconds = time.perf_counter() - started + measurement_data = {"runtime_seconds": elapsed_seconds} + elif measurement == "memory" and case["backend"] == "cpu": + import memray + + with tempfile.TemporaryDirectory() as temp_dir: + profile_path = Path(temp_dir) / "allocations.bin" + with memray.Tracker(profile_path): + result = evaluate() + peak_bytes = int(memray.FileReader(profile_path).metadata.peak_memory) + measurement_data = {"incremental_peak_bytes": peak_bytes} + elif measurement == "memory" and case["backend"] == "gpu": + case["synchronize"]() + torch.cuda.empty_cache() + case["synchronize"]() + baseline_bytes = torch.cuda.memory_allocated() + torch.cuda.reset_peak_memory_stats() + result = evaluate() + case["synchronize"]() + peak_bytes = max(0, torch.cuda.max_memory_allocated() - baseline_bytes) + measurement_data = { + "incremental_peak_bytes": int(peak_bytes), + "allocator_baseline_bytes": int(baseline_bytes), + } + else: + raise ValueError(f"Unknown measurement: {measurement}") + + assert result is not None + return { + "status": "ok", + "measurement": payload["measurement"], + "mode": payload["mode"], + "route": case["route"], + "system": case["system"], + "fingerprint": fingerprint(result, case["to_numpy"]), + **measurement_data, + } + + +def classify_exception(error: Exception) -> str: + message = f"{type(error).__name__}: {error}".lower() + if ( + isinstance(error, MemoryError) + or "out of memory" in message + or "bad alloc" in message + ): + return "oom" + return "error" + + +def emit_worker_record(record: dict[str, Any]) -> None: + print(WORKER_RESULT_PREFIX + json.dumps(record, sort_keys=True), flush=True) + + +def worker_main() -> None: + payload = json.load(sys.stdin) + try: + if payload["operation"] == "environment": + emit_worker_record( + {"status": "ok", "environment": collect_environment(payload)} + ) + elif payload["operation"] == "measure": + emit_worker_record(run_measurement(payload)) + else: + raise ValueError(f"Unknown operation: {payload['operation']}") + except Exception as error: # noqa: BLE001 - serialize worker failures for the parent + emit_worker_record( + { + "status": classify_exception(error), + "error_type": type(error).__name__, + "error": str(error), + "traceback": traceback.format_exc()[-12000:], + "measurement": payload.get("measurement"), + "mode": payload.get("mode"), + } + ) + + +def utc_now() -> str: + return datetime.now(UTC).isoformat() + + +def git_output(source_root: Path, *arguments: str) -> str: + completed = subprocess.run( + ["git", "-C", str(source_root), *arguments], + check=True, + capture_output=True, + text=True, + ) + return completed.stdout.strip() + + +def source_metadata(source_root: Path) -> dict[str, Any]: + return { + "root": str(source_root), + "commit": git_output(source_root, "rev-parse", "HEAD"), + "branch": git_output(source_root, "branch", "--show-current") or None, + "dirty": bool(git_output(source_root, "status", "--porcelain")), + } + + +def runner_sha256() -> str: + return hashlib.sha256(Path(__file__).read_bytes()).hexdigest() + + +def worker_environment(config: BenchmarkConfig) -> dict[str, str]: + environment = os.environ.copy() + source_python_path = str(config.source_root / "src") + existing_python_path = environment.get("PYTHONPATH") + python_paths = [source_python_path, str(RUNNER_ROOT)] + if existing_python_path: + python_paths.append(existing_python_path) + environment["PYTHONPATH"] = os.pathsep.join(python_paths) + environment.update(config.worker_thread_environment) + return environment + + +def execute_worker(payload: dict[str, Any], config: BenchmarkConfig) -> dict[str, Any]: + try: + completed = subprocess.run( + [sys.executable, str(Path(__file__).resolve()), "--worker"], + input=json.dumps(payload), + cwd=config.source_root, + env=worker_environment(config), + capture_output=True, + text=True, + timeout=config.worker_timeout_seconds, + check=False, + ) + except subprocess.TimeoutExpired as error: + return { + "status": "timeout", + "measurement": payload.get("measurement"), + "mode": payload.get("mode"), + "error": f"Worker exceeded {config.worker_timeout_seconds} seconds", + "stdout_tail": (error.stdout or "")[-4000:], + "stderr_tail": (error.stderr or "")[-4000:], + } + + marker_lines = [ + line.removeprefix(WORKER_RESULT_PREFIX) + for line in completed.stdout.splitlines() + if line.startswith(WORKER_RESULT_PREFIX) + ] + if marker_lines: + record = json.loads(marker_lines[-1]) + if record["status"] != "ok": + record["stderr_tail"] = completed.stderr[-4000:] + return record + + combined_output = f"{completed.stdout}\n{completed.stderr}".lower() + status = ( + "oom" + if completed.returncode in {-9, 137} or "out of memory" in combined_output + else "error" + ) + return { + "status": status, + "measurement": payload.get("measurement"), + "mode": payload.get("mode"), + "error": f"Worker exited with code {completed.returncode} without a result record", + "stdout_tail": completed.stdout[-4000:], + "stderr_tail": completed.stderr[-4000:], + } + + +def execute_measurement( + payload: dict[str, Any], config: BenchmarkConfig +) -> dict[str, Any]: + if payload["measurement"] != "runtime": + return execute_worker(payload, config) + + runtime_samples: list[float] = [] + first_result: dict[str, Any] | None = None + for sample_index in range(config.runtime_repetitions): + result = execute_worker(payload, config) + if result["status"] != "ok": + result["runtime_samples_seconds"] = runtime_samples + result["failed_runtime_sample_index"] = sample_index + return result + if first_result is None: + first_result = result + else: + for key in ("route", "system"): + if result.get(key) != first_result.get(key): + raise ValueError( + f"Runtime worker {key} changed between isolated samples" + ) + runtime_samples.append(float(result["runtime_seconds"])) + + assert first_result is not None + first_result.pop("runtime_seconds") + first_result["runtime_samples_seconds"] = runtime_samples + return first_result + + +def atomic_write_json(path: Path, document: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + temporary_path: Path | None = None + try: + with tempfile.NamedTemporaryFile( + "w", + encoding="utf-8", + dir=path.parent, + prefix=f".{path.name}.", + delete=False, + ) as stream: + json.dump(document, stream, indent=2, sort_keys=True, allow_nan=False) + stream.write("\n") + stream.flush() + os.fsync(stream.fileno()) + temporary_path = Path(stream.name) + temporary_path.replace(path) + finally: + if temporary_path is not None and temporary_path.exists(): + temporary_path.unlink() + + +def worker_payload( + config: BenchmarkConfig, + molecule: MoleculeSpec, + mode: str, + measurement: str, +) -> dict[str, Any]: + backend = "gpu" if mode.startswith("gpu") else "cpu" + return { + "operation": "measure", + "source_root": str(config.source_root), + "functional": config.functional, + "basis": config.basis, + "grid_level": config.grid_level, + "grid_alignment": config.grid_alignment, + "max_memory_mb": config.max_memory_mb, + "cpu_threads": config.cpu_threads, + "backend": backend, + "forced_dense": mode.endswith("_dense"), + "mode": mode, + "measurement": measurement, + "molecule": { + "carbon_count": molecule.carbon_count, + "formula": molecule.formula, + "atom_text": molecule.atom_text, + "coordinate_sha256": molecule.coordinate_sha256, + }, + } + + +def new_result_document( + config: BenchmarkConfig, + molecules: tuple[MoleculeSpec, ...], + source: dict[str, Any], + environment: dict[str, Any], +) -> dict[str, Any]: + created_at = utc_now() + return { + "schema_version": 1, + "created_at": created_at, + "updated_at": created_at, + "run_label": config.run_label, + "source": source, + "environment": environment, + "configuration": config.as_json(), + "geometry": GEOMETRY_PARAMETERS, + "worker_sha256": runner_sha256(), + "molecules": { + molecule.formula: { + **molecule.as_json(), + "observed": None, + "modes": {mode: {} for mode in MODES}, + } + for molecule in molecules + }, + } + + +def validate_resume_document( + document: dict[str, Any], config: BenchmarkConfig, source: dict[str, Any] +) -> None: + if document.get("schema_version") != 1: + raise ValueError("Cannot resume a result file with a different schema version") + if document.get("worker_sha256") != runner_sha256(): + raise ValueError( + "Cannot resume results created by a different runner implementation" + ) + if document.get("source", {}).get("commit") != source["commit"]: + raise ValueError("Cannot resume results from a different Git commit") + if document.get("configuration") != config.as_json(): + raise ValueError( + "Cannot resume results created with a different benchmark configuration" + ) + + +def merge_worker_result( + molecule_record: dict[str, Any], mode: str, measurement: str, result: dict[str, Any] +) -> None: + result = dict(result) + system = result.pop("system", None) + route = result.pop("route", None) + if system is not None: + observed = molecule_record.get("observed") + if observed is not None and observed != system: + raise ValueError( + f"Worker system metadata changed for {molecule_record['formula']}" + ) + molecule_record["observed"] = system + mode_record = molecule_record["modes"][mode] + if route is not None: + existing_route = mode_record.get("route") + if existing_route is not None and existing_route != route: + raise ValueError( + f"Worker route metadata changed for {molecule_record['formula']} {mode}" + ) + mode_record["route"] = route + if measurement == "runtime" and "runtime_seconds" in result: + result["runtime_samples_seconds"] = [result.pop("runtime_seconds")] + mode_record[measurement] = result + + +def result_path(config: BenchmarkConfig, source: dict[str, Any]) -> Path: + safe_label = re.sub(r"[^A-Za-z0-9_.-]+", "-", config.run_label).strip("-.") + if not safe_label: + raise ValueError("The run label must contain a filename-safe character") + return ( + config.results_dir + / f"skala-pyscf-ao-screening-{safe_label}-{source['commit'][:12]}.json" + ) + + +def run_worker_preflight(config: BenchmarkConfig) -> dict[str, Any]: + result = execute_worker( + {"operation": "environment", "source_root": str(config.source_root)}, config + ) + if result["status"] != "ok": + raise RuntimeError(f"Benchmark preflight failed: {result}") + environment = result["environment"] + imported_path = Path(environment["imported_skala"]) + imported_path.relative_to(config.source_root / "src") + required_packages = ("skala", "pyscf", "torch", "memray") + missing = [ + name for name in required_packages if not environment["packages"].get(name) + ] + if missing: + raise RuntimeError(f"Worker environment is missing packages: {missing}") + return environment + + +def atom_distance(left: Atom, right: Atom) -> float: + return math.dist(left[1:], right[1:]) + + +def validate_molecule_ladder(config: BenchmarkConfig) -> None: + from pyscf import gto + + assert len(FULL_MOLECULE_LADDER) == len(FULL_CARBON_COUNTS) + assert len( + {molecule.coordinate_sha256 for molecule in FULL_MOLECULE_LADDER} + ) == len(FULL_CARBON_COUNTS) + for molecule, expected_aos in zip( + FULL_MOLECULE_LADDER, EXPECTED_AO_COUNTS, strict=True + ): + carbon_count = molecule.carbon_count + hydrogen_count = 2 * carbon_count + 2 + assert molecule.formula == f"C{carbon_count}H{hydrogen_count}" + assert len(molecule.atoms) == carbon_count + hydrogen_count + assert molecule.atoms == generate_alkane_atoms(carbon_count) + + carbons = molecule.atoms[:carbon_count] + hydrogens = molecule.atoms[carbon_count:] + for left, right in pairwise(carbons): + assert math.isclose( + atom_distance(left, right), + CARBON_CARBON_BOND_ANGSTROM, + abs_tol=1e-12, + ) + for hydrogen in hydrogens: + nearest_carbon = min(atom_distance(hydrogen, carbon) for carbon in carbons) + assert math.isclose( + nearest_carbon, + CARBON_HYDROGEN_BOND_ANGSTROM, + abs_tol=1e-12, + ) + + mol = gto.M( + atom=molecule.atom_text, + basis=config.basis, + charge=0, + spin=0, + unit="Angstrom", + cart=False, + verbose=0, + ) + assert mol.nao_nr() == expected_aos == molecule.expected_aos + assert mol.nelectron % 2 == 0 + + +def run_benchmark( + config: BenchmarkConfig, + molecules: tuple[MoleculeSpec, ...], + environment: dict[str, Any], +) -> Path: + source = source_metadata(config.source_root) + output_path = result_path(config, source) + if output_path.exists(): + document = json.loads(output_path.read_text(encoding="utf-8")) + validate_resume_document(document, config, source) + else: + document = new_result_document(config, molecules, source, environment) + atomic_write_json(output_path, document) + + cuda_available = bool(document["environment"]["cuda"]["available"]) + for mode in MODES: + backend = "gpu" if mode.startswith("gpu") else "cpu" + for measurement in MEASUREMENTS: + blocked_by: dict[str, Any] | None = None + for molecule in molecules: + molecule_record = document["molecules"][molecule.formula] + existing = molecule_record["modes"][mode].get(measurement) + if existing and existing.get("status") in TERMINAL_STATUSES: + if existing["status"] in {"oom", "timeout"}: + blocked_by = { + "formula": molecule.formula, + "status": existing["status"], + } + continue + + result: dict[str, Any] + if backend == "gpu" and not cuda_available: + result = { + "status": "error", + "mode": mode, + "measurement": measurement, + "error": "CUDA is not available in the worker environment", + } + elif blocked_by is not None: + result = { + "status": "skipped_after_resource_failure", + "mode": mode, + "measurement": measurement, + "blocked_by": blocked_by, + } + else: + result = execute_measurement( + worker_payload(config, molecule, mode, measurement), config + ) + + merge_worker_result(molecule_record, mode, measurement, result) + document["updated_at"] = utc_now() + atomic_write_json(output_path, document) + if result["status"] in {"oom", "timeout"}: + blocked_by = { + "formula": molecule.formula, + "status": result["status"], + } + print( + f"{mode:9s} {measurement:7s} {molecule.formula:8s} " + f"{result['status']}" + ) + return output_path + + +def parse_arguments(argv: list[str]) -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Benchmark one Skala XC/Vxc evaluation on CPU and GPU.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + parser.add_argument( + "--label", + required=True, + help="Result label, normally the revision name such as 'mr' or 'main'.", + ) + parser.add_argument( + "--source-root", + type=Path, + default=DEFAULT_SOURCE_ROOT, + help="Skala checkout whose src/skala package is benchmarked.", + ) + parser.add_argument( + "--results-dir", + type=Path, + default=RUNNER_ROOT / "benchmarks" / "results", + help="Directory for commit-labelled JSON output.", + ) + parser.add_argument("--functional", default="skala-1.1") + parser.add_argument("--basis", default="def2-qzvpp") + parser.add_argument("--grid-level", type=int, default=1) + parser.add_argument("--max-memory-mb", type=int, default=2000) + parser.add_argument("--threads", type=int, default=4) + parser.add_argument("--runtime-repetitions", type=int, default=3) + parser.add_argument("--timeout-minutes", type=float, default=30.0) + parser.add_argument( + "--smoke", + action="store_true", + help="Run only C2H6 instead of the full 11-molecule ladder.", + ) + parser.add_argument( + "--preflight-only", + action="store_true", + help="Validate geometry, dependencies, source import, and CUDA without measurements.", + ) + return parser.parse_args(argv) + + +def config_from_arguments(arguments: argparse.Namespace) -> BenchmarkConfig: + if arguments.timeout_minutes <= 0: + raise ValueError("--timeout-minutes must be positive") + if arguments.threads <= 0: + raise ValueError("--threads must be positive") + if arguments.runtime_repetitions <= 0: + raise ValueError("--runtime-repetitions must be positive") + source_root = arguments.source_root.expanduser().resolve() + if not (source_root / "src" / "skala").is_dir(): + raise FileNotFoundError(f"No src/skala package below {source_root}") + return BenchmarkConfig( + source_root=source_root, + results_dir=arguments.results_dir.expanduser().resolve(), + run_label=arguments.label, + functional=arguments.functional, + basis=arguments.basis, + grid_level=arguments.grid_level, + max_memory_mb=arguments.max_memory_mb, + cpu_threads=arguments.threads, + runtime_repetitions=arguments.runtime_repetitions, + worker_timeout_seconds=round(arguments.timeout_minutes * 60), + smoke_run=arguments.smoke, + ) + + +def main(argv: list[str] | None = None) -> int: + arguments = parse_arguments(sys.argv[1:] if argv is None else argv) + config = config_from_arguments(arguments) + validate_molecule_ladder(config) + environment = run_worker_preflight(config) + print("Benchmark configuration:") + print(json.dumps(config.as_json(), indent=2, sort_keys=True)) + print(f"Skala import: {environment['imported_skala']}") + print(f"Python: {environment['python_executable']}") + print(f"CUDA: {environment['cuda']}") + if arguments.preflight_only: + print("Preflight passed.") + return 0 + + molecules = FULL_MOLECULE_LADDER[:1] if config.smoke_run else FULL_MOLECULE_LADDER + output_path = run_benchmark(config, molecules, environment) + print(f"Results written to {output_path}") + return 0 + + +if __name__ == "__main__": + if sys.argv[1:] == ["--worker"]: + worker_main() + else: + raise SystemExit(main()) diff --git a/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py b/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py new file mode 100644 index 00000000..463ade53 --- /dev/null +++ b/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py @@ -0,0 +1,409 @@ +"""Benchmark AO screening across rotations of one approximately 900-AO molecule. + +The default grid applies ``Rz(azimuth) @ Ry(polar)`` to C7H16 (879 AOs with +def2-qzvpp). Azimuth runs from 0 through 330 degrees and polar angle runs from +0 through 150 degrees, both in 30-degree steps, for 72 orientations per mode. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import math +import re +import sys +from dataclasses import asdict, dataclass +from pathlib import Path +from typing import Any + +import run_pyscf_ao_screening_benchmark as benchmark + +MODES = ("gpu", "cpu_dense", "cpu_screened") +MEASUREMENTS = ("runtime", "memory") +BASE_MOLECULE = benchmark.make_molecule_spec(7) + + +@dataclass(frozen=True) +class Orientation: + azimuth_degrees: int + polar_degrees: int + + @property + def key(self) -> str: + return f"azimuth_{self.azimuth_degrees:03d}_polar_{self.polar_degrees:03d}" + + def as_json(self) -> dict[str, int]: + return { + "azimuth_degrees": self.azimuth_degrees, + "polar_degrees": self.polar_degrees, + } + + +@dataclass(frozen=True) +class RotationBenchmarkConfig(benchmark.BenchmarkConfig): + azimuth_step_degrees: int = 30 + polar_step_degrees: int = 30 + + @property + def azimuth_angles(self) -> tuple[int, ...]: + return tuple(range(0, 360, self.azimuth_step_degrees)) + + @property + def polar_angles(self) -> tuple[int, ...]: + return tuple(range(0, 180, self.polar_step_degrees)) + + @property + def full_orientations(self) -> tuple[Orientation, ...]: + return tuple( + Orientation(azimuth, polar) + for azimuth in self.azimuth_angles + for polar in self.polar_angles + ) + + @property + def orientations(self) -> tuple[Orientation, ...]: + orientations = self.full_orientations + return orientations[:1] if self.smoke_run else orientations + + def as_json(self) -> dict[str, Any]: + data = asdict(self) + data["source_root"] = str(self.source_root) + data["results_dir"] = str(self.results_dir) + data["azimuth_angles_degrees"] = list(self.azimuth_angles) + data["polar_angles_degrees"] = list(self.polar_angles) + data["orientation_count"] = len(self.orientations) + data["full_orientation_count"] = len(self.full_orientations) + data["modes"] = list(MODES) + data["measurements"] = list(MEASUREMENTS) + data["worker_thread_environment"] = self.worker_thread_environment + return data + + +def rotate_atoms( + atoms: tuple[benchmark.Atom, ...], orientation: Orientation +) -> tuple[benchmark.Atom, ...]: + azimuth = math.radians(orientation.azimuth_degrees) + polar = math.radians(orientation.polar_degrees) + cos_azimuth = math.cos(azimuth) + sin_azimuth = math.sin(azimuth) + cos_polar = math.cos(polar) + sin_polar = math.sin(polar) + + rotated: list[benchmark.Atom] = [] + for element, x, y, z in atoms: + polar_x = cos_polar * x + sin_polar * z + polar_z = -sin_polar * x + cos_polar * z + rotated.append( + ( + element, + cos_azimuth * polar_x - sin_azimuth * y, + sin_azimuth * polar_x + cos_azimuth * y, + polar_z, + ) + ) + return tuple(rotated) + + +def rotated_molecule(orientation: Orientation) -> benchmark.MoleculeSpec: + return benchmark.MoleculeSpec( + carbon_count=BASE_MOLECULE.carbon_count, + expected_aos=BASE_MOLECULE.expected_aos, + formula=BASE_MOLECULE.formula, + atoms=rotate_atoms(BASE_MOLECULE.atoms, orientation), + ) + + +def runner_hashes() -> dict[str, str]: + return { + "rotation_runner_sha256": hashlib.sha256( + Path(__file__).read_bytes() + ).hexdigest(), + "worker_sha256": benchmark.runner_sha256(), + } + + +def validate_rotation_grid(config: RotationBenchmarkConfig) -> None: + from pyscf import gto + + molecules = tuple(rotated_molecule(item) for item in config.full_orientations) + coordinate_hashes = {molecule.coordinate_sha256 for molecule in molecules} + if len(coordinate_hashes) != len(molecules): + raise ValueError("The rotation grid produced duplicate coordinate sets") + + for molecule in molecules: + for original, rotated in zip(BASE_MOLECULE.atoms, molecule.atoms, strict=True): + if original[0] != rotated[0] or not math.isclose( + math.dist((0.0, 0.0, 0.0), original[1:]), + math.dist((0.0, 0.0, 0.0), rotated[1:]), + abs_tol=1e-12, + ): + raise ValueError("A rotation changed the molecular geometry") + + mol = gto.M( + atom=BASE_MOLECULE.atom_text, + basis=config.basis, + charge=0, + spin=0, + unit="Angstrom", + cart=False, + verbose=0, + ) + actual_aos = int(mol.nao_nr()) + if actual_aos != BASE_MOLECULE.expected_aos: + raise ValueError( + f"Expected {BASE_MOLECULE.expected_aos} AOs for {BASE_MOLECULE.formula} " + f"with {config.basis}, got {actual_aos}" + ) + + +def run_worker_preflight(config: RotationBenchmarkConfig) -> dict[str, Any]: + result = benchmark.execute_worker( + {"operation": "environment", "source_root": str(config.source_root)}, config + ) + if result["status"] != "ok": + raise RuntimeError(f"Benchmark preflight failed: {result}") + environment = result["environment"] + imported_path = Path(environment["imported_skala"]) + imported_path.relative_to(config.source_root / "src") + required_packages = ("skala", "pyscf", "torch", "memray") + missing = [ + name for name in required_packages if not environment["packages"].get(name) + ] + if missing: + raise RuntimeError(f"Worker environment is missing packages: {missing}") + return environment + + +def result_path(config: RotationBenchmarkConfig, source: dict[str, Any]) -> Path: + safe_label = re.sub(r"[^A-Za-z0-9_.-]+", "-", config.run_label).strip("-.") + if not safe_label: + raise ValueError("The run label must contain a filename-safe character") + return ( + config.results_dir + / f"skala-pyscf-ao-screening-rotations-{safe_label}-{source['commit'][:12]}.json" + ) + + +def new_result_document( + config: RotationBenchmarkConfig, + source: dict[str, Any], + environment: dict[str, Any], +) -> dict[str, Any]: + created_at = benchmark.utc_now() + return { + "schema_version": 1, + "benchmark": "pyscf_ao_screening_rotations", + "created_at": created_at, + "updated_at": created_at, + "run_label": config.run_label, + "source": source, + "environment": environment, + "configuration": config.as_json(), + "geometry": { + **benchmark.GEOMETRY_PARAMETERS, + "base_molecule": BASE_MOLECULE.as_json(), + "rotation_convention": "active Cartesian rotation Rz(azimuth) @ Ry(polar)", + }, + "runner_hashes": runner_hashes(), + "orientations": { + orientation.key: { + "index": index, + **orientation.as_json(), + "coordinate_sha256": rotated_molecule(orientation).coordinate_sha256, + "observed": None, + "modes": {mode: {} for mode in MODES}, + } + for index, orientation in enumerate(config.orientations) + }, + } + + +def validate_resume_document( + document: dict[str, Any], + config: RotationBenchmarkConfig, + source: dict[str, Any], +) -> None: + if document.get("schema_version") != 1: + raise ValueError("Cannot resume a result file with a different schema version") + if document.get("runner_hashes") != runner_hashes(): + raise ValueError( + "Cannot resume results created by different runner implementations" + ) + if document.get("source", {}).get("commit") != source["commit"]: + raise ValueError("Cannot resume results from a different Git commit") + if document.get("configuration") != config.as_json(): + raise ValueError( + "Cannot resume results created with a different benchmark configuration" + ) + + +def run_benchmark(config: RotationBenchmarkConfig, environment: dict[str, Any]) -> Path: + source = benchmark.source_metadata(config.source_root) + output_path = result_path(config, source) + if output_path.exists(): + document = json.loads(output_path.read_text(encoding="utf-8")) + validate_resume_document(document, config, source) + else: + document = new_result_document(config, source, environment) + benchmark.atomic_write_json(output_path, document) + + cuda_available = bool(document["environment"]["cuda"]["available"]) + for mode in MODES: + for measurement in MEASUREMENTS: + blocked_by: dict[str, Any] | None = None + for orientation in config.orientations: + orientation_record = document["orientations"][orientation.key] + existing = orientation_record["modes"][mode].get(measurement) + if existing and existing.get("status") in benchmark.TERMINAL_STATUSES: + if existing["status"] in {"oom", "timeout"}: + blocked_by = { + "orientation": orientation.key, + "status": existing["status"], + } + continue + + result: dict[str, Any] + if mode == "gpu" and not cuda_available: + result = { + "status": "error", + "mode": mode, + "measurement": measurement, + "error": "CUDA is not available in the worker environment", + } + elif blocked_by is not None: + result = { + "status": "skipped_after_resource_failure", + "mode": mode, + "measurement": measurement, + "blocked_by": blocked_by, + } + else: + molecule = rotated_molecule(orientation) + payload = benchmark.worker_payload( + config, molecule, mode, measurement + ) + payload["orientation"] = orientation.as_json() + result = benchmark.execute_measurement(payload, config) + + benchmark.merge_worker_result( + orientation_record, mode, measurement, result + ) + document["updated_at"] = benchmark.utc_now() + benchmark.atomic_write_json(output_path, document) + if result["status"] in {"oom", "timeout"}: + blocked_by = { + "orientation": orientation.key, + "status": result["status"], + } + print( + f"{mode:12s} {measurement:7s} {orientation.key} {result['status']}" + ) + return output_path + + +def parse_arguments(argv: list[str]) -> argparse.Namespace: + parser = argparse.ArgumentParser( + description=( + "Benchmark Skala XC/Vxc evaluation for 72 rotations of one 879-AO " + "molecule on GPU, dense CPU, and screened CPU." + ), + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + parser.add_argument( + "--label", + required=True, + help="Result label, normally the revision name such as 'mr' or 'main'.", + ) + parser.add_argument( + "--source-root", + type=Path, + default=benchmark.DEFAULT_SOURCE_ROOT, + help="Skala checkout whose src/skala package is benchmarked.", + ) + parser.add_argument( + "--results-dir", + type=Path, + default=benchmark.RUNNER_ROOT / "benchmarks" / "results", + help="Directory for commit-labelled JSON output.", + ) + parser.add_argument("--functional", default="skala-1.1") + parser.add_argument("--basis", default="def2-qzvpp") + parser.add_argument("--grid-level", type=int, default=1) + parser.add_argument("--max-memory-mb", type=int, default=2000) + parser.add_argument("--threads", type=int, default=4) + parser.add_argument("--runtime-repetitions", type=int, default=3) + parser.add_argument("--timeout-minutes", type=float, default=30.0) + parser.add_argument("--azimuth-step-degrees", type=int, default=30) + parser.add_argument("--polar-step-degrees", type=int, default=30) + parser.add_argument( + "--smoke", + action="store_true", + help="Run only the unrotated orientation for each mode.", + ) + parser.add_argument( + "--preflight-only", + action="store_true", + help="Validate rotations, dependencies, source import, and CUDA without measurements.", + ) + return parser.parse_args(argv) + + +def config_from_arguments( + arguments: argparse.Namespace, +) -> RotationBenchmarkConfig: + if arguments.timeout_minutes <= 0: + raise ValueError("--timeout-minutes must be positive") + if arguments.threads <= 0: + raise ValueError("--threads must be positive") + if arguments.runtime_repetitions <= 0: + raise ValueError("--runtime-repetitions must be positive") + if arguments.azimuth_step_degrees <= 0 or 360 % arguments.azimuth_step_degrees: + raise ValueError("--azimuth-step-degrees must be a positive divisor of 360") + if arguments.polar_step_degrees <= 0 or 180 % arguments.polar_step_degrees: + raise ValueError("--polar-step-degrees must be a positive divisor of 180") + source_root = arguments.source_root.expanduser().resolve() + if not (source_root / "src" / "skala").is_dir(): + raise FileNotFoundError(f"No src/skala package below {source_root}") + return RotationBenchmarkConfig( + source_root=source_root, + results_dir=arguments.results_dir.expanduser().resolve(), + run_label=arguments.label, + functional=arguments.functional, + basis=arguments.basis, + grid_level=arguments.grid_level, + max_memory_mb=arguments.max_memory_mb, + cpu_threads=arguments.threads, + runtime_repetitions=arguments.runtime_repetitions, + worker_timeout_seconds=round(arguments.timeout_minutes * 60), + smoke_run=arguments.smoke, + azimuth_step_degrees=arguments.azimuth_step_degrees, + polar_step_degrees=arguments.polar_step_degrees, + ) + + +def main(argv: list[str] | None = None) -> int: + arguments = parse_arguments(sys.argv[1:] if argv is None else argv) + config = config_from_arguments(arguments) + validate_rotation_grid(config) + environment = run_worker_preflight(config) + print("Benchmark configuration:") + print(json.dumps(config.as_json(), indent=2, sort_keys=True)) + print( + f"Molecule: {BASE_MOLECULE.formula}, " + f"{BASE_MOLECULE.expected_aos} AOs with {config.basis}" + ) + print(f"Skala import: {environment['imported_skala']}") + print(f"Python: {environment['python_executable']}") + print(f"CUDA: {environment['cuda']}") + if arguments.preflight_only: + print("Preflight passed.") + return 0 + + output_path = run_benchmark(config, environment) + print(f"Results written to {output_path}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/benchmarks/vxc_accuracy_grid_grouping.ipynb b/benchmarks/vxc_accuracy_grid_grouping.ipynb new file mode 100644 index 00000000..bf9c8485 --- /dev/null +++ b/benchmarks/vxc_accuracy_grid_grouping.ipynb @@ -0,0 +1,703 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "201eea25", + "metadata": {}, + "source": [ + "# GPU $V_{xc}$ accuracy versus grid grouping\n", + "\n", + "This notebook uses the carbon-chain/def2-QZVPP stress case from `test_gpu_screened_skala_matches_cpu_on_carbon_chain` to isolate how grouping grid points into GPU4PySCF screening blocks affects Skala's integrated $V_{xc}$.\n", + "\n", + "Grid levels 1 and 2 are evaluated independently, each against a dense CPU calculation on the identical grid and density matrix. Every screened candidate executes GPU4PySCF's real CUDA mask construction and AO evaluation with its installed $10^{-10}$ AO threshold and 4096-point block size." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ce0ae4d", + "metadata": {}, + "outputs": [], + "source": [ + "from dataclasses import dataclass\n", + "from typing import Any\n", + "from unittest.mock import patch\n", + "\n", + "import cupy\n", + "import numpy as np\n", + "import torch\n", + "from pyscf import dft, gto\n", + "from tests.utils import patch_ao_screening\n", + "\n", + "from skala.functional import load_functional\n", + "from skala.functional.base import ExcFunctionalBase\n", + "from skala.pyscf import features as features_module\n", + "from skala.pyscf.backend import dft_gpu\n", + "from skala.pyscf.features import _spatial_grid_permutations\n", + "from skala.pyscf.numint import SkalaNumInt\n", + "\n", + "np.set_printoptions(precision=4, suppress=True)\n", + "\n", + "\n", + "@dataclass(frozen=True)\n", + "class Evaluation:\n", + " electron_count: float\n", + " xc_energy: float\n", + " vxc: np.ndarray\n", + " active_ao_counts: np.ndarray\n", + "\n", + "\n", + "@dataclass(frozen=True)\n", + "class GridExperiment:\n", + " level: int\n", + " coords: np.ndarrays\n", + " dense_reference: Evaluation\n", + " groupings: dict[str, list[np.ndarray]]\n", + " rows: list[dict[str, object]]\n", + "\n", + "\n", + "CARBON_CHAIN = \"\"\"\n", + "C 0.0 0.0 0.0\n", + "C 1.4 0.0 0.0\n", + "C 2.8 0.0 0.0\n", + "C 4.2 0.0 0.0\n", + "C 5.6 0.0 0.0\n", + "C 7.0 0.0 0.0\n", + "\"\"\"\n", + "GRID_LEVELS = (1, 2)\n", + "\n", + "assert torch.cuda.is_available()\n", + "assert dft_gpu is not None\n", + "mol = gto.M(atom=CARBON_CHAIN, basis=\"def2-qzvpp\", verbose=0)\n", + "dm = dft.RKS(mol).get_init_guess()\n", + "\n", + "cpu_functional = load_functional(\"skala-1.1\", device=torch.device(\"cpu\"))\n", + "gpu_functional = load_functional(\"skala-1.1\", device=torch.device(\"cuda:0\"))\n", + "assert isinstance(cpu_functional, ExcFunctionalBase)\n", + "assert isinstance(gpu_functional, ExcFunctionalBase)\n", + "cpu_numint = SkalaNumInt(cpu_functional, device=torch.device(\"cpu\"))\n", + "gpu_numint = SkalaNumInt(gpu_functional, device=torch.device(\"cuda:0\"))\n", + "GPU_BLOCK_SIZE = int(dft_gpu.numint.MIN_BLK_SIZE)\n", + "\n", + "print(f\"Atoms / AOs / shells: {mol.natm} / {mol.nao_nr()} / {mol.nbas}\")\n", + "print(f\"Grid levels: {GRID_LEVELS}\")\n", + "print(f\"GPU4PySCF AO threshold: {dft_gpu.numint.AO_THRESHOLD:.1e}\")\n", + "print(f\"GPU screening block size: {GPU_BLOCK_SIZE}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c5410a08", + "metadata": {}, + "source": [ + "## Screening permutations\n", + "\n", + "Each algorithm partitions the complete grid required by that setting: level 1 has 31,080 points in 8 physical GPU groups, while level 2 has 67,248 points in 17 groups. Every group contains at most 4096 points.\n", + "\n", + "The atom-major case preserves PySCF's original grid order and divides the complete sequence into consecutive blocks. The production spatial case recursively partitions the complete coordinate set, choosing split directions from the spatial extent. The mixed cases exchange points between complete spatial groups while preserving every group size and leaving the final partial group intact. In every case, each grid point appears exactly once.\n", + "\n", + "Even spatially grouped 4096-point blocks can overlap many functions in a diffuse def2-QZVPP basis. `Active AO fraction` reports the grid-point-weighted fraction of AOs retained by the actual masks. `DM matmul proxy` weights the squared fraction, matching the leading $n_{\\mathrm{active}}^2 n_{\\mathrm{grid}}$ scaling of Skala's density-feature matrix multiplications; neither column is a measured runtime." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa8cb8c1", + "metadata": {}, + "outputs": [], + "source": [ + "def validate_partition(groups: list[np.ndarray], point_count: int) -> None:\n", + " if not groups or any(group.size == 0 for group in groups):\n", + " raise ValueError(\"Groups must be non-empty.\")\n", + " flattened = np.concatenate(groups)\n", + " if flattened.size != point_count or not np.array_equal(\n", + " np.sort(flattened), np.arange(point_count, dtype=np.int64)\n", + " ):\n", + " raise ValueError(\"Groups must partition every grid point exactly once.\")\n", + "\n", + "\n", + "def groups_from_permutation(\n", + " permutation: np.ndarray, block_size: int\n", + ") -> list[np.ndarray]:\n", + " groups = [\n", + " permutation[start : start + block_size].copy()\n", + " for start in range(0, permutation.size, block_size)\n", + " ]\n", + " validate_partition(groups, permutation.size)\n", + " return groups\n", + "\n", + "\n", + "def mix_spatial_groups(\n", + " groups: list[np.ndarray], mixing_fraction: float, point_count: int\n", + ") -> list[np.ndarray]:\n", + " if not 0 <= mixing_fraction <= 1:\n", + " raise ValueError(\"mixing_fraction must be between zero and one.\")\n", + "\n", + " complete = [group for group in groups if group.size == GPU_BLOCK_SIZE]\n", + " remainders = [group.copy() for group in groups if group.size != GPU_BLOCK_SIZE]\n", + " if mixing_fraction == 0 or len(complete) < 2:\n", + " return [group.copy() for group in groups]\n", + "\n", + " source = np.stack(complete)\n", + " mixed = source.copy()\n", + " mixed_columns = round(mixing_fraction * GPU_BLOCK_SIZE)\n", + " columns = np.floor(\n", + " np.arange(mixed_columns) * GPU_BLOCK_SIZE / mixed_columns\n", + " ).astype(np.int64)\n", + " for column_index, column in enumerate(columns):\n", + " shift = 1 + column_index % (source.shape[0] - 1)\n", + " mixed[:, column] = np.roll(source[:, column], shift)\n", + "\n", + " result = [row.copy() for row in mixed] + remainders\n", + " validate_partition(result, point_count)\n", + " return result\n", + "\n", + "\n", + "def build_matching_grids(level: int) -> tuple[Any, Any, np.ndarray]:\n", + " cpu_grids = dft.Grids(mol)\n", + " cpu_grids.level = level\n", + " cpu_grids.alignment = 1\n", + " cpu_grids.build(sort_grids=False)\n", + " assert cpu_grids.coords is not None and cpu_grids.weights is not None\n", + "\n", + " gpu_grids = dft_gpu.Grids(mol)\n", + " gpu_grids.level = level\n", + " gpu_grids.alignment = 1\n", + " gpu_grids.build(sort_grids=False)\n", + "\n", + " coords = np.asarray(cpu_grids.coords)\n", + " np.testing.assert_allclose(\n", + " coords, cupy.asnumpy(gpu_grids.coords), rtol=0.0, atol=0.0\n", + " )\n", + " np.testing.assert_allclose(\n", + " cpu_grids.weights,\n", + " cupy.asnumpy(gpu_grids.weights),\n", + " rtol=1e-12,\n", + " atol=1e-12,\n", + " )\n", + " return cpu_grids, gpu_grids, coords\n", + "\n", + "\n", + "def dense_cpu_reference(cpu_grids: Any) -> Evaluation:\n", + " with patch_ao_screening(False):\n", + " electron_count, xc_energy, vxc = cpu_numint.nr_rks(mol, cpu_grids, None, dm)\n", + " return Evaluation(\n", + " electron_count=float(electron_count),\n", + " xc_energy=float(xc_energy),\n", + " vxc=np.asarray(vxc),\n", + " active_ao_counts=np.asarray([mol.nao_nr()], dtype=np.int64),\n", + " )\n", + "\n", + "\n", + "def fresh_gpu_grids(template: Any) -> Any:\n", + " case_grids = dft_gpu.Grids(mol)\n", + " case_grids.level = template.level\n", + " case_grids.alignment = template.alignment\n", + " case_grids.coords = template.coords\n", + " case_grids.weights = template.weights\n", + " case_grids._non0ao_idx = None\n", + " return case_grids\n", + "\n", + "\n", + "def evaluate_gpu_permutation(\n", + " permutation: np.ndarray, gpu_grid_template: Any, point_count: int\n", + ") -> Evaluation:\n", + " inverse = np.empty_like(permutation)\n", + " inverse[permutation] = np.arange(point_count, dtype=np.int64)\n", + " case_grids = fresh_gpu_grids(gpu_grid_template)\n", + " with (\n", + " patch.object(\n", + " features_module,\n", + " \"_spatial_grid_permutations\",\n", + " return_value=(permutation, inverse),\n", + " ),\n", + " patch_ao_screening(True),\n", + " ):\n", + " electron_count, xc_energy, vxc = gpu_numint.nr_rks(\n", + " mol, case_grids, None, cupy.asarray(dm)\n", + " )\n", + "\n", + " prepared_grids, cached_forward, _ = features_module._prepare_spatially_sorted_grids(\n", + " mol, case_grids, GPU_BLOCK_SIZE, gpu=True\n", + " )\n", + " assert np.array_equal(cached_forward, permutation)\n", + " active_ao_counts = np.asarray(\n", + " [entry[1].size for entry in prepared_grids.get_non0ao_idx()],\n", + " dtype=np.int64,\n", + " )\n", + " return Evaluation(\n", + " electron_count=float(electron_count),\n", + " xc_energy=float(xc_energy),\n", + " vxc=cupy.asnumpy(vxc),\n", + " active_ao_counts=active_ao_counts,\n", + " )\n", + "\n", + "\n", + "def vxc_errors(\n", + " candidate: np.ndarray, dense_reference: Evaluation\n", + ") -> tuple[float, float]:\n", + " difference = candidate - dense_reference.vxc\n", + " return (\n", + " float(np.max(np.abs(difference))),\n", + " float(np.linalg.norm(difference) / np.linalg.norm(dense_reference.vxc)),\n", + " )\n", + "\n", + "\n", + "def normalized_within_group_radius(\n", + " groups: list[np.ndarray], coords: np.ndarray\n", + ") -> float:\n", + " global_center = coords.mean(axis=0)\n", + " global_rms = np.sqrt(np.mean(np.sum(np.square(coords - global_center), axis=1)))\n", + " within_sum = 0.0\n", + " for group in groups:\n", + " group_coords = coords[group]\n", + " center = group_coords.mean(axis=0)\n", + " within_sum += float(np.sum(np.square(group_coords - center)))\n", + " return float(np.sqrt(within_sum / coords.shape[0]) / global_rms)\n", + "\n", + "\n", + "def mean_maximum_bbox_iou(groups: list[np.ndarray], coords: np.ndarray) -> float:\n", + " if len(groups) == 1:\n", + " return 0.0\n", + " minimums = np.asarray([coords[group].min(axis=0) for group in groups])\n", + " maximums = np.asarray([coords[group].max(axis=0) for group in groups])\n", + " volumes = np.prod(np.maximum(maximums - minimums, 0.0), axis=1)\n", + " maximum_ious = []\n", + " for index in range(len(groups)):\n", + " intersection_extent = np.maximum(\n", + " np.minimum(maximums[index], maximums)\n", + " - np.maximum(minimums[index], minimums),\n", + " 0.0,\n", + " )\n", + " intersection = np.prod(intersection_extent, axis=1)\n", + " union = volumes[index] + volumes - intersection\n", + " iou = np.divide(\n", + " intersection,\n", + " union,\n", + " out=np.zeros_like(intersection),\n", + " where=union > 0,\n", + " )\n", + " iou[index] = 0.0\n", + " maximum_ious.append(float(iou.max()))\n", + " return float(np.mean(maximum_ious))\n", + "\n", + "\n", + "def summarize_case(\n", + " level: int,\n", + " name: str,\n", + " groups: list[np.ndarray],\n", + " evaluation: Evaluation,\n", + " coords: np.ndarray,\n", + " dense_reference: Evaluation,\n", + ") -> dict[str, object]:\n", + " point_count = coords.shape[0]\n", + " validate_partition(groups, point_count)\n", + " sizes = np.asarray([group.size for group in groups], dtype=np.int64)\n", + " active_aos = evaluation.active_ao_counts\n", + " assert sizes.size == active_aos.size\n", + " maximum_error, relative_error = vxc_errors(evaluation.vxc, dense_reference)\n", + " return {\n", + " \"level\": level,\n", + " \"grid_points\": point_count,\n", + " \"case\": name,\n", + " \"groups\": len(groups),\n", + " \"occupancy\": f\"{sizes.min()}/{np.median(sizes):.0f}/{sizes.max()}\",\n", + " \"active_aos\": f\"{active_aos.min()}/{np.median(active_aos):.0f}/{active_aos.max()}\",\n", + " \"radius\": normalized_within_group_radius(groups, coords),\n", + " \"bbox_iou\": mean_maximum_bbox_iou(groups, coords),\n", + " \"active_ao_fraction\": float(\n", + " np.sum(sizes * active_aos) / (point_count * mol.nao_nr())\n", + " ),\n", + " \"dm_matmul_proxy\": float(\n", + " np.sum(sizes * np.square(active_aos)) / (point_count * mol.nao_nr() ** 2)\n", + " ),\n", + " \"max_vxc_error\": maximum_error,\n", + " \"relative_vxc_error\": relative_error,\n", + " \"electron_error\": abs(\n", + " evaluation.electron_count - dense_reference.electron_count\n", + " ),\n", + " \"energy_error\": abs(evaluation.xc_energy - dense_reference.xc_energy),\n", + " }\n", + "\n", + "\n", + "def build_groupings(coords: np.ndarray) -> dict[str, list[np.ndarray]]:\n", + " point_count = coords.shape[0]\n", + " atom_major = groups_from_permutation(\n", + " np.arange(point_count, dtype=np.int64), GPU_BLOCK_SIZE\n", + " )\n", + " spatial_forward, _ = _spatial_grid_permutations(coords, GPU_BLOCK_SIZE)\n", + " spatial = groups_from_permutation(spatial_forward, GPU_BLOCK_SIZE)\n", + " return {\n", + " \"GPU4PySCF atom-major blocks\": atom_major,\n", + " \"GPU4PySCF spatial blocks\": spatial,\n", + " \"GPU4PySCF spatial, mix 0.500\": mix_spatial_groups(spatial, 0.5, point_count),\n", + " \"GPU4PySCF spatial, mix 1.000\": mix_spatial_groups(spatial, 1.0, point_count),\n", + " }\n", + "\n", + "\n", + "def run_grid_level(level: int) -> GridExperiment:\n", + " cpu_grids, gpu_grid_template, coords = build_matching_grids(level)\n", + " point_count = coords.shape[0]\n", + " dense_reference = dense_cpu_reference(cpu_grids)\n", + " groupings = build_groupings(coords)\n", + " all_points = [np.arange(point_count, dtype=np.int64)]\n", + " case_data = [(\"Dense CPU reference\", all_points, dense_reference)]\n", + "\n", + " print(f\"Level {level}: {point_count:,} points\")\n", + " for name, groups in groupings.items():\n", + " print(f\" Evaluating {name}...\")\n", + " evaluation = evaluate_gpu_permutation(\n", + " np.concatenate(groups), gpu_grid_template, point_count\n", + " )\n", + " assert np.isfinite(evaluation.electron_count)\n", + " assert np.isfinite(evaluation.xc_energy)\n", + " assert np.isfinite(evaluation.vxc).all()\n", + " assert np.allclose(evaluation.vxc, evaluation.vxc.T, rtol=1e-10, atol=1e-11)\n", + " case_data.append((name, groups, evaluation))\n", + "\n", + " rows = [\n", + " summarize_case(level, name, groups, evaluation, coords, dense_reference)\n", + " for name, groups, evaluation in case_data\n", + " ]\n", + " atom_major_error = rows[1][\"max_vxc_error\"]\n", + " spatial_error = rows[2][\"max_vxc_error\"]\n", + " assert isinstance(atom_major_error, float)\n", + " assert isinstance(spatial_error, float)\n", + " print(\n", + " \" Spatial grouping changes max |dVxc| by \"\n", + " f\"{atom_major_error / spatial_error:.2f}x.\"\n", + " )\n", + " return GridExperiment(level, coords, dense_reference, groupings, rows)\n", + "\n", + "\n", + "def render_results(rows: list[dict[str, object]]) -> str:\n", + " columns = (\n", + " (\"level\", \"Grid level\"),\n", + " (\"grid_points\", \"Grid points\"),\n", + " (\"case\", \"Case\"),\n", + " (\"groups\", \"Groups\"),\n", + " (\"occupancy\", \"Points min/med/max\"),\n", + " (\"active_aos\", \"Active AOs min/med/max\"),\n", + " (\"radius\", \"RMS radius\"),\n", + " (\"bbox_iou\", \"BBox IoU\"),\n", + " (\"active_ao_fraction\", \"Active AO fraction\"),\n", + " (\"dm_matmul_proxy\", \"DM matmul proxy\"),\n", + " (\"max_vxc_error\", \"max |dVxc|\"),\n", + " (\"relative_vxc_error\", \"rel. Frobenius\"),\n", + " (\"electron_error\", \"|dN|\"),\n", + " (\"energy_error\", \"|dExc|\"),\n", + " )\n", + " parts = [\n", + " '',\n", + " \"\",\n", + " ]\n", + " parts.extend(\n", + " f''\n", + " for _, label in columns\n", + " )\n", + " parts.append(\"\")\n", + " for row in rows:\n", + " parts.append(\"\")\n", + " for key, _ in columns:\n", + " value = row[key]\n", + " text = f\"{value:.3e}\" if isinstance(value, float) else str(value)\n", + " parts.append(\n", + " f''\n", + " )\n", + " parts.append(\"\")\n", + " parts.append(\"
{label}
{text}
\")\n", + " return \"\".join(parts)\n", + "\n", + "\n", + "class HTMLTable(str):\n", + " def _repr_html_(self) -> str:\n", + " return str(self)" + ] + }, + { + "cell_type": "markdown", + "id": "9aa97ac5", + "metadata": {}, + "source": [ + "## Results\n", + "\n", + "Each grid level has its own dense CPU reference and independently constructed grouping permutations. All screened rows use actual GPU4PySCF masks. Lower active-AO metrics mean more aggressive screening; lower error means closer agreement with that level's dense reference." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ab116d3", + "metadata": {}, + "outputs": [], + "source": [ + "experiments = [run_grid_level(level) for level in GRID_LEVELS]\n", + "results = [row for experiment in experiments for row in experiment.rows]\n", + "\n", + "HTMLTable(render_results(results))" + ] + }, + { + "cell_type": "markdown", + "id": "4e6acd97", + "metadata": {}, + "source": [ + "## Fixed grid-group slices\n", + "\n", + "For each grid level, the figure shows three fixed slabs centered at $z=-1$, $0$, and $+1$ bohr relative to the molecular $x$-$y$ plane. Each slab includes points satisfying $|z-z_0|\\leq 0.25$ bohr. The outermost 1% of each grid, ranked by three-dimensional distance to the nearest carbon nucleus, is omitted to keep the molecular region legible.\n", + "\n", + "The selected points are accumulated in shared $x$-$y$ bins. Each occupied bin takes the color of its most frequent screening group; the color is blended toward white according to that group's fraction of points in the bin. Pure color means complete local agreement, while a pale bin contains a stronger mixture of groups. Black crosses mark the carbon nuclei." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e47fa055", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from matplotlib.colors import BoundaryNorm, ListedColormap\n", + "\n", + "\n", + "def group_labels(groups: list[np.ndarray], point_count: int) -> np.ndarray:\n", + " labels = np.empty(point_count, dtype=np.int64)\n", + " for group_index, group in enumerate(groups):\n", + " labels[group] = group_index\n", + " return labels\n", + "\n", + "\n", + "def dominant_group_image(\n", + " coords: np.ndarray,\n", + " labels: np.ndarray,\n", + " selected: np.ndarray,\n", + " x_edges: np.ndarray,\n", + " y_edges: np.ndarray,\n", + " group_colors: np.ndarray,\n", + ") -> np.ndarray:\n", + " x_bin_count = x_edges.size - 1\n", + " y_bin_count = y_edges.size - 1\n", + " selected_coords = coords[selected]\n", + " x_bins = np.searchsorted(x_edges, selected_coords[:, 0], side=\"right\") - 1\n", + " y_bins = np.searchsorted(y_edges, selected_coords[:, 1], side=\"right\") - 1\n", + " x_bins = np.clip(x_bins, 0, x_bin_count - 1)\n", + " y_bins = np.clip(y_bins, 0, y_bin_count - 1)\n", + " flat_bins = y_bins * x_bin_count + x_bins\n", + " combined = labels[selected] * (x_bin_count * y_bin_count) + flat_bins\n", + " counts = np.bincount(\n", + " combined,\n", + " minlength=group_colors.shape[0] * x_bin_count * y_bin_count,\n", + " ).reshape(group_colors.shape[0], y_bin_count, x_bin_count)\n", + " assert int(counts.sum()) == int(selected.sum())\n", + "\n", + " totals = counts.sum(axis=0)\n", + " dominant_groups = counts.argmax(axis=0)\n", + " dominant_counts = counts.max(axis=0)\n", + " populated = totals > 0\n", + " dominant_fraction = np.divide(\n", + " dominant_counts,\n", + " totals,\n", + " out=np.zeros_like(dominant_counts, dtype=float),\n", + " where=populated,\n", + " )\n", + "\n", + " image = np.ones((*totals.shape, 4), dtype=float)\n", + " dominant_colors = group_colors[dominant_groups]\n", + " image[populated, :3] = 1.0 - dominant_fraction[populated, None] * (\n", + " 1.0 - dominant_colors[populated]\n", + " )\n", + " return image\n", + "\n", + "\n", + "def rgb_to_lab(rgb: np.ndarray) -> np.ndarray:\n", + " linear = np.where(\n", + " rgb <= 0.04045,\n", + " rgb / 12.92,\n", + " ((rgb + 0.055) / 1.055) ** 2.4,\n", + " )\n", + " transform = np.asarray(\n", + " [\n", + " [0.4124564, 0.3575761, 0.1804375],\n", + " [0.2126729, 0.7151522, 0.0721750],\n", + " [0.0193339, 0.1191920, 0.9503041],\n", + " ]\n", + " )\n", + " xyz = linear @ transform.T\n", + " xyz /= np.asarray([0.95047, 1.0, 1.08883])\n", + " delta = 6 / 29\n", + " transformed = np.where(\n", + " xyz > delta**3,\n", + " np.cbrt(xyz),\n", + " xyz / (3 * delta**2) + 4 / 29,\n", + " )\n", + " return np.column_stack(\n", + " (\n", + " 116 * transformed[:, 1] - 16,\n", + " 500 * (transformed[:, 0] - transformed[:, 1]),\n", + " 200 * (transformed[:, 1] - transformed[:, 2]),\n", + " )\n", + " )\n", + "\n", + "\n", + "def distinct_group_colors(count: int) -> np.ndarray:\n", + " levels = np.linspace(0.0, 1.0, 11)\n", + " candidates = np.stack(\n", + " np.meshgrid(levels, levels, levels, indexing=\"ij\"), axis=-1\n", + " ).reshape(-1, 3)\n", + " candidate_lab = rgb_to_lab(candidates)\n", + " chroma = np.linalg.norm(candidate_lab[:, 1:], axis=1)\n", + " keep = (candidate_lab[:, 0] >= 35) & (candidate_lab[:, 0] <= 75) & (chroma >= 35)\n", + " candidates = candidates[keep]\n", + " candidate_lab = candidate_lab[keep]\n", + "\n", + " seed = np.argmin(np.linalg.norm(candidates - np.asarray([0.0, 0.3, 0.8]), axis=1))\n", + " selected = [int(seed)]\n", + " minimum_distance = np.linalg.norm(candidate_lab - candidate_lab[seed], axis=1)\n", + " for _ in range(1, count):\n", + " index = int(np.argmax(minimum_distance))\n", + " selected.append(index)\n", + " distance = np.linalg.norm(candidate_lab - candidate_lab[index], axis=1)\n", + " minimum_distance = np.minimum(minimum_distance, distance)\n", + " return candidates[selected]\n", + "\n", + "\n", + "atom_coords = mol.atom_coords()\n", + "slice_centers = (-1.0, 0.0, 1.0)\n", + "slice_half_width = 0.25\n", + "retained_by_level = {}\n", + "for experiment in experiments:\n", + " nearest_atom_distance = np.linalg.norm(\n", + " experiment.coords[:, None, :] - atom_coords[None, :, :], axis=2\n", + " ).min(axis=1)\n", + " removed_count = round(0.01 * experiment.coords.shape[0])\n", + " retained = np.ones(experiment.coords.shape[0], dtype=bool)\n", + " outside_order = np.argsort(nearest_atom_distance, kind=\"stable\")\n", + " retained[outside_order[-removed_count:]] = False\n", + " assert retained.sum() == experiment.coords.shape[0] - removed_count\n", + " retained_by_level[experiment.level] = retained\n", + "\n", + "trimmed_xy = np.concatenate(\n", + " [\n", + " experiment.coords[retained_by_level[experiment.level], :2]\n", + " for experiment in experiments\n", + " ]\n", + ")\n", + "x_min, y_min = trimmed_xy.min(axis=0)\n", + "x_max, y_max = trimmed_xy.max(axis=0)\n", + "x_bin_count = 120\n", + "bin_width = (x_max - x_min) / x_bin_count\n", + "y_bin_count = max(1, int(np.ceil((y_max - y_min) / bin_width)))\n", + "y_center = 0.5 * (y_min + y_max)\n", + "x_edges = np.linspace(x_min, x_max, x_bin_count + 1)\n", + "y_edges = np.linspace(\n", + " y_center - 0.5 * y_bin_count * bin_width,\n", + " y_center + 0.5 * y_bin_count * bin_width,\n", + " y_bin_count + 1,\n", + ")\n", + "\n", + "for experiment in experiments:\n", + " coords = experiment.coords\n", + " retained = retained_by_level[experiment.level]\n", + " group_count = max(len(groups) for groups in experiment.groupings.values())\n", + " group_colors = distinct_group_colors(group_count)\n", + " palette = ListedColormap(group_colors)\n", + " norm = BoundaryNorm(np.arange(group_count + 1) - 0.5, palette.N)\n", + " labels_by_name = {\n", + " name: group_labels(groups, coords.shape[0])\n", + " for name, groups in experiment.groupings.items()\n", + " }\n", + "\n", + " figure, axes = plt.subplots(\n", + " len(labels_by_name),\n", + " len(slice_centers),\n", + " figsize=(15, 13),\n", + " sharex=True,\n", + " sharey=True,\n", + " constrained_layout=True,\n", + " squeeze=False,\n", + " )\n", + " for row_index, (name, labels) in enumerate(labels_by_name.items()):\n", + " for column_index, height in enumerate(slice_centers):\n", + " axis = axes[row_index, column_index]\n", + " selected = retained & (np.abs(coords[:, 2] - height) <= slice_half_width)\n", + " image = dominant_group_image(\n", + " coords,\n", + " labels,\n", + " selected,\n", + " x_edges,\n", + " y_edges,\n", + " group_colors,\n", + " )\n", + " axis.imshow(\n", + " image,\n", + " origin=\"lower\",\n", + " extent=(x_edges[0], x_edges[-1], y_edges[0], y_edges[-1]),\n", + " interpolation=\"nearest\",\n", + " aspect=\"equal\",\n", + " )\n", + " axis.scatter(\n", + " atom_coords[:, 0],\n", + " atom_coords[:, 1],\n", + " marker=\"x\",\n", + " c=\"black\",\n", + " s=24,\n", + " linewidths=1.0,\n", + " zorder=3,\n", + " )\n", + " axis.text(\n", + " 0.98,\n", + " 0.96,\n", + " f\"{selected.sum():,} points\",\n", + " ha=\"right\",\n", + " va=\"top\",\n", + " transform=axis.transAxes,\n", + " fontsize=8,\n", + " )\n", + " if row_index == 0:\n", + " axis.set_title(\n", + " f\"z = {height:+.1f} +/- {slice_half_width:.2f} bohr\",\n", + " fontsize=10,\n", + " )\n", + " if column_index == 0:\n", + " axis.set_ylabel(f\"{name}\\ny (bohr)\", fontsize=9)\n", + " if row_index == len(labels_by_name) - 1:\n", + " axis.set_xlabel(\"x (bohr)\")\n", + "\n", + " colorbar = figure.colorbar(\n", + " plt.cm.ScalarMappable(norm=norm, cmap=palette),\n", + " ax=axes,\n", + " ticks=np.arange(group_count),\n", + " shrink=0.82,\n", + " pad=0.02,\n", + " )\n", + " colorbar.ax.set_yticklabels(np.arange(1, group_count + 1))\n", + " colorbar.set_label(\"Dominant screening group\")\n", + " figure.suptitle(\n", + " f\"Level {experiment.level}: dominant GPU screening groups \"\n", + " f\"({coords.shape[0]:,} grid points)\"\n", + " )\n", + " plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pixi.lock b/pixi.lock index 99135867..afbd63ab 100644 --- a/pixi.lock +++ b/pixi.lock @@ -145,7 +145,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -323,7 +323,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -501,7 +501,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -709,7 +709,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda @@ -782,7 +782,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda @@ -969,7 +969,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-16.2.0-he9431aa_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-16.2.0-he9431aa_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-16.2.0-hc864f27_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgoogle-cloud-3.8.0-h2efc11c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgoogle-cloud-storage-3.8.0-h66d5b86_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgrpc-1.82.1-h05b84e8_0.conda @@ -1031,7 +1031,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyarrow-25.0.0-py312h8025657_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyarrow-core-25.0.0-py312h2cce741_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.12.14-h94ad73b_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-librt-0.15.0-py312h085bef5_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-librt-0.15.0-py312h085bef5_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pytorch-2.13.0-cpu_generic_py312_h556be23_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py312ha4530ae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/qhull-2020.2-h70be974_5.conda @@ -1287,7 +1287,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-16.2.0-h3cf6597_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-16.2.0-h07b0088_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-16.2.0-hdb7a957_4.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h89cd0c0_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h81decf1_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-3.8.0-ha595bda_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-storage-3.8.0-hc8aed40_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgrpc-1.82.1-hf3e839d_0.conda @@ -1346,7 +1346,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-25.0.0-py312h1f38498_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-core-25.0.0-py312h7d9569a_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.14-hd05a0c4_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-librt-0.15.0-py312h7ac3c4f_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-librt-0.15.0-py312h7ac3c4f_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pytorch-2.13.0-cpu_generic_py312_ha1580ae_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.3-py312h04c11ed_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/qhull-2020.2-h420ef59_5.conda @@ -1457,7 +1457,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda @@ -1534,7 +1534,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlalchemy-2.0.52-py312h5253ce2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2023.0.0-hab88423_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h1df4ec4_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py312h4c3975b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py312h5cc1888_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-h280c20c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-h0d788c3_1.conda @@ -2061,6 +2061,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-12.9.79-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-12.9.86-h4bc722e_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h2d75abc_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -2070,6 +2071,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hb7133d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hf-xet-1.5.2-py310hb823017_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda @@ -2080,6 +2082,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-25.0.0-hcc2f0d9_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-25.0.0-h635bf11_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-compute-25.0.0-h53684a4_4_cpu.conda @@ -2114,17 +2117,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-ha7672b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -2143,10 +2148,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.12.1-cuda129_mkl_h6b8258c_300.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda @@ -2158,13 +2166,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h4d09622_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onednn-3.12-omp_h83de36e_0.conda @@ -2172,12 +2183,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.3.1-h443056b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.5-py312h8ecdadd_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda @@ -2242,7 +2255,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -2251,6 +2266,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum-3.4.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum_fx-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.6-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -2266,15 +2282,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - pypi: ./benchmark - pypi: ./model - pypi: ./skala @@ -2332,6 +2351,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-12.9.79-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-12.9.86-h4bc722e_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h2d75abc_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -2341,6 +2361,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hb7133d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hf-xet-1.5.2-py310hb823017_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda @@ -2351,6 +2372,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-25.0.0-hcc2f0d9_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-25.0.0-h635bf11_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-compute-25.0.0-h53684a4_4_cpu.conda @@ -2385,17 +2407,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-ha7672b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -2414,10 +2438,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda129_mkl_h546cc0b_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda @@ -2429,13 +2456,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h4d09622_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onednn-3.12-omp_h83de36e_0.conda @@ -2443,12 +2473,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.3.1-h443056b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.5-py312h8ecdadd_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda @@ -2513,7 +2545,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -2522,6 +2556,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum-3.4.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum_fx-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.6-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -2537,15 +2572,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - pypi: ./benchmark - pypi: ./model - pypi: ./skala @@ -2603,6 +2641,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-13.3.29-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-13.3.73-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h15eaa2f_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -2612,6 +2651,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hb7133d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hf-xet-1.5.2-py310hb823017_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda @@ -2622,6 +2662,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-25.0.0-hcc2f0d9_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-25.0.0-h635bf11_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-compute-25.0.0-h53684a4_4_cpu.conda @@ -2656,17 +2697,19 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-hd93470c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -2685,10 +2728,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda130_mkl_h1ca3d63_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda @@ -2700,13 +2746,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h1aa9b5a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onednn-3.12-omp_h83de36e_0.conda @@ -2714,12 +2763,14 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.3.1-h443056b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.5-py312h8ecdadd_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda @@ -2784,7 +2835,9 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -2793,6 +2846,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum-3.4.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum_fx-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.6-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -2808,15 +2862,18 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - pypi: ./benchmark - pypi: ./model - pypi: ./skala @@ -2909,7 +2966,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda @@ -2982,7 +3039,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda @@ -3247,7 +3304,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -3310,7 +3367,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cuda129_mkl_py312_h0509a7e_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-gpu-2.13.0-cuda129_mkl_h0d04637_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda @@ -3543,7 +3600,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -3606,7 +3663,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cuda130_mkl_py312_hcdc9d04_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-gpu-2.13.0-cuda129_mkl_h0d04637_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda @@ -3845,7 +3902,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -3909,7 +3966,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cuda130_mkl_py312_hcdc9d04_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-gpu-2.13.0-cuda129_mkl_h0d04637_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda @@ -4133,7 +4190,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-64.0-h192683f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda @@ -4293,7 +4350,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-64.0-h192683f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda @@ -4453,7 +4510,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-64.0-h192683f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda @@ -4613,7 +4670,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pkg-config-0.29.2-hfbd14cd_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/psutil-7.2.2-py312h898233f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.12.14-h94ad73b_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-librt-0.15.0-py312h085bef5_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-librt-0.15.0-py312h085bef5_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pytorch-2.13.0-cpu_generic_py312_h556be23_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rdma-core-64.0-h1f0f388_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-ha7194a6_1.conda @@ -4830,7 +4887,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pkg-config-0.29.2-he0b766d_1012.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.2.2-py312hbd136b4_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.14-hd05a0c4_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-librt-0.15.0-py312h7ac3c4f_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-librt-0.15.0-py312h7ac3c4f_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pytorch-2.13.0-cpu_generic_py312_ha1580ae_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h8b90a29_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.6-h84a0fba_2.conda @@ -4958,7 +5015,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-64.0-h192683f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda @@ -5133,7 +5190,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-64.0-h192683f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda @@ -5308,7 +5365,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-64.0-h192683f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda @@ -5469,7 +5526,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -5524,7 +5581,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda @@ -5689,7 +5746,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -5744,7 +5801,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda @@ -5909,7 +5966,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda @@ -5964,7 +6021,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda @@ -6212,7 +6269,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda @@ -6412,7 +6469,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda @@ -6645,7 +6702,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-16.2.0-he9431aa_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-16.2.0-he9431aa_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-16.2.0-hc864f27_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgoogle-cloud-3.8.0-h2efc11c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgoogle-cloud-storage-3.8.0-h66d5b86_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgrpc-1.82.1-h05b84e8_0.conda @@ -6922,7 +6979,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-16.2.0-h3cf6597_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-16.2.0-h07b0088_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-16.2.0-hdb7a957_4.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h89cd0c0_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h81decf1_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-3.8.0-ha595bda_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-storage-3.8.0-hc8aed40_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgrpc-1.82.1-hf3e839d_0.conda @@ -7081,7 +7138,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda @@ -7314,7 +7371,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-16.2.0-he9431aa_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-16.2.0-he9431aa_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-16.2.0-hc864f27_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgoogle-cloud-3.8.0-h2efc11c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgoogle-cloud-storage-3.8.0-h66d5b86_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgrpc-1.82.1-h05b84e8_0.conda @@ -7591,7 +7648,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-16.2.0-h3cf6597_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-16.2.0-h07b0088_4.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-16.2.0-hdb7a957_4.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h89cd0c0_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h81decf1_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-3.8.0-ha595bda_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-storage-3.8.0-hc8aed40_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgrpc-1.82.1-hf3e839d_0.conda @@ -7714,7 +7771,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda @@ -11448,16 +11505,16 @@ packages: run_exports: {} size: 2526008 timestamp: 1787618692926 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_2.conda - sha256: af6c14f387f810c5df491b328ae955329596d3bc73b1e2e091ab5adb46a10759 - md5: 533d342dedadf134c67760ce6fc5b748 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda + sha256: f57bf3954dbba8b27ec68540e84f8b2c2375ffa5702f89ca9741e17329fc3953 + md5: d216efacca3f34f2b13ddd1632f53833 depends: - - __glibc >=2.17,<3.0.a0 - libgcc >=15 - - pcre2 >=10.47,<10.48.0a0 - - libzlib >=1.3.2,<2.0a0 + - __glibc >=2.17,<3.0.a0 - libiconv >=1.18,<2.0a0 + - pcre2 >=10.47,<10.48.0a0 - libffi >=3.7.0,<3.8.0a0 + - libzlib >=1.3.2,<2.0a0 constrains: - glib >2.66 license: LGPL-2.1-or-later @@ -11465,8 +11522,8 @@ packages: run_exports: weak: - libglib >=2.88.3,<3.0a0 - size: 4758097 - timestamp: 1787884091247 + size: 4758346 + timestamp: 1788525203514 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda sha256: 0fe5cb8e0752241ab55e11656ed1b9726248b522d23b929fe7c95b83eb55b9bb md5: 89d2c1231f47bd818f5d624b9411459d @@ -13724,21 +13781,20 @@ packages: size: 24369771 timestamp: 1788387840141 python_site_packages_path: lib/python3.13/site-packages -- conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_1.conda - sha256: dc4176b0715a6226663551add60bb4216d2c3e5faafcaf1ac917e9803fa4f7d1 - md5: 37726df0a5491ed021e08006699162e3 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda + sha256: 93eefb027858ef06d03e21560b704a4dd9f0a6e4fadeb332c601c16ff5bc54e8 + md5: e4b266d7f7ae5cce6071f51de9d13588 depends: - python - libgcc >=15 - __glibc >=2.17,<3.0.a0 - python_abi 3.12.* *_cp312 license: MIT - license_family: MIT purls: - pkg:pypi/librt?source=compressed-mapping run_exports: {} - size: 169369 - timestamp: 1788228288554 + size: 169277 + timestamp: 1788524688833 - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.12.1-cpu_mkl_py312_h38523ed_100.conda sha256: 827e69c59252e91a4f15a9b7892d075a73cb4263cbf0faa38f995c6447a267d5 md5: ebe0e6778530b8073f04ccdae79d6e94 @@ -14506,12 +14562,12 @@ packages: - tk >=8.6.13,<8.7.0a0 size: 3566806 timestamp: 1787272857910 -- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py312h4c3975b_0.conda - sha256: 2ea8f8b10e869b675d2fba157b387eaf4eed1696bfc924bb7b28e67d7aa0a947 - md5: 5423c2b8f82d60320e65b9ff30babbdf +- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py312h5cc1888_1.conda + sha256: 3480bf39c540d3dfa737ce5df1e14c74fef161ccb2a19485cb211a654921fa68 + md5: e15caa7ad9be633c3cba5a7937b117b7 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=14 + - libgcc >=15 - python >=3.12,<3.13.0a0 - python_abi 3.12.* *_cp312 license: Apache-2.0 @@ -14519,8 +14575,8 @@ packages: purls: - pkg:pypi/tornado?source=compressed-mapping run_exports: {} - size: 869730 - timestamp: 1786226754702 + size: 868900 + timestamp: 1788524841516 - conda: https://conda.anaconda.org/conda-forge/linux-64/triton-3.7.1-cuda129py312h811769c_1.conda sha256: f6057dfe20a473f0b1ab7e1a231ebce774ba934a3c54176efb58bf1133aaa44b md5: b32d0cc6a3091264c0b61db49ecc8718 @@ -16436,15 +16492,15 @@ packages: run_exports: {} size: 1489572 timestamp: 1787617767130 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_2.conda - sha256: 1a1f854a38a4a0247a0193f220f0aa4f16ce964eed91963be4d0e63ca9e029d4 - md5: de44cb5a4ccf6eccf34811b95a1f247b +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.88.3-hb514e8e_3.conda + sha256: 90ffb44655cc8ab1d4566ae77be09f887760d859c24358ee926edd56cbdc2e42 + md5: 18837ca7480048a942c7404a36883b08 depends: - libgcc >=15 - - libiconv >=1.18,<2.0a0 - - pcre2 >=10.47,<10.48.0a0 - libzlib >=1.3.2,<2.0a0 - libffi >=3.7.0,<3.8.0a0 + - libiconv >=1.18,<2.0a0 + - pcre2 >=10.47,<10.48.0a0 constrains: - glib >2.66 license: LGPL-2.1-or-later @@ -16452,8 +16508,8 @@ packages: run_exports: weak: - libglib >=2.88.3,<3.0a0 - size: 4830545 - timestamp: 1788398417264 + size: 4830492 + timestamp: 1788525192222 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-16.2.0-h8acb6b2_4.conda sha256: 6d216e6dc9a158b920f6e0c1dfdd6d77575bf79420dadf85d64576298ecb4503 md5: 727c19b26cd43140e4a90a6f8f1cc31a @@ -17764,21 +17820,20 @@ packages: - python size: 22418400 timestamp: 1788392934327 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-librt-0.15.0-py312h085bef5_1.conda - sha256: 8be7607be3d299fd3978f4814bc7414bd220606e2d4a984896a0611bb1e28bce - md5: b258f86969c21b76687c0a01e7dc755d +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-librt-0.15.0-py312h085bef5_2.conda + sha256: 5a2af2a40f3e86f1e89559cf1f9eef23f97b7241172fb774afc265d1a6fd4cf4 + md5: 7a1184f162fed7074bc8eae7c7ec2eba depends: - python - - python 3.12.* *_cpython - libgcc >=15 + - python 3.12.* *_cpython - python_abi 3.12.* *_cp312 license: MIT - license_family: MIT purls: - - pkg:pypi/librt?source=compressed-mapping + - pkg:pypi/librt?source=hash-mapping run_exports: {} - size: 171890 - timestamp: 1788228308212 + size: 172069 + timestamp: 1788524702946 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pytorch-2.12.1-cpu_generic_py312_h9dd5f13_0.conda sha256: 8956bf3e04eaed1056dd011714dcb50d8c2804aeb7ec40ff6e8a739b5d6abdb2 md5: 452a1b67f47bc4ff7bd6c48ad0f20667 @@ -22760,16 +22815,16 @@ packages: run_exports: {} size: 554806 timestamp: 1787617465010 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h89cd0c0_2.conda - sha256: 9c25def7c7f9ab98b265690c80012e917d080538875f9679b46ccd0c042e6201 - md5: 14ef48eb322e0bfb1e5fe31e047359e3 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.88.3-h81decf1_3.conda + sha256: aad240a33afc71c0c9cefea5304c917c256518e6724cd646d924838fdff1fcb3 + md5: f3ee2d5802e47ff391fe9a6d956e76b0 depends: - __osx >=11.0 - - libintl >=0.25.1,<1.0a0 - libzlib >=1.3.2,<2.0a0 + - libffi >=3.7.0,<3.8.0a0 - pcre2 >=10.47,<10.48.0a0 + - libintl >=0.25.1,<1.0a0 - libiconv >=1.18,<2.0a0 - - libffi >=3.7.0,<3.8.0a0 constrains: - glib >2.66 license: LGPL-2.1-or-later @@ -22777,8 +22832,8 @@ packages: run_exports: weak: - libglib >=2.88.3,<3.0a0 - size: 4443052 - timestamp: 1787884141804 + size: 4443129 + timestamp: 1788525252185 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-3.8.0-ha595bda_0.conda sha256: a48050bcf3827e0fc10de5a7d251760b8b84011f3aeea23ae18b5e0ce25aff19 md5: 4f34ca73f16b37fae583ce16c48b5492 @@ -24052,21 +24107,20 @@ packages: - python size: 11705033 timestamp: 1788407558326 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-librt-0.15.0-py312h7ac3c4f_1.conda - sha256: 94aa71abc82ab24c52252997062b117f63149fce14377958ece828cd79011f6a - md5: b8e9ca60f567b679f76d908dcc51628d +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-librt-0.15.0-py312h7ac3c4f_2.conda + sha256: ace7db1c4bc3f8423f01683cd8ad6ad7940277957b688f56eec93e6d9197db60 + md5: af32bad9f75ad4b132017bb2b12d5296 depends: - python - - __osx >=11.0 - python 3.12.* *_cpython + - __osx >=11.0 - python_abi 3.12.* *_cp312 license: MIT - license_family: MIT purls: - - pkg:pypi/librt?source=compressed-mapping + - pkg:pypi/librt?source=hash-mapping run_exports: {} - size: 129888 - timestamp: 1788228436318 + size: 130261 + timestamp: 1788524846305 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pytorch-2.12.1-cpu_generic_py312_h7a5249f_0.conda sha256: 538726375bf71a9f7d776eeba3964ff049fa888c79ed93d76319127e2a02559d md5: 93c511e326295c67ccd7864983a5e87a diff --git a/pixi.toml b/pixi.toml index e86b8d02..80616892 100644 --- a/pixi.toml +++ b/pixi.toml @@ -301,9 +301,9 @@ test-py311-pyscf214-torch213 = { features = ["python-runtime", "model-assets", " test-py312-pyscf214-torch212 = { features = ["python-runtime", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-212-cpu", "test", "profiling", "benchmark"], no-default-feature = true, platforms = ["linux-64", "linux-aarch64", "osx-arm64"] } test-py312-pyscf214-torch213 = { features = ["python-runtime", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-cpu", "test", "profiling", "benchmark"], no-default-feature = true, platforms = ["linux-64", "linux-aarch64", "osx-arm64"] } test-py313-pyscf214-torch213 = { features = ["python-runtime", "model-assets", "python-313", "pyscf-214", "dispersion", "torch-213-cpu", "test"], no-default-feature = true, platforms = ["linux-64"] } -gpu-cuda12-torch212 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-212-gpu", "cuda-12", "test", "benchmark"], no-default-feature = true, platforms = ["linux-64-cuda12"] } -gpu-cuda12-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-12", "test", "benchmark"], no-default-feature = true, platforms = ["linux-64-cuda12"] } -gpu-cuda13-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-13", "test", "benchmark"], no-default-feature = true, platforms = ["linux-64-cuda13"] } +gpu-cuda12-torch212 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-212-gpu", "cuda-12", "test", "benchmark","profiling"], no-default-feature = true, platforms = ["linux-64-cuda12"] } +gpu-cuda12-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-12", "test", "benchmark","profiling"], no-default-feature = true, platforms = ["linux-64-cuda12"] } +gpu-cuda13-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-13", "test", "benchmark","profiling"], no-default-feature = true, platforms = ["linux-64-cuda13"] } docs = { features = ["python-runtime", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-cpu", "benchmark", "docs"], no-default-feature = true, platforms = ["linux-64"] } assets = { features = ["python-312", "model-assets"], no-default-feature = true, platforms = ["linux-64"] } release = { features = ["python-312", "release"], no-default-feature = true, platforms = ["linux-64"] } diff --git a/skala/tests/utils.py b/skala/tests/utils.py index f20931cd..1bee5d80 100644 --- a/skala/tests/utils.py +++ b/skala/tests/utils.py @@ -89,22 +89,18 @@ def get_exc(self, mol: FeatureMap) -> torch.Tensor: @contextmanager -def force_ao_screening( - enabled: bool, - module: ModuleType = xc_integrator_module, -) -> Generator[None]: +def force_ao_screening(enabled: bool) -> Generator[None]: """Temporarily force the AO-screening route decision. Args: enabled: Whether calls should select screened AO evaluation. - module: Module whose ``_should_screen_aos`` decision function is patched. Yields: Control while the forced decision is active. The previous function is restored when the context exits. """ with patch.object( - module, + xc_integrator_module, "_should_screen_aos", return_value=enabled, ): From 9a82fad680cc1dea3207109fa8cef8ebbc015b44 Mon Sep 17 00:00:00 2001 From: jenswehner Date: Thu, 3 Sep 2026 12:57:14 +0200 Subject: [PATCH 2/4] added warmups --- benchmarks/run_pyscf_ao_screening_benchmark.py | 8 ++++++++ benchmarks/run_pyscf_ao_screening_rotation_benchmark.py | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/benchmarks/run_pyscf_ao_screening_benchmark.py b/benchmarks/run_pyscf_ao_screening_benchmark.py index af2c4117..492a5351 100644 --- a/benchmarks/run_pyscf_ao_screening_benchmark.py +++ b/benchmarks/run_pyscf_ao_screening_benchmark.py @@ -95,6 +95,7 @@ class BenchmarkConfig: max_memory_mb: int = 2000 cpu_threads: int = 4 runtime_repetitions: int = 3 + runtime_warmup_runs: int = 2 worker_timeout_seconds: int = 30 * 60 smoke_run: bool = False @@ -572,6 +573,8 @@ def evaluate() -> tuple[Any, Any, Any]: with dense_route_override: measurement = payload["measurement"] if measurement == "runtime": + for _ in range(int(payload["runtime_warmup_runs"])): + evaluate() case["synchronize"]() started = time.perf_counter() result = evaluate() @@ -814,6 +817,7 @@ def worker_payload( "forced_dense": mode.endswith("_dense"), "mode": mode, "measurement": measurement, + "runtime_warmup_runs": config.runtime_warmup_runs, "molecule": { "carbon_count": molecule.carbon_count, "formula": molecule.formula, @@ -1064,6 +1068,7 @@ def parse_arguments(argv: list[str]) -> argparse.Namespace: parser.add_argument("--max-memory-mb", type=int, default=2000) parser.add_argument("--threads", type=int, default=4) parser.add_argument("--runtime-repetitions", type=int, default=3) + parser.add_argument("--runtime-warmup-runs", type=int, default=2) parser.add_argument("--timeout-minutes", type=float, default=30.0) parser.add_argument( "--smoke", @@ -1085,6 +1090,8 @@ def config_from_arguments(arguments: argparse.Namespace) -> BenchmarkConfig: raise ValueError("--threads must be positive") if arguments.runtime_repetitions <= 0: raise ValueError("--runtime-repetitions must be positive") + if arguments.runtime_warmup_runs < 0: + raise ValueError("--runtime-warmup-runs must be non-negative") source_root = arguments.source_root.expanduser().resolve() if not (source_root / "src" / "skala").is_dir(): raise FileNotFoundError(f"No src/skala package below {source_root}") @@ -1098,6 +1105,7 @@ def config_from_arguments(arguments: argparse.Namespace) -> BenchmarkConfig: max_memory_mb=arguments.max_memory_mb, cpu_threads=arguments.threads, runtime_repetitions=arguments.runtime_repetitions, + runtime_warmup_runs=arguments.runtime_warmup_runs, worker_timeout_seconds=round(arguments.timeout_minutes * 60), smoke_run=arguments.smoke, ) diff --git a/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py b/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py index 463ade53..a81ccd08 100644 --- a/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py +++ b/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py @@ -333,6 +333,7 @@ def parse_arguments(argv: list[str]) -> argparse.Namespace: parser.add_argument("--max-memory-mb", type=int, default=2000) parser.add_argument("--threads", type=int, default=4) parser.add_argument("--runtime-repetitions", type=int, default=3) + parser.add_argument("--runtime-warmup-runs", type=int, default=2) parser.add_argument("--timeout-minutes", type=float, default=30.0) parser.add_argument("--azimuth-step-degrees", type=int, default=30) parser.add_argument("--polar-step-degrees", type=int, default=30) @@ -358,6 +359,8 @@ def config_from_arguments( raise ValueError("--threads must be positive") if arguments.runtime_repetitions <= 0: raise ValueError("--runtime-repetitions must be positive") + if arguments.runtime_warmup_runs < 0: + raise ValueError("--runtime-warmup-runs must be non-negative") if arguments.azimuth_step_degrees <= 0 or 360 % arguments.azimuth_step_degrees: raise ValueError("--azimuth-step-degrees must be a positive divisor of 360") if arguments.polar_step_degrees <= 0 or 180 % arguments.polar_step_degrees: @@ -375,6 +378,7 @@ def config_from_arguments( max_memory_mb=arguments.max_memory_mb, cpu_threads=arguments.threads, runtime_repetitions=arguments.runtime_repetitions, + runtime_warmup_runs=arguments.runtime_warmup_runs, worker_timeout_seconds=round(arguments.timeout_minutes * 60), smoke_run=arguments.smoke, azimuth_step_degrees=arguments.azimuth_step_degrees, From 1fae00861bb22bb02fd5f670f29b93e3603ad5e1 Mon Sep 17 00:00:00 2001 From: jenswehner Date: Thu, 3 Sep 2026 14:52:21 +0200 Subject: [PATCH 3/4] added dev environment with plotting --- AGENTS.md | 2 + CONTRIBUTING.md | 10 + README.md | 3 +- benchmarks/vxc_accuracy_grid_grouping.ipynb | 6 +- pixi.lock | 1141 ++++++++++++++++++- pixi.toml | 12 +- skala/README.md | 3 +- website/installation.rst | 8 + website/pyscf/gpu4pyscf.rst | 6 +- 9 files changed, 1120 insertions(+), 71 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e6446f27..e59d75bd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,6 +33,8 @@ SkalaXC's bundled model selectors are `LDA`, `PBE`, and `TPSS`, or an explicit ` ```bash pixi install --locked -e default ``` + On Linux x86_64 with a CUDA 12-compatible driver, use `pixi install --locked -e dev` + for the GPU-enabled superset with profiling, IPython, notebook, and plotting tools. 3. **Pre-commit hooks** (required before committing): ```bash pixi run -e default pre-commit install diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e273ca59..7599952f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,6 +23,16 @@ pixi install --locked -e default pixi run -e default pre-commit install ``` +On Linux x86_64 with a CUDA 12-compatible driver, the `dev` environment is the +GPU-enabled development superset. It adds GPU4PySCF, profiling, IPython, a +notebook kernel, and plotting tools while retaining the default test, lint, +model, and benchmark tooling: + +```bash +pixi install --locked -e dev +pixi run -e dev ipython +``` + Run the standard checks in their Pixi environments: ```bash diff --git a/README.md b/README.md index 1bc81e13..47a6dc7e 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,8 @@ pip install skala-cuda12x The `skala-cuda13x` package is available for CUDA 13. -For a reproducible source environment, choose one of the locked GPU environments: +For a reproducible source environment, choose one of the locked GPU compatibility +environments: | Environment | CUDA | PyTorch | |---|---:|---:| diff --git a/benchmarks/vxc_accuracy_grid_grouping.ipynb b/benchmarks/vxc_accuracy_grid_grouping.ipynb index bf9c8485..5acb16a2 100644 --- a/benchmarks/vxc_accuracy_grid_grouping.ipynb +++ b/benchmarks/vxc_accuracy_grid_grouping.ipynb @@ -26,9 +26,6 @@ "import cupy\n", "import numpy as np\n", "import torch\n", - "from pyscf import dft, gto\n", - "from tests.utils import patch_ao_screening\n", - "\n", "from skala.functional import load_functional\n", "from skala.functional.base import ExcFunctionalBase\n", "from skala.pyscf import features as features_module\n", @@ -36,6 +33,9 @@ "from skala.pyscf.features import _spatial_grid_permutations\n", "from skala.pyscf.numint import SkalaNumInt\n", "\n", + "from pyscf import dft, gto\n", + "from tests.utils import patch_ao_screening\n", + "\n", "np.set_printoptions(precision=4, suppress=True)\n", "\n", "\n", diff --git a/pixi.lock b/pixi.lock index afbd63ab..3a2f368b 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1378,6 +1378,386 @@ environments: - pypi: https://files.pythonhosted.org/packages/65/6c/eea1d03e475217aea95b1d52aee09c97575d05bbc592c39c085b71dab89f/pyarrow_stubs-20.0.0.20260819-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b0/42/c84efcc1d4caebafb1ecd8be4643f39c85c47a80fe254d92b8b43b1eadaf/h5py-3.16.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/e1/26/d4bc2ba3427a623f79a6c10c8f427c7a55b56eb8b3eddc369319d97f741b/scipy_stubs-1.17.1.5-py3-none-any.whl + dev: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64-cuda12: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-8_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.16.1-h7cc23a3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ast-serialize-0.9.0-py311hf77984d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.10.4-hb7a77c6_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.14-h2aa3ae6_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.14.2-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.2-h720e601_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.7.1-h6ffeea8_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.11.0-h38ae05a_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.27.3-h6f4d18d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.16.0-h21f4ec5_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.12.8-h46fcd08_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.7-h720e601_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.10-h720e601_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.40.1-h102d43b_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.833-hc7390e0_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-core-cpp-1.16.3-h206d751_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-identity-cpp-1.13.3-h71f81a8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.18.0-h74b55db_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.14.0-hf596fc9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.16.0-h1f05bef_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-h505cf86_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-h9908984_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3c89d7e_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.1.1-py312h703531f_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312h0a2e395_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.16.0-py312h8b7ec3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-crt-tools-12.9.86-ha770c72_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-12.9.79-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-dev-12.9.79-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-static-12.9.79-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cuobjdump-12.9.82-hffce074_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-cupti-12.9.79-h676940d_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvcc-tools-12.9.86-he02047a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvdisasm-12.9.88-hffce074_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-12.9.86-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-dev-12.9.86-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-12.9.79-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-12.9.86-h4bc722e_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h2d75abc_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-he8c428d_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.21-py312h8285ef7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.4.0-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.16-h7cc23a3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gflags-2.3.1-h54a6638_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hb7133d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hf-xet-1.5.2-py310hb823017_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-h7cc23a3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.1-py312h9be0db6_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-hbc21106_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h9073bf1_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-25.0.0-hcc2f0d9_4_cpu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-25.0.0-h635bf11_4_cpu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-compute-25.0.0-h53684a4_4_cpu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-25.0.0-h635bf11_4_cpu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-25.0.0-h66fbfdd_4_cpu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-10_h5875eb1_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-h018ffa1_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.78-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-10_hfef963f_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp23.1-23.1.0-default_h0acdd01_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-23.1.0-default_h7855034_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcublas-12.9.2.10-h676940d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcublas-dev-12.9.2.10-h676940d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcudnn-9.10.2.21-hf7e9902_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcudss-0.8.0.10-h58dd1b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcufft-11.4.1.4-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcufile-1.14.1.1-hbc026e6_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurand-10.3.10.19-h676940d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.22.0-ha042cf0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcusolver-11.7.5.82-h676940d_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcusparse-12.5.10.65-hecca717_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-hd45a770_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.129-h7cc23a3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h373387f_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-h280c20c_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.7.0-h81df57d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h5e6c136_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.2.0-ha9f2e26_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-3.8.0-hbc29df5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-3.8.0-hdbdcf42_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.82.1-h792040b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm23-23.1.0-h474f4eb_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-ha7672b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnvjitlink-12.9.86-hecca717_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-1.27.0-h3133023_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-headers-1.27.0-ha770c72_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libparquet-25.0.0-h7376487_4_cpu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.19-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h922cc85_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.6-h9d76c99_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-7.35.1-h622638d_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpsl-0.23.1-hd9e3e90_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpython-3.12.14-h0c77377_3_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libraqm-0.11.0-h6406941_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2025.11.05-h60473fc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.22-hebe6cf0_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h13e7031_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-h6154650_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda129_mkl_h546cc0b_302.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.357.0-h0e34353_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-hb83e432_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.38-h280c20c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.2-h51789e4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.45-h8e12856_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.11.1-py312h6a12a82_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-2.3.1-py312h89dfda2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h4d09622_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/onednn-3.12-omp_h83de36e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-heb1ab33_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.3.1-h443056b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.5-py312h8ecdadd_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.2-py312hf143aa3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cuda129_mkl_py312_h0509a7e_302.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-gpu-2.13.0-cuda129_mkl_h0d04637_302.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.2.0-py312h8a5ba0d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.11.2-pl5321h9df5c37_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-64.0-h192683f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/re2-2025.11.05-h94463f1_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-hd6e31c0_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.7.5-h7e3ee7f_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.18.0-py312h54fa4ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/sleef-3.9.0-ha0421bc_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2023.0.0-hab88423_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h1df4ec4_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py312h5cc1888_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/triton-3.7.1-cuda129py312h811769c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py312hd9148b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-17.0.1-py312h4c3975b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.26.0-hc1c935e_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.48-h280c20c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-h280c20c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-h0d788c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.7-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.7-h7cc23a3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.2-h7cc23a3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.3-h7cc23a3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.5-h7cc23a3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-h7cc23a3_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.7-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2025.1-hebe6cf0_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-hebe6cf0_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h09e67af_11.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hce19668_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.15.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ase-3.29.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.4.2-pyhc90fa1f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.3-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.14-py312hd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cccl_linux-64-12.9.27-ha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-crt-dev_linux-64-12.9.86-ha770c72_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_linux-64-12.9.79-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-64-12.9.79-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-64-12.9.79-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cuda-version-12.9-h4f385c5_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/e3nn-0.6.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.32.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.16.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.9-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-0.28.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/huggingface_hub-1.30.0-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-7.3.0-pyha191276_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.17.1-pyh53cf698_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.20.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.10.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio2-1.7.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/opt-einsum-3.4.0-hd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum-3.4.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum_fx-0.1.4-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.7-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.6-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.2-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.53-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-global-3.0.4-pyh648e204_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-3.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-benchmark-5.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-randomly-4.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-timeout-2.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.6.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.16.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.7.8-pyh5ded981_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.8.3-pyhcf101f3_0.conda + - pypi: ./benchmark + - pypi: ./model + - pypi: ./skala + - pypi: https://files.pythonhosted.org/packages/08/52/eefeba09be4ef2a1eb989eb92934561e8e502a6ee3c32654996e4be7e399/types_pyyaml-6.0.12.20260815-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2f/d4/c6a2b043e33f0dd012486dcebe0593585588d400175d22aad42049c88321/optype-0.17.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/2f/10a2e9ad81bd5c2479a255d18c4f02c734a3a21bf4b36a236ba615919592/pyscf_dispersion-1.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/4d/57/f53eb30c38aa4eeabddc3bddf283f4c10616de65d95fcd1f43900721f425/geometric-1.1.1.tar.gz + - pypi: https://files.pythonhosted.org/packages/60/c2/959caec5c46f484b5f8bb6def4b0cf7a45ba6acda26f12b75142d98cc5ae/pandas_stubs-3.0.5.260730-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/7c/5c2892e6bc0628a2ccf4e938e1e2db22794657ccb374672d66e20d73839e/numpy_typing_compat-20251206.2.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/b5/ff337f8db80e67c464846a7d10f7f6bc1039c40a2c8b57ecb90d6b0c11d9/gpu4pyscf_libxc_cuda12x-0.8.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/65/6c/eea1d03e475217aea95b1d52aee09c97575d05bbc592c39c085b71dab89f/pyarrow_stubs-20.0.0.20260819-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7c/5b/65124de2dbaf2e85109f611a41947e39acd6dd938751c04b4c4d7bf6fc82/cupy_cuda12x-14.2.0-cp312-cp312-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/88/30/8e48717aff32f11fd78f981192d0b567971eb285ea048414b7dac2a211cf/pyscf-2.14.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/99/a7/6ed6f987f79d6442e553841ddd45439aa90a3992d8e009ccd47e46901814/gpu4pyscf_cuda12x-1.8.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9d/e6/22df83f82f9bc26cb1c42265cf14d34d4908dba2a0f261bd7b28244acb00/cuda_pathfinder-1.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/e9/1a19e42cd43cc1365e127db6aae85e1c671da1d9a5d746f4d34a50edb577/h5py-3.16.0-cp312-cp312-manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/e1/26/d4bc2ba3427a623f79a6c10c8f427c7a55b56eb8b3eddc369319d97f741b/scipy_stubs-1.17.1.5-py3-none-any.whl docs: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -2061,7 +2441,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-12.9.79-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-12.9.86-h4bc722e_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h2d75abc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -2071,7 +2450,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hb7133d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hf-xet-1.5.2-py310hb823017_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda @@ -2082,7 +2460,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-25.0.0-hcc2f0d9_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-25.0.0-h635bf11_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-compute-25.0.0-h53684a4_4_cpu.conda @@ -2124,12 +2501,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-ha7672b3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -2148,13 +2523,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.12.1-cuda129_mkl_h6b8258c_300.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda @@ -2166,16 +2538,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h4d09622_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onednn-3.12-omp_h83de36e_0.conda @@ -2183,14 +2552,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.3.1-h443056b_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.5-py312h8ecdadd_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda @@ -2255,9 +2622,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -2266,7 +2631,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum-3.4.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum_fx-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.6-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -2282,18 +2646,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - pypi: ./benchmark - pypi: ./model - pypi: ./skala @@ -2351,7 +2712,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-12.9.79-hecca717_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-12.9.86-h4bc722e_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h2d75abc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -2361,7 +2721,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hb7133d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hf-xet-1.5.2-py310hb823017_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda @@ -2372,7 +2731,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-25.0.0-hcc2f0d9_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-25.0.0-h635bf11_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-compute-25.0.0-h53684a4_4_cpu.conda @@ -2414,12 +2772,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-ha7672b3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -2438,13 +2794,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda129_mkl_h546cc0b_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda @@ -2456,16 +2809,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h4d09622_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onednn-3.12-omp_h83de36e_0.conda @@ -2473,14 +2823,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.3.1-h443056b_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.5-py312h8ecdadd_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda @@ -2545,9 +2893,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -2556,7 +2902,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum-3.4.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum_fx-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.6-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -2572,18 +2917,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - pypi: ./benchmark - pypi: ./model - pypi: ./skala @@ -2641,7 +2983,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-13.3.29-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cuda-nvvm-tools-13.3.73-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h15eaa2f_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -2651,7 +2992,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hb7133d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/hf-xet-1.5.2-py310hb823017_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda @@ -2662,7 +3002,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-25.0.0-hcc2f0d9_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-25.0.0-h635bf11_4_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-compute-25.0.0-h53684a4_4_cpu.conda @@ -2704,12 +3043,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-hd93470c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -2728,13 +3065,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda130_mkl_h1ca3d63_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda @@ -2746,16 +3080,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h1aa9b5a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/onednn-3.12-omp_h83de36e_0.conda @@ -2763,14 +3094,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.3.1-h443056b_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.5-py312h8ecdadd_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-25.0.0-py312h7900ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-25.0.0-py312h2054cf2_0_cpu.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda @@ -2835,9 +3164,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -2846,7 +3173,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum-3.4.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/opt_einsum_fx-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.6-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -2862,18 +3188,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - pypi: ./benchmark - pypi: ./model - pypi: ./skala @@ -7921,6 +8244,20 @@ packages: - _openmp_mutex >=4.5 size: 8050 timestamp: 1788046427177 +- conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.16.1-h7cc23a3_1.conda + sha256: a35bddac04be093769e81814465a537961c6ed0f8d3cc23d6dce6ecdfaf71821 + md5: 7094e0d8d14de0eff6d83f0d2f1f661e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + license: LGPL-2.1-or-later + license_family: LGPL + purls: [] + run_exports: + weak: + - alsa-lib >=1.2.16.1,<1.3.0a0 + size: 594986 + timestamp: 1787763412911 - conda: https://conda.anaconda.org/conda-forge/linux-64/ast-serialize-0.9.0-py311hf77984d_0.conda noarch: python sha256: 5b77c2444c8fef0feb1c37e7050c78f7e235c62ffec9ab58b6c4a82566ef32d4 @@ -9652,6 +9989,42 @@ packages: run_exports: {} size: 6972 timestamp: 1786642183694 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda + sha256: 7684da83306bb69686c0506fb09aa7074e1a55ade50c3a879e4e5df6eebb1009 + md5: af491aae930edc096b58466c51c4126c + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=13 + - libntlm >=1.8,<2.0a0 + - libstdcxx >=13 + - libxcrypt >=4.4.36 + - openssl >=3.5.5,<4.0a0 + license: BSD-3-Clause-Attribution + license_family: BSD + purls: [] + run_exports: + weak: + - cyrus-sasl >=2.1.28,<3.0a0 + size: 210103 + timestamp: 1771943128249 +- conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-he8c428d_2.conda + sha256: 87a0a42d4ccc527597eff3234509dfb03e0d9bf67d5e2b6fc758e2ef389d8abe + md5: a6eb37b51be1a9a654dc3a8aca039b1a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - libstdcxx >=15 + - libexpat >=2.8.1,<3.0a0 + - libzlib >=1.3.2,<2.0a0 + - libglib >=2.88.3,<3.0a0 + license: AFL-2.1 OR GPL-2.0-or-later + purls: [] + run_exports: + weak: + - dbus >=1.16.2,<2.0a0 + size: 449564 + timestamp: 1788197922783 - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.21-py312h8285ef7_0.conda sha256: b8dbe25820064a099f315bbb8f45f5bac3fddb63e96af3cbf0c93a830733ef34 md5: e6778419a1851f6e15820558abddfa04 @@ -9668,6 +10041,21 @@ packages: run_exports: {} size: 2821960 timestamp: 1780390159181 +- conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.4.0-hecca717_0.conda + sha256: 40cdd1b048444d3235069d75f9c8e1f286db567f6278a93b4f024e5642cfaecc + md5: dbe3ec0f120af456b3477743ffd99b74 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: BSD-3-Clause + license_family: BSD + purls: [] + run_exports: + weak: + - double-conversion >=3.4.0,<3.5.0a0 + size: 71809 + timestamp: 1765193127016 - conda: https://conda.anaconda.org/conda-forge/linux-64/doxygen-1.18.0-py310hb664d3d_0.conda sha256: aa8efe84767d1f628f439749df5bd1d369cad6ef1a6cc2922ffc75238e62f07a md5: 13974bf5357b9bb5ecab0a09fd06d144 @@ -10956,6 +11344,7 @@ packages: - libllvm23 >=23.1.0,<23.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE + purls: [] run_exports: weak: - libclang-cpp23.1 >=23.1.0,<23.2.0a0 @@ -10976,6 +11365,7 @@ packages: - libllvm23 >=23.1.0,<23.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE + purls: [] run_exports: weak: - libclang13 >=23.1.0 @@ -11207,6 +11597,23 @@ packages: run_exports: {} size: 1117538 timestamp: 1782772352403 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h7a8fb5f_6.conda + sha256: 205c4f19550f3647832ec44e35e6d93c8c206782bdd620c1d7cf66237580ff9c + md5: 49c553b47ff679a6a1e9fc80b9c5a2d4 + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + license: Apache-2.0 + license_family: Apache + purls: [] + run_exports: + weak: + - libcups >=2.3.3,<2.4.0a0 + size: 4518030 + timestamp: 1770902209173 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurand-10.3.10.19-h676940d_1.conda sha256: 3d40daf956b220cc367a6306ede1e259446fb844051bcfed87c46539cc1aaf03 md5: 2a91559a9345bedf09af8b7903deb6e6 @@ -11328,6 +11735,21 @@ packages: - libdeflate >=1.25,<1.26.0a0 size: 73710 timestamp: 1785908694612 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.129-h7cc23a3_0.conda + sha256: ea46b0ca0fa16af1f8b329b740e6cd8b4577c5378fa8717b28a885f70668633d + md5: 64cc91512b6278c315349dc13c53f680 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - libpciaccess >=0.19,<0.20.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - libdrm >=2.4.129,<2.5.0a0 + size: 313461 + timestamp: 1786684701973 - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h373387f_1.conda sha256: 6473eb8caf2aae830f37caa93db9b26dddf7ac84b63229e8bf7fc0e5c3ab95b0 md5: 50708d3b951d0f8e2d7f2df5b5edc040 @@ -11344,6 +11766,32 @@ packages: - libedit >=3.1.20250104,<3.2.0a0 size: 135098 timestamp: 1786616658086 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_5.conda + sha256: 13d3fde9c1dcf254968cc70652222a43f25d04e69555ccf855553110e753288e + md5: 3a1b41c4591a0a1734382af3e2b8bc08 + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_5 + license: LicenseRef-libglvnd + purls: [] + run_exports: {} + size: 46694 + timestamp: 1787310030923 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_5.conda + sha256: fd2794bbcff7e692fb476c17886702702893d074071d429217bad7cfb072abfd + md5: 577800fc8c9d8b7d9727246bbfde704e + depends: + - __glibc >=2.17,<3.0.a0 + - libegl 1.7.0 ha4b6fd6_5 + - libgl-devel 1.7.0 ha4b6fd6_5 + - xorg-libx11 + license: LicenseRef-libglvnd + purls: [] + run_exports: + weak: + - libegl >=1.7.0,<2.0a0 + size: 31242 + timestamp: 1787310065866 - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-h280c20c_3.conda sha256: e4418f68d01a6307c4431b585c71b584f40189877364e542ee87deb777f5e85b md5: 7bc31538d6e3fb349e897353969237ec @@ -11505,6 +11953,32 @@ packages: run_exports: {} size: 2526008 timestamp: 1787618692926 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_5.conda + sha256: 7b2e7e31e8a4f5a01c45ecadcd8aa68c8f733b035240bc7ba9881835ef4bf7b4 + md5: 81141db127a106eb5a91df69a29c9918 + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_5 + - libglx 1.7.0 ha4b6fd6_5 + license: LicenseRef-libglvnd + purls: [] + run_exports: {} + size: 131988 + timestamp: 1787310049847 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_5.conda + sha256: 3bebdbeb3ce451287794dddd5cc4d7f4970aac200b2fb797f0d17ac727a71cb7 + md5: f5f7fc038c611a25b22758c0a40d25c9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgl 1.7.0 ha4b6fd6_5 + - libglx-devel 1.7.0 ha4b6fd6_5 + license: LicenseRef-libglvnd + purls: [] + run_exports: + weak: + - libgl >=1.7.0,<2.0a0 + size: 116212 + timestamp: 1787310061570 - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.88.3-he503a2a_3.conda sha256: f57bf3954dbba8b27ec68540e84f8b2c2375ffa5702f89ca9741e17329fc3953 md5: d216efacca3f34f2b13ddd1632f53833 @@ -11524,6 +11998,43 @@ packages: - libglib >=2.88.3,<3.0a0 size: 4758346 timestamp: 1788525203514 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_5.conda + sha256: 6eb77601a44b78c4631d886d54ef54f321c2bdc69fdefc4065a1e0491f030c76 + md5: cfcf11edcfd4acf0094771a9c3b8587f + depends: + - __glibc >=2.17,<3.0.a0 + license: LicenseRef-libglvnd + purls: [] + run_exports: {} + size: 133827 + timestamp: 1787310026653 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_5.conda + sha256: d1f0d51aea6bcc5d915969cbed32e72a8ed6a95931b87357ef8d0866573688c4 + md5: 614e10aae180f87b84f0d1ca8ceb7d9e + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_5 + - xorg-libx11 >=1.8.13,<2.0a0 + license: LicenseRef-libglvnd + purls: [] + run_exports: {} + size: 79834 + timestamp: 1787310042550 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_5.conda + sha256: aff3841e3404d78e1887fef988ca4842930c577399d566fa0980808756b1df51 + md5: fb00b4fb800f2d431303a5c1625ef9d0 + depends: + - __glibc >=2.17,<3.0.a0 + - libglx 1.7.0 ha4b6fd6_5 + - xorg-libx11 >=1.8.13,<2.0a0 + - xorg-xorgproto + license: LicenseRef-libglvnd + purls: [] + run_exports: + weak: + - libglx >=1.7.0,<2.0a0 + size: 27698 + timestamp: 1787310053582 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda sha256: 0fe5cb8e0752241ab55e11656ed1b9726248b522d23b929fe7c95b83eb55b9bb md5: 89d2c1231f47bd818f5d624b9411459d @@ -11758,6 +12269,7 @@ packages: - zstd >=1.5.7,<1.6.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache + purls: [] run_exports: weak: - libllvm23 >=23.1.0,<23.2.0a0 @@ -11893,6 +12405,19 @@ packages: - libnsl >=2.0.1,<2.1.0a0 size: 33731 timestamp: 1750274110928 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda + sha256: 3b3f19ced060013c2dd99d9d46403be6d319d4601814c772a3472fe2955612b0 + md5: 7c7927b404672409d9917d49bff5f2d6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-or-later + purls: [] + run_exports: + weak: + - libntlm >=1.8,<2.0a0 + size: 33418 + timestamp: 1734670021371 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnvjitlink-12.9.86-hecca717_2.conda sha256: 3b1c851f4fc42d347ce1c1606bdd195343a47f121e0fceb7a1f1e5aa1d497da9 md5: 3461b0f2d5cbb7973d361f9e85241d98 @@ -11941,6 +12466,17 @@ packages: run_exports: {} size: 27739 timestamp: 1787703595006 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_5.conda + sha256: 7bdca717c840e17d7dd050f925dd964da61086c2612b8579a4ff4147105f291f + md5: d207a2e9bae9da476bc0a603215d5167 + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_5 + license: LicenseRef-libglvnd + purls: [] + run_exports: {} + size: 50627 + timestamp: 1787310045795 - conda: https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-1.27.0-h3133023_1.conda sha256: 8f9281133322e9eb0bd4a5b11330db1c14f3b40c409639dd3805251151ca52e2 md5: f749f223bede1bac7724e49d686ac598 @@ -11989,9 +12525,23 @@ packages: purls: [] run_exports: weak: - - libparquet >=25.0.0,<25.1.0a0 - size: 1412634 - timestamp: 1786315223543 + - libparquet >=25.0.0,<25.1.0a0 + size: 1412634 + timestamp: 1786315223543 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.19-hb03c661_1.conda + sha256: addc80c69d362a9e6c40305c493139a8e9ee504b2f45a6687dbdaa9da3c6183c + md5: 35fa2b34bbced424e6976d30f5fde576 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - libpciaccess >=0.19,<0.20.0a0 + size: 30070 + timestamp: 1785971678815 - conda: https://conda.anaconda.org/conda-forge/linux-64/libpmix-5.0.8-h31fc519_4.conda sha256: 2837759fb832ab8587622602531f8e4b5d5e5ec12ea9b3936be06f384b933800 md5: bd15ae3916a0cbe005c683bbc33811b7 @@ -12023,6 +12573,23 @@ packages: - libpng >=1.6.58,<1.7.0a0 size: 316643 timestamp: 1786616563127 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.6-h9d76c99_0.conda + sha256: b1eb210c180fda9c445b11cba1286ec250ce2c2a85ccb0551a4ed5423df51e68 + md5: 72e019c04ed02a179da38c56965802d1 + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=78.3,<79.0a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=15 + - openldap >=2.6.13,<2.7.0a0 + - openssl >=3.5.7,<4.0a0 + license: PostgreSQL + purls: [] + run_exports: + weak: + - libpq >=18.6,<19.0a0 + size: 2719680 + timestamp: 1786641133110 - conda: https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-7.35.1-h622638d_3.conda sha256: 37c51fbc936a6bb8bf5f67c8f056edacaaa41e8603738bc8a4dee186292bb114 md5: fd307b61cceb36fdca38e1718bdb2893 @@ -12609,6 +13176,25 @@ packages: - libuv >=1.52.1,<2.0a0 size: 420040 timestamp: 1785914567661 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.357.0-h0e34353_2.conda + sha256: a70c25b66321ee77f9892b205e3247263c400803f543dc8aca53d569a59c5a77 + md5: c5f5f159b66332152197893427071695 + depends: + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=15 + - libgcc >=15 + - xorg-libxrandr >=1.5.5,<2.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 + constrains: + - libvulkan-headers 1.4.357.0.* + license: Apache-2.0 + license_family: APACHE + purls: [] + run_exports: + weak: + - libvulkan-loader >=1.4.357.0,<2.0a0 + size: 206957 + timestamp: 1787491938583 - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda sha256: 8415001414f488c85b72b9d8cc2071dfb3981a47bc3c8eb56ef91a57d12eae7f md5: 9332b53d0ea93c5d39e33be03a0c611a @@ -12655,6 +13241,25 @@ packages: - libxcrypt >=4.4.38 size: 101957 timestamp: 1785887123445 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.2-h51789e4_1.conda + sha256: d44878d396713ccf3b355df617f61c40a1442fffcf134392bc6ce0e6c2219369 + md5: f888787e0eab7a8076a67d197e155ffc + depends: + - xkeyboard-config + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libxcb >=1.17.0,<2.0a0 + - xorg-libxau >=1.0.12,<2.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + license: MIT AND MIT-open-group AND HPND AND HPND-sell-variant AND ISC + purls: [] + run_exports: + weak: + - libxkbcommon >=1.13.2,<2.0a0 + size: 942571 + timestamp: 1787178780572 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_1.conda sha256: 087d4de023f22d6a28b9e1b818961dd41e9bda6e9793590600ff16ca150bf9cb md5: 20e4d67ec908f0405124f11612c48305 @@ -12693,6 +13298,22 @@ packages: - libxml2-16 >=2.15.3 size: 46203 timestamp: 1787237584107 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.45-h8e12856_0.conda + sha256: 3257043531b6828cbfe3f1c4d843dd29de3898c4c8780efba792ccdd1464c3b1 + md5: be101a81eab00f1abe854c11a68970de + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - libxml2 + - libxml2-16 >=2.15.3 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - libxslt >=1.1.45,<2.0a0 + size: 250892 + timestamp: 1788362459630 - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda sha256: eb8a0db0aa570124f7d2a93d7c7f596e3390df5e047818d873baad32985fc736 md5: 0de0122d9570a8ab637c6b73db268389 @@ -12806,6 +13427,21 @@ packages: run_exports: {} size: 26100 timestamp: 1772445154165 +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.11.1-py312h6a12a82_2.conda + sha256: 72daeb18e9f82509cf6eec25975324c06681127fb94b9b20b53a620a76457e62 + md5: 26c8cd6cbd98ec961a2f8969e14a6e4d + depends: + - matplotlib-base >=3.11.1,<3.11.2.0a0 + - pyside6 >=6.7.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tornado >=5 + license: PSF-2.0 + license_family: PSF + purls: [] + run_exports: {} + size: 14938 + timestamp: 1785211151683 - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py311he401cf6_2.conda sha256: f9f48162f2553080d041b061b9f6cfec64d79d7c40df0e6379496f9ad2df738c md5: f602c096988d0f744f4f017aa0269e30 @@ -13243,6 +13879,24 @@ packages: - openjpeg >=2.5.4,<3.0a0 size: 391242 timestamp: 1788425045145 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.13-hbde042b_0.conda + sha256: 21c4f6c7f41dc9bec2ea2f9c80440d9a4d45a6f2ac13243e658f10dcf1044146 + md5: 680608784722880fbfe1745067570b00 + depends: + - __glibc >=2.17,<3.0.a0 + - cyrus-sasl >=2.1.28,<3.0a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=14 + - libstdcxx >=14 + - openssl >=3.5.6,<4.0a0 + license: OLDAP-2.8 + license_family: BSD + purls: [] + run_exports: + weak: + - openldap >=2.6.13,<2.7.0a0 + size: 786149 + timestamp: 1775741359582 - conda: https://conda.anaconda.org/conda-forge/linux-64/openmpi-5.0.10-hee33aa4_2.conda sha256: 20cafe96c3159bd328886552c45561dd52b6cdb844170c54189a1860a88d7997 md5: 7a082f0e3fe2002e187798fd2ed6b1de @@ -13680,6 +14334,33 @@ packages: run_exports: {} size: 5395858 timestamp: 1784258391353 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.11.2-py312hf143aa3_0.conda + sha256: 4e25d9259683126c377b219a741e081f7b8daa63aa256435d037cdaa3f453589 + md5: bfcdbf7dfa025bf855ffbf44181c143e + depends: + - python + - qt6-main 6.11.2.* + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - libstdcxx >=15 + - python_abi 3.12.* *_cp312 + - libclang13 >=22.1.8 + - libopengl >=1.7.0,<2.0a0 + - libgl >=1.7.0,<2.0a0 + - libegl >=1.7.0,<2.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - libvulkan-loader >=1.4.357.0,<2.0a0 + - qt6-main >=6.11.2,<7.0a0 + - libxslt >=1.1.43,<2.0a0 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/pyside6?source=hash-mapping + - pkg:pypi/shiboken6?source=hash-mapping + run_exports: {} + size: 13943954 + timestamp: 1787219437874 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.16-h5f976f7_2_cpython.conda build_number: 2 sha256: 35375a255970809e8b0a1c744d56533f4da5339769ef5f5a24fe165ca321fcf3 @@ -14287,6 +14968,82 @@ packages: - qhull >=2020.2,<2020.3.0a0 size: 552937 timestamp: 1720813982144 +- conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.11.2-pl5321h9df5c37_0.conda + sha256: 00d9bc98d04aeeab6f698ca7fe9d666b157ab39b52cad1af0fa346522705668d + md5: 2ff98660281d1c6bfebda5bffa52cc89 + depends: + - libxcb + - xcb-util + - xcb-util-wm + - xcb-util-keysyms + - xcb-util-image + - xcb-util-renderutil + - xcb-util-cursor + - libgl-devel + - libegl-devel + - libgcc >=15 + - libstdcxx >=15 + - __glibc >=2.17,<3.0.a0 + - libglib >=2.88.3,<3.0a0 + - libbrotlicommon >=1.2.0,<1.3.0a0 + - libbrotlienc >=1.2.0,<1.3.0a0 + - libbrotlidec >=1.2.0,<1.3.0a0 + - libvulkan-loader >=1.4.357.0,<2.0a0 + - wayland >=1.26.0,<2.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 + - libcups >=2.3.3,<2.4.0a0 + - alsa-lib >=1.2.16.1,<1.3.0a0 + - zstd >=1.5.7,<1.6.0a0 + - libtiff >=4.7.2,<4.8.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - dbus >=1.16.2,<2.0a0 + - libegl >=1.7.0,<2.0a0 + - xorg-libsm >=1.2.6,<2.0a0 + - xcb-util-wm >=0.4.2,<0.5.0a0 + - xorg-libice >=1.1.2,<2.0a0 + - xorg-libxxf86vm >=1.1.7,<2.0a0 + - double-conversion >=3.4.0,<3.5.0a0 + - icu >=78.3,<79.0a0 + - libwebp-base >=1.6.0,<2.0a0 + - krb5 >=1.22.2,<1.23.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 + - pcre2 >=10.47,<10.48.0a0 + - openssl >=3.5.7,<4.0a0 + - xorg-libxcomposite >=0.4.7,<1.0a0 + - libpng >=1.6.58,<1.7.0a0 + - libjpeg-turbo >=3.2.0,<4.0a0 + - libpq >=18.6,<19.0a0 + - libxcb >=1.17.0,<2.0a0 + - xcb-util >=0.4.1,<0.5.0a0 + - xcb-util-keysyms >=0.4.1,<0.5.0a0 + - xcb-util-renderutil >=0.3.10,<0.4.0a0 + - xcb-util-image >=0.4.0,<0.5.0a0 + - libharfbuzz >=14.3.1 + - fontconfig >=2.18.3,<3.0a0 + - fonts-conda-ecosystem + - xorg-libxdamage >=1.1.6,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - libgl >=1.7.0,<2.0a0 + - xorg-libxrandr >=1.5.5,<2.0a0 + - libsqlite >=3.53.4,<4.0a0 + - xcb-util-cursor >=0.1.6,<0.2.0a0 + - libxkbcommon >=1.13.2,<2.0a0 + - libfreetype >=2.14.3 + - libfreetype6 >=2.14.3 + - libdrm >=2.4.129,<2.5.0a0 + - xorg-libxext >=1.3.7,<2.0a0 + - xorg-libxtst >=1.2.5,<2.0a0 + constrains: + - qt ==6.11.2 + license: LGPL-3.0-only + license_family: LGPL + purls: [] + run_exports: + weak: + - qt6-main >=6.11.2,<7.0a0 + size: 60888449 + timestamp: 1787048975419 - conda: https://conda.anaconda.org/conda-forge/linux-64/rattler-build-0.74.0-hf01adef_1.conda sha256: 516a606bdaab6be626036a7a8f5e10db3d3b8a297b03ede0b93222bddce901d9 md5: 184a4c38cd3b9c5326147484450f14f7 @@ -14756,6 +15513,126 @@ packages: run_exports: {} size: 410641 timestamp: 1770909099497 +- conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.26.0-hc1c935e_2.conda + sha256: df65b987979e6d7f88e756494da5a230d4f2d08d17437d04eecd35559c3a04e4 + md5: 88a47e22b53e50865b1cabe2eb648352 + depends: + - __glibc >=2.17,<3.0.a0 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.7.0,<3.8.0a0 + - libgcc >=15 + - libstdcxx >=15 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - wayland >=1.26.0,<2.0a0 + size: 340058 + timestamp: 1787793849093 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda + sha256: ad8cab7e07e2af268449c2ce855cbb51f43f4664936eff679b1f3862e6e4b01d + md5: fdc27cb255a7a2cc73b7919a968b48f0 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libxcb >=1.17.0,<2.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xcb-util >=0.4.1,<0.5.0a0 + size: 20772 + timestamp: 1750436796633 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda + sha256: c2be9cae786fdb2df7c2387d2db31b285cf90ab3bfabda8fa75a596c3d20fc67 + md5: 4d1fc190b99912ed557a8236e958c559 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libxcb >=1.13 + - libxcb >=1.17.0,<2.0a0 + - xcb-util-image >=0.4.0,<0.5.0a0 + - xcb-util-renderutil >=0.3.10,<0.4.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xcb-util-cursor >=0.1.6,<0.2.0a0 + size: 20829 + timestamp: 1763366954390 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda + sha256: 94b12ff8b30260d9de4fd7a28cca12e028e572cbc504fd42aa2646ec4a5bded7 + md5: a0901183f08b6c7107aab109733a3c91 + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + - xcb-util >=0.4.1,<0.5.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xcb-util-image >=0.4.0,<0.5.0a0 + size: 24551 + timestamp: 1718880534789 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda + sha256: 546e3ee01e95a4c884b6401284bb22da449a2f4daf508d038fdfa0712fe4cc69 + md5: ad748ccca349aec3e91743e08b5e2b50 + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xcb-util-keysyms >=0.4.1,<0.5.0a0 + size: 14314 + timestamp: 1718846569232 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda + sha256: 2d401dadc43855971ce008344a4b5bd804aca9487d8ebd83328592217daca3df + md5: 0e0cbe0564d03a99afd5fd7b362feecd + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xcb-util-renderutil >=0.3.10,<0.4.0a0 + size: 16978 + timestamp: 1718848865819 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda + sha256: 31d44f297ad87a1e6510895740325a635dd204556aa7e079194a0034cdd7e66a + md5: 608e0ef8256b81d04456e8d211eee3e8 + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xcb-util-wm >=0.4.2,<0.5.0a0 + size: 51689 + timestamp: 1718844051451 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.48-h280c20c_0.conda + sha256: 3b04afd5d1a65d2d27ac2d49a63b01ab8bcd875776779ec63e337370ed38afdc + md5: b233b41be0bf210989d57160ed39b394 + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - xorg-libx11 >=1.8.13,<2.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: {} + size: 441670 + timestamp: 1782027360439 - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-h280c20c_0.conda sha256: 49b532d1df875c6749d9078b56a76f3f5db49a5abe0ca620b593ed474ef0ebf1 md5: 85c9442aec283b4e464fa9ecc484a2f3 @@ -14815,6 +15692,56 @@ packages: - xorg-libxau >=1.0.12,<2.0a0 size: 16419 timestamp: 1786381001122 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.7-hb03c661_0.conda + sha256: 048c103000af9541c919deef03ae7c5e9c570ffb4024b42ecb58dbde402e373a + md5: f2ba4192d38b6cef2bb2c25029071d90 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxfixes >=6.0.2,<7.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxcomposite >=0.4.7,<1.0a0 + size: 14415 + timestamp: 1770044404696 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + sha256: 832f538ade441b1eee863c8c91af9e69b356cd3e9e1350fff4fe36cc573fc91a + md5: 2ccd714aa2242315acaf0a67faea780b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + - xorg-libxrender >=0.9.11,<0.10.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxcursor >=1.2.3,<2.0a0 + size: 32533 + timestamp: 1730908305254 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda + sha256: 43b9772fd6582bf401846642c4635c47a9b0e36ca08116b3ec3df36ab96e0ec0 + md5: b5fcc7172d22516e1f965490e65e33a4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxdamage >=1.1.6,<2.0a0 + size: 13217 + timestamp: 1727891438799 - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_2.conda sha256: c50a16c05ccd7fe7dd6d6cfb539f4e9a491d50f9ed7a5c902fec638f7d0d27be md5: 2e66c929f3d879708335b6ea4557c838 @@ -14844,6 +15771,55 @@ packages: - xorg-libxext >=1.3.7,<2.0a0 size: 53124 timestamp: 1787100841900 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.2-h7cc23a3_1.conda + sha256: aec84f554fc897bf4085c7bc8b8f0740e4c224e13bca3cc51c93e7699d56f83a + md5: 09132e874fe0e1f5e4492b0b6b904b6e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - xorg-libx11 >=1.8.13,<2.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxfixes >=6.0.2,<7.0a0 + size: 21440 + timestamp: 1787248059682 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.3-h7cc23a3_1.conda + sha256: a523d71344a2f640efe6fc42b88fc261d9cd389d4f9838a5d42dcdb120c2b0c8 + md5: a1412b2b1184dacda45f8476fef2cc25 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - xorg-libx11 >=1.8.13,<2.0a0 + - xorg-libxext >=1.3.7,<2.0a0 + - xorg-libxfixes >=6.0.2,<7.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxi >=1.8.3,<2.0a0 + size: 49165 + timestamp: 1787257060460 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.5-h7cc23a3_1.conda + sha256: 05a7f25d7f7f5cd32b27a019233ece97167fd8ade255bc13a0e49e53387f4c30 + md5: 798a8c9d171859a022e1cb89e7d0eb10 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - xorg-libx11 >=1.8.13,<2.0a0 + - xorg-libxext >=1.3.7,<2.0a0 + - xorg-libxrender >=0.9.12,<0.10.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxrandr >=1.5.5,<2.0a0 + size: 31106 + timestamp: 1787246614086 - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb03c661_1.conda sha256: 6901f91d398811e4ec89d7e20a69abac02a7bfebfaf073338b7ea3d1a99685b7 md5: e470d224a7a5be1b1d021bded7abb536 @@ -14859,6 +15835,51 @@ packages: - xorg-libxrender >=0.9.12,<0.10.0a0 size: 34645 timestamp: 1787100191192 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-h7cc23a3_4.conda + sha256: d66525e7b1c492aa179c6c55610fc8dfb0a9a62ea7d4fb9f904fa6af62127f61 + md5: 752a5ac9322e0fbbc24146c1ce3ae44e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + - xorg-libx11 >=1.8.13,<2.0a0 + - xorg-libxext >=1.3.7,<2.0a0 + - xorg-libxi >=1.8.3,<2.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxtst >=1.2.5,<2.0a0 + size: 35052 + timestamp: 1787360025506 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.7-hb03c661_0.conda + sha256: 64db17baaf36fa03ed8fae105e2e671a7383e22df4077486646f7dbf12842c9f + md5: 665d152b9c6e78da404086088077c844 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - xorg-libxxf86vm >=1.1.7,<2.0a0 + size: 18701 + timestamp: 1769434732453 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2025.1-hebe6cf0_2.conda + sha256: 28be920cbb36bb674f66a23f368b67733dbbb89b2321e5ed7266d9b415156795 + md5: 7386d38083163c5b5c4a92a1582daaef + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15 + license: MIT + license_family: MIT + purls: [] + run_exports: {} + size: 594980 + timestamp: 1788447117643 - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-hebe6cf0_3.conda sha256: d164dfa75ecd538f6fd68765defcc06aa875bc697b9b215362d79a2a73125dd0 md5: e741576fb8f89821ac7c1c537322a33d diff --git a/pixi.toml b/pixi.toml index 80616892..11ad0a88 100644 --- a/pixi.toml +++ b/pixi.toml @@ -128,6 +128,11 @@ types-PyYAML = "*" memray = "*" py-spy = "*" +[feature.interactive.dependencies] +ipykernel = "*" +ipython = "*" +matplotlib = "*" + [feature.benchmark.dependencies] jinja2 = "*" markdown-it-py = "*" @@ -296,14 +301,15 @@ skalaxc-doxygen = { cmd = "cmake -DSKALAXC_DOXYGEN_SOURCE_DIR=$PIXI_PROJECT_ROOT [environments] default = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-cpu", "test", "lint", "profiling", "benchmark"], no-default-feature = true, platforms = ["linux-64", "linux-aarch64", "osx-arm64"] } +dev = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-12", "test", "lint", "profiling", "benchmark", "interactive"], no-default-feature = true, platforms = ["linux-64-cuda12"] } lint = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-cpu", "test", "lint", "profiling", "benchmark"], no-default-feature = true, platforms = ["linux-64"] } test-py311-pyscf214-torch213 = { features = ["python-runtime", "model-assets", "python-311", "pyscf-214", "dispersion", "torch-213-cpu", "test"], no-default-feature = true, platforms = ["linux-64"] } test-py312-pyscf214-torch212 = { features = ["python-runtime", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-212-cpu", "test", "profiling", "benchmark"], no-default-feature = true, platforms = ["linux-64", "linux-aarch64", "osx-arm64"] } test-py312-pyscf214-torch213 = { features = ["python-runtime", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-cpu", "test", "profiling", "benchmark"], no-default-feature = true, platforms = ["linux-64", "linux-aarch64", "osx-arm64"] } test-py313-pyscf214-torch213 = { features = ["python-runtime", "model-assets", "python-313", "pyscf-214", "dispersion", "torch-213-cpu", "test"], no-default-feature = true, platforms = ["linux-64"] } -gpu-cuda12-torch212 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-212-gpu", "cuda-12", "test", "benchmark","profiling"], no-default-feature = true, platforms = ["linux-64-cuda12"] } -gpu-cuda12-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-12", "test", "benchmark","profiling"], no-default-feature = true, platforms = ["linux-64-cuda12"] } -gpu-cuda13-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-13", "test", "benchmark","profiling"], no-default-feature = true, platforms = ["linux-64-cuda13"] } +gpu-cuda12-torch212 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-212-gpu", "cuda-12", "test", "benchmark"], no-default-feature = true, platforms = ["linux-64-cuda12"] } +gpu-cuda12-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-12", "test", "benchmark"], no-default-feature = true, platforms = ["linux-64-cuda12"] } +gpu-cuda13-torch213 = { features = ["python-runtime", "model-definition", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-gpu", "cuda-13", "test", "benchmark"], no-default-feature = true, platforms = ["linux-64-cuda13"] } docs = { features = ["python-runtime", "component-sources", "model-assets", "python-312", "pyscf-214", "dispersion", "torch-213-cpu", "benchmark", "docs"], no-default-feature = true, platforms = ["linux-64"] } assets = { features = ["python-312", "model-assets"], no-default-feature = true, platforms = ["linux-64"] } release = { features = ["python-312", "release"], no-default-feature = true, platforms = ["linux-64"] } diff --git a/skala/README.md b/skala/README.md index 73740500..9af42eda 100644 --- a/skala/README.md +++ b/skala/README.md @@ -77,7 +77,8 @@ pip install skala-cuda12x The `skala-cuda13x` package is available for CUDA 13. -For a reproducible source environment, choose one of the locked GPU environments: +For a reproducible source environment, choose one of the locked GPU compatibility +environments: | Environment | CUDA | PyTorch | |---|---:|---:| diff --git a/website/installation.rst b/website/installation.rst index 1bcd56e6..2b18f4a7 100644 --- a/website/installation.rst +++ b/website/installation.rst @@ -64,6 +64,14 @@ always use the selected environment: Set ``OMP_NUM_THREADS=4`` when running tests locally to match CI. +On Linux x86_64 with a CUDA 12-compatible driver, install the GPU-enabled +development superset with profiling and interactive analysis tools: + +.. code-block:: bash + + pixi install --locked -e dev + pixi run -e dev ipython + The locked compatibility environments are: .. list-table:: diff --git a/website/pyscf/gpu4pyscf.rst b/website/pyscf/gpu4pyscf.rst index 663ec7bd..68c02012 100644 --- a/website/pyscf/gpu4pyscf.rst +++ b/website/pyscf/gpu4pyscf.rst @@ -22,9 +22,9 @@ The Skala functional can also be used in GPU4PySCF with an appropriate PyTorch C Installation ------------ -The repository provides three locked GPU environments. They combine conda-forge -PyTorch and CUDA libraries with PyPI PySCF and the latest tested GPU4PySCF -release, 1.8.1: +The repository provides three locked GPU compatibility environments. They +combine conda-forge PyTorch and CUDA libraries with PyPI PySCF and the latest +tested GPU4PySCF release, 1.8.1: * ``gpu-cuda12-torch212`` * ``gpu-cuda12-torch213`` From 266dba2d0e4f6a33932d1d66ab53bb857047f561 Mon Sep 17 00:00:00 2001 From: jenswehner Date: Wed, 9 Sep 2026 23:10:38 +0200 Subject: [PATCH 4/4] wip skalaxc benchmark extension --- .../pyscf_ao_screening_performance.ipynb | 103 +++- ...scf_ao_screening_rotation_comparison.ipynb | 75 ++- .../run_pyscf_ao_screening_benchmark.py | 514 +++++++++++++++--- ...n_pyscf_ao_screening_rotation_benchmark.py | 209 ++++--- pixi.lock | 144 +++++ pixi.toml | 8 +- 6 files changed, 877 insertions(+), 176 deletions(-) diff --git a/benchmarks/pyscf_ao_screening_performance.ipynb b/benchmarks/pyscf_ao_screening_performance.ipynb index d7114c2d..177feba7 100644 --- a/benchmarks/pyscf_ao_screening_performance.ipynb +++ b/benchmarks/pyscf_ao_screening_performance.ipynb @@ -49,12 +49,20 @@ "\n", "MODES = (\"cpu\", \"cpu_dense\", \"gpu\")\n", "MEASUREMENTS = (\"runtime\", \"memory\")\n", - "TERMINAL_STATUSES = {\"ok\", \"timeout\", \"oom\", \"error\", \"skipped_after_resource_failure\"}\n", + "TERMINAL_STATUSES = {\n", + " \"ok\",\n", + " \"timeout\",\n", + " \"oom\",\n", + " \"error\",\n", + " \"unsupported\",\n", + " \"skipped_after_resource_failure\",\n", + "}\n", "SCIENTIFIC_CONFIG_KEYS = (\n", " \"functional\",\n", " \"basis\",\n", " \"grid_level\",\n", " \"grid_alignment\",\n", + " \"skalaxc_grid_size\",\n", " \"max_memory_mb\",\n", " \"cpu_threads\",\n", " \"full_carbon_counts\",\n", @@ -73,6 +81,11 @@ "\n", "def is_molecule_benchmark_result(path: Path) -> bool:\n", " document = json.loads(path.read_text(encoding=\"utf-8\"))\n", + " if document.get(\"schema_version\") == 2:\n", + " return isinstance(\n", + " document.get(\"implementations\", {}).get(\"skala\", {}).get(\"molecules\"),\n", + " dict,\n", + " )\n", " return isinstance(document.get(\"molecules\"), dict)\n", "\n", "\n", @@ -112,9 +125,34 @@ "metadata": {}, "outputs": [], "source": [ + "def implementation_view(\n", + " document: dict[str, Any], implementation: str\n", + ") -> dict[str, Any] | None:\n", + " schema_version = document.get(\"schema_version\")\n", + " if schema_version == 1:\n", + " if implementation != \"skala\" or not isinstance(document.get(\"molecules\"), dict):\n", + " return None\n", + " view = dict(document)\n", + " view[\"implementation\"] = \"skala\"\n", + " view[\"modes\"] = list(MODES)\n", + " return view\n", + " if schema_version != 2:\n", + " return None\n", + " implementation_record = document.get(\"implementations\", {}).get(implementation)\n", + " if not isinstance(implementation_record, dict):\n", + " return None\n", + " view = dict(document)\n", + " view[\"implementation\"] = implementation\n", + " view[\"molecules\"] = implementation_record.get(\"molecules\", {})\n", + " view[\"modes\"] = implementation_record.get(\"modes\", [])\n", + " if implementation != \"skala\":\n", + " view[\"run_label\"] = f\"{document['run_label']}:{implementation}\"\n", + " return view\n", + "\n", + "\n", "def validate_result_document(document: dict[str, Any]) -> list[str]:\n", " errors: list[str] = []\n", - " if document.get(\"schema_version\") != 1:\n", + " if document.get(\"schema_version\") not in {1, 2}:\n", " errors.append(f\"Unsupported schema version: {document.get('schema_version')}\")\n", " for formula, molecule in document.get(\"molecules\", {}).items():\n", " observed = molecule.get(\"observed\")\n", @@ -151,6 +189,8 @@ "\n", "def fingerprint_warnings(document: dict[str, Any]) -> list[str]:\n", " messages: list[str] = []\n", + " if \"cpu_dense\" not in document.get(\"modes\", []):\n", + " return messages\n", " for formula, molecule in document[\"molecules\"].items():\n", " reference = preferred_fingerprint(molecule[\"modes\"][\"cpu_dense\"])\n", " if reference is None:\n", @@ -162,7 +202,7 @@ " production = preferred_fingerprint(molecule[\"modes\"][production_mode])\n", " if production is None:\n", " continue\n", - " for key in production:\n", + " for key in production.keys() & reference.keys():\n", " if not np.isclose(\n", " production[key], reference[key], rtol=rtol, atol=atol\n", " ):\n", @@ -223,39 +263,78 @@ " return messages\n", "\n", "\n", - "def load_result_documents(paths: list[Path]) -> list[dict[str, Any]]:\n", - " documents = [json.loads(path.read_text(encoding=\"utf-8\")) for path in paths]\n", + "def load_result_documents(\n", + " paths: list[Path], implementation: str\n", + ") -> list[dict[str, Any]]:\n", + " raw_documents = [json.loads(path.read_text(encoding=\"utf-8\")) for path in paths]\n", + " documents = [\n", + " view\n", + " for document in raw_documents\n", + " if (view := implementation_view(document, implementation)) is not None\n", + " ]\n", " messages = comparison_warnings(documents)\n", " if messages:\n", - " print(\"Comparison warnings:\")\n", + " print(f\"{implementation} comparison warnings:\")\n", " for message in messages:\n", " print(f\" WARNING: {message}\")\n", " return documents\n", "\n", "\n", "def print_status_table(documents: list[dict[str, Any]]) -> None:\n", - " header = f\"{'label':10s} {'formula':9s} {'AOs':>5s} {'mode':10s} {'runtime':12s} {'memory':12s}\"\n", + " header = (\n", + " f\"{'label':18s} {'formula':9s} {'AOs':>5s} {'mode':10s} \"\n", + " f\"{'runtime':12s} {'memory':12s}\"\n", + " )\n", " print(header)\n", " print(\"-\" * len(header))\n", " for document in documents:\n", " for molecule in document[\"molecules\"].values():\n", " observed = molecule.get(\"observed\") or {}\n", " aos = observed.get(\"actual_aos\", molecule[\"expected_aos\"])\n", - " for mode in MODES:\n", + " for mode in document.get(\"modes\", MODES):\n", " mode_record = molecule[\"modes\"][mode]\n", " runtime_status = mode_record.get(\"runtime\", {}).get(\"status\", \"pending\")\n", " memory_status = mode_record.get(\"memory\", {}).get(\"status\", \"pending\")\n", " print(\n", - " f\"{document['run_label'][:10]:10s} {molecule['formula']:9s} {aos:5d} \"\n", + " f\"{document['run_label'][:18]:18s} {molecule['formula']:9s} {aos:5d} \"\n", " f\"{mode:10s} {runtime_status:12s} {memory_status:12s}\"\n", " )\n", "\n", "\n", + "def print_skalaxc_grid_table(documents: list[dict[str, Any]]) -> None:\n", + " if not documents:\n", + " return\n", + " print(\"\\nSkalaXC/PySCF grid comparison:\")\n", + " print(\n", + " f\"{'label':18s} {'formula':9s} {'grid':12s} {'PySCF':>10s} {'SkalaXC':>10s} {'ratio':>8s}\"\n", + " )\n", + " for document in documents:\n", + " for molecule in document[\"molecules\"].values():\n", + " observed = molecule.get(\"observed\") or {}\n", + " if not observed:\n", + " continue\n", + " print(\n", + " f\"{document['run_label'][:18]:18s} {molecule['formula']:9s} \"\n", + " f\"{str(observed.get('grid_size', '')):12s} \"\n", + " f\"{int(observed.get('pyscf_grid_points', 0)):10d} \"\n", + " f\"{int(observed.get('grid_points', 0)):10d} \"\n", + " f\"{float(observed.get('grid_point_ratio', np.nan)):8.3f}\"\n", + " )\n", + "\n", + "\n", "SELECTED_DOCUMENTS = (\n", - " load_result_documents(SELECTED_RESULT_FILES) if SELECTED_RESULT_FILES else []\n", + " load_result_documents(SELECTED_RESULT_FILES, \"skala\")\n", + " if SELECTED_RESULT_FILES\n", + " else []\n", + ")\n", + "SKALAXC_DOCUMENTS = (\n", + " load_result_documents(SELECTED_RESULT_FILES, \"skalaxc\")\n", + " if SELECTED_RESULT_FILES\n", + " else []\n", ")\n", - "if SELECTED_DOCUMENTS:\n", - " print_status_table(SELECTED_DOCUMENTS)\n", + "if SELECTED_DOCUMENTS or SKALAXC_DOCUMENTS:\n", + " print_status_table([*SELECTED_DOCUMENTS, *SKALAXC_DOCUMENTS])\n", + " print_skalaxc_grid_table(SKALAXC_DOCUMENTS)\n", "else:\n", " print(\"No benchmark result files were found. Run the benchmark script first.\")" ] diff --git a/benchmarks/pyscf_ao_screening_rotation_comparison.ipynb b/benchmarks/pyscf_ao_screening_rotation_comparison.ipynb index bf938326..d4e2cdcd 100644 --- a/benchmarks/pyscf_ao_screening_rotation_comparison.ipynb +++ b/benchmarks/pyscf_ao_screening_rotation_comparison.ipynb @@ -54,6 +54,7 @@ "import seaborn as sns\n", "\n", "MODES = (\"gpu\", \"cpu_dense\", \"cpu_screened\")\n", + "SKALAXC_MODES = (\"cpu\", \"gpu\")\n", "MEASUREMENTS = (\"runtime\", \"memory\")\n", "REFERENCE_MODE = \"cpu_dense\"\n", "EXPECTED_AOS = 879\n", @@ -67,6 +68,7 @@ " \"timeout\",\n", " \"oom\",\n", " \"error\",\n", + " \"unsupported\",\n", " \"skipped_after_resource_failure\",\n", "}\n", "FINGERPRINT_LABELS = {\n", @@ -179,6 +181,33 @@ "]\n", "\n", "\n", + "def rotation_implementation_view(\n", + " document: dict[str, Any], implementation: str\n", + ") -> dict[str, Any] | None:\n", + " schema_version = document.get(\"schema_version\")\n", + " if schema_version == 1:\n", + " if implementation != \"skala\" or not isinstance(\n", + " document.get(\"orientations\"), dict\n", + " ):\n", + " return None\n", + " view = dict(document)\n", + " view[\"implementation\"] = \"skala\"\n", + " view[\"modes\"] = list(MODES)\n", + " return view\n", + " if schema_version != 2:\n", + " return None\n", + " implementation_record = document.get(\"implementations\", {}).get(implementation)\n", + " if not isinstance(implementation_record, dict):\n", + " return None\n", + " view = dict(document)\n", + " view[\"implementation\"] = implementation\n", + " view[\"orientations\"] = implementation_record.get(\"orientations\", {})\n", + " view[\"modes\"] = implementation_record.get(\"modes\", [])\n", + " if implementation != \"skala\":\n", + " view[\"run_label\"] = f\"{document['run_label']}:{implementation}\"\n", + " return view\n", + "\n", + "\n", "def validate_document(path: Path, document: dict[str, Any]) -> list[str]:\n", " failures: list[str] = []\n", " required_fields = {\n", @@ -194,13 +223,13 @@ " missing_fields = sorted(required_fields - document.keys())\n", " if missing_fields:\n", " failures.append(f\"missing top-level fields: {missing_fields}\")\n", - " if document.get(\"schema_version\") != 1:\n", + " if document.get(\"schema_version\") not in {1, 2}:\n", " failures.append(f\"unsupported schema version {document.get('schema_version')}\")\n", " if document.get(\"benchmark\") != \"pyscf_ao_screening_rotations\":\n", " failures.append(f\"unexpected benchmark marker {document.get('benchmark')!r}\")\n", "\n", " configuration = document.get(\"configuration\", {})\n", - " configured_modes = tuple(configuration.get(\"modes\", ()))\n", + " configured_modes = tuple(document.get(\"modes\", ()))\n", " configured_measurements = tuple(configuration.get(\"measurements\", ()))\n", " if configured_modes and configured_modes != MODES:\n", " failures.append(f\"configured modes are {configured_modes}, expected {MODES}\")\n", @@ -342,18 +371,55 @@ " return rows\n", "\n", "\n", + "def print_skalaxc_rotation_summary(\n", + " documents: list[tuple[Path, dict[str, Any]]],\n", + ") -> None:\n", + " if not documents:\n", + " return\n", + " print(\"SkalaXC rotation grid summary:\")\n", + " print(\n", + " f\"{'run':22s} {'orientations':>12s} {'grid':12s} \"\n", + " f\"{'PySCF':>10s} {'SkalaXC':>10s} {'ratio':>8s}\"\n", + " )\n", + " for _, document in documents:\n", + " orientations = document.get(\"orientations\", {})\n", + " observed_records = [\n", + " orientation.get(\"observed\") or {}\n", + " for orientation in orientations.values()\n", + " if orientation.get(\"observed\")\n", + " ]\n", + " observed = observed_records[0] if observed_records else {}\n", + " print(\n", + " f\"{document['run_label'][:22]:22s} {len(orientations):12d} \"\n", + " f\"{str(observed.get('grid_size', 'pending')):12s} \"\n", + " f\"{int(observed.get('pyscf_grid_points', 0)):10d} \"\n", + " f\"{int(observed.get('grid_points', 0)):10d} \"\n", + " f\"{float(observed.get('grid_point_ratio', np.nan)):8.3f}\"\n", + " )\n", + "\n", + "\n", "DOCUMENTS: list[tuple[Path, dict[str, Any]]] = []\n", + "SKALAXC_DOCUMENTS: list[tuple[Path, dict[str, Any]]] = []\n", "validation_rows: list[dict[str, str]] = []\n", "normalized_rows: list[dict[str, Any]] = []\n", "for result_file in SELECTED_RESULT_FILES:\n", " try:\n", - " document = json.loads(result_file.read_text(encoding=\"utf-8\"))\n", + " raw_document = json.loads(result_file.read_text(encoding=\"utf-8\"))\n", " except (OSError, json.JSONDecodeError) as error:\n", " validation_rows.append(\n", " {\"run_label\": result_file.stem, \"failure\": f\"could not load: {error}\"}\n", " )\n", " continue\n", + " document = rotation_implementation_view(raw_document, \"skala\")\n", + " if document is None:\n", + " validation_rows.append(\n", + " {\"run_label\": result_file.stem, \"failure\": \"missing Skala results\"}\n", + " )\n", + " continue\n", " DOCUMENTS.append((result_file, document))\n", + " skalaxc_document = rotation_implementation_view(raw_document, \"skalaxc\")\n", + " if skalaxc_document is not None:\n", + " SKALAXC_DOCUMENTS.append((result_file, skalaxc_document))\n", " normalized_rows.extend(normalize_document(result_file, document))\n", " failures = validate_document(result_file, document)\n", " run_label = str(document.get(\"run_label\") or result_file.stem)\n", @@ -374,8 +440,9 @@ "validation_df = pd.DataFrame(validation_rows, columns=[\"run_label\", \"failure\"])\n", "if DOCUMENTS:\n", " print(\n", - " f\"Loaded {len(DOCUMENTS)} document(s) and {len(normalized_df)} normalized rows\"\n", + " f\"Loaded {len(DOCUMENTS)} document(s) and {len(normalized_df)} normalized Skala rows\"\n", " )\n", + " print_skalaxc_rotation_summary(SKALAXC_DOCUMENTS)\n", "else:\n", " print(\"No rotation benchmark JSON files found. Run the benchmark first.\")\n", "display(\n", diff --git a/benchmarks/run_pyscf_ao_screening_benchmark.py b/benchmarks/run_pyscf_ao_screening_benchmark.py index 492a5351..8bbec288 100644 --- a/benchmarks/run_pyscf_ao_screening_benchmark.py +++ b/benchmarks/run_pyscf_ao_screening_benchmark.py @@ -4,6 +4,7 @@ import argparse import hashlib +import importlib import importlib.metadata import inspect import json @@ -39,9 +40,22 @@ 1347, 1464, ) -MODES = ("cpu", "cpu_dense", "gpu") +SKALA_MODES = ("cpu", "cpu_dense", "gpu") +SKALAXC_MODES = ("cpu", "gpu") +MODES = SKALA_MODES +IMPLEMENTATION_MODES = { + "skala": SKALA_MODES, + "skalaxc": SKALAXC_MODES, +} MEASUREMENTS = ("runtime", "memory") -TERMINAL_STATUSES = {"ok", "timeout", "oom", "error", "skipped_after_resource_failure"} +TERMINAL_STATUSES = { + "ok", + "timeout", + "oom", + "error", + "unsupported", + "skipped_after_resource_failure", +} WORKER_RESULT_PREFIX = "SKALA_BENCHMARK_RESULT=" THREAD_ENVIRONMENT_VARIABLES = ( "OMP_NUM_THREADS", @@ -89,6 +103,7 @@ class BenchmarkConfig: results_dir: Path run_label: str functional: str = "skala-1.1" + skalaxc_grid_size: str = "GM3" basis: str = "def2-qzvpp" grid_level: int = 1 grid_alignment: int = 1 @@ -308,6 +323,13 @@ def verify_skala_import(source_root: Path) -> str: return str(imported_path) +def module_path(module: Any) -> Path: + module_file = getattr(module, "__file__", None) + if module_file is None: + raise RuntimeError(f"Module {module.__name__} has no filesystem path") + return Path(module_file).resolve() + + def collect_environment(payload: dict[str, Any]) -> dict[str, Any]: import torch @@ -319,6 +341,26 @@ def collect_environment(payload: dict[str, Any]) -> dict[str, Any]: gpu_name = torch.cuda.get_device_name(0) if cuda_available else None cupy_version = package_version("cupy-cuda12x") or package_version("cupy") torch_cuda_version = getattr(getattr(torch, "version", None), "cuda", None) + try: + skalaxc = importlib.import_module("skalaxc") + + skalaxc_environment: dict[str, Any] = { + "available": True, + "module": str(module_path(skalaxc)), + "version": skalaxc.__version__, + "native_version": skalaxc.native_version(), + "cuda_enabled": bool(skalaxc.CUDA_ENABLED), + "cuda_toolkit_version": skalaxc.CUDA_TOOLKIT_VERSION, + "mpi_enabled": bool(skalaxc.MPI_ENABLED), + "openmp_enabled": bool(skalaxc.OPENMP_ENABLED), + "hdf5_enabled": getattr(skalaxc, "HDF5_ENABLED", None), + "model_dir": str(Path(skalaxc.MODEL_DIR).resolve()), + } + except (ImportError, OSError) as error: + skalaxc_environment = { + "available": False, + "error": f"{type(error).__name__}: {error}", + } return { "python": sys.version, "python_executable": sys.executable, @@ -336,7 +378,9 @@ def collect_environment(payload: dict[str, Any]) -> dict[str, Any]: "torch": torch.__version__, "cupy": cupy_version, "memray": package_version("memray"), + "skalaxc": package_version("skalaxc"), }, + "skalaxc": skalaxc_environment, "cuda": { "available": cuda_available, "torch_cuda_version": torch_cuda_version, @@ -456,7 +500,240 @@ def route_metadata(numint: Any, mol: Any, forced_dense: bool) -> dict[str, Any]: } +def _enum_name(value: Any) -> str: + name = getattr(value, "name", None) + return str(name) if name is not None else str(value).rsplit(".", 1)[-1] + + +def _pyscf_to_skalaxc(pyscf_molecule: Any, skalaxc: Any) -> tuple[Any, Any]: + molecule = skalaxc.Molecule() + coordinates = pyscf_molecule.atom_coords(unit="Bohr") + for atomic_number, center in zip( + pyscf_molecule.atom_charges(), coordinates, strict=True + ): + molecule.append( + skalaxc.Atom( + int(atomic_number), + float(center[0]), + float(center[1]), + float(center[2]), + ) + ) + + basis = skalaxc.BasisSet() + for atom_index, (atom_label, _) in enumerate(pyscf_molecule._atom): + center = coordinates[atom_index].tolist() + for pyscf_shell in pyscf_molecule._basis[atom_label]: + angular_momentum = int(pyscf_shell[0]) + primitives = pyscf_shell[1:] + exponents = [float(primitive[0]) for primitive in primitives] + for contraction_index in range(1, len(primitives[0])): + coefficients = [ + float(primitive[contraction_index]) for primitive in primitives + ] + basis.append( + skalaxc.Shell( + angular_momentum, + not pyscf_molecule.cart and angular_momentum != 1, + exponents, + coefficients, + center, + normalize=True, + ) + ) + return molecule, basis + + +def _closed_shell_density_channels(density: Any) -> tuple[Any, Any]: + import numpy as np + + scalar_density = np.asfortranarray(density, dtype=np.float64) + if scalar_density.ndim != 2 or scalar_density.shape[0] != scalar_density.shape[1]: + raise ValueError( + f"Expected a square RKS density matrix, got {scalar_density.shape}" + ) + return scalar_density, np.zeros_like(scalar_density, order="F") + + +def _resolve_skalaxc_model(functional: str, skalaxc: Any) -> str: + if functional.lower() in {"lda", "pbe", "tpss"}: + return functional.upper() + model_path = Path(skalaxc.MODEL_DIR) / f"{functional}.fun" + if not model_path.is_file(): + raise FileNotFoundError( + f"SkalaXC model for {functional!r} was not found at {model_path}" + ) + return str(model_path) + + +def _resolve_skalaxc_grid_size(name: str, skalaxc: Any) -> Any: + normalized = name.upper().replace("-", "_") + try: + return getattr(skalaxc.AtomicGridSize, normalized) + except AttributeError as error: + choices = ("FINE", "ULTRA_FINE", "SUPER_FINE", "GM3", "GM5") + raise ValueError( + f"Unknown SkalaXC grid size {name!r}; choose from {', '.join(choices)}" + ) from error + + +def _skalaxc_diagnostics(integrator: Any) -> dict[str, Any]: + diagnostics = integrator.diagnostics() + return { + "backend": _enum_name(diagnostics.backend), + "rank": int(diagnostics.rank), + "communicator_size": int(diagnostics.communicator_size), + "device_id": int(diagnostics.device_id), + "openmp_threads": int(diagnostics.openmp_threads), + "device_memory_fraction": float(diagnostics.device_memory_fraction), + "exc_vxc_calls": int(diagnostics.exc_vxc_calls), + "model_batches": int(diagnostics.model_batches), + "domains": int(diagnostics.domains), + "tasks": int(diagnostics.tasks), + "points": int(diagnostics.points), + "local_atoms": int(diagnostics.local_atoms), + } + + +def _build_skalaxc_case(payload: dict[str, Any]) -> dict[str, Any]: + import numpy as np + import torch + from skala.pyscf.grids import SkalaGrids + + from pyscf import dft, gto, lib + + source_root = Path(payload["source_root"]).resolve() + skalaxc = importlib.import_module("skalaxc") + imported_skala = verify_skala_import(source_root) + thread_count = int(payload["cpu_threads"]) + lib.num_threads(thread_count) + torch.set_num_threads(thread_count) + + molecule_spec = payload["molecule"] + mol = gto.M( + atom=molecule_spec["atom_text"], + basis=payload["basis"], + charge=0, + spin=0, + unit="Angstrom", + cart=False, + verbose=0, + ) + initial_density = dft.RKS(mol).get_init_guess() + scalar_density, spin_density = _closed_shell_density_channels(initial_density) + + reference_grid = SkalaGrids(mol) + reference_grid.level = int(payload["grid_level"]) + reference_grid.alignment = int(payload["grid_alignment"]) + reference_grid.build(sort_grids=False) + if reference_grid.weights is None: + raise RuntimeError("PySCF reference grid construction did not produce weights") + pyscf_grid_points = int(reference_grid.weights.size) + + backend = payload["backend"] + if backend == "cpu": + execution_space = skalaxc.ExecutionSpace.HOST + + def synchronize() -> None: + return None + + elif backend == "gpu": + if not bool(skalaxc.CUDA_ENABLED): + raise RuntimeError("SkalaXC was built without CUDA support") + execution_space = skalaxc.ExecutionSpace.DEVICE + synchronize = torch.cuda.synchronize + else: + raise ValueError(f"Unknown backend: {backend}") + + molecule, basis = _pyscf_to_skalaxc(mol, skalaxc) + grid_size = _resolve_skalaxc_grid_size(payload["skalaxc_grid_size"], skalaxc) + grid = skalaxc.MolGridFactory.create_default( + molecule, + pruning_scheme=skalaxc.PruningScheme.UNPRUNED, + radial_quad=skalaxc.RadialQuad.MURA_KNOWLES, + grid_size=grid_size, + ) + + if backend == "gpu": + device_settings = skalaxc.DeviceRuntimeSettings() + if skalaxc.MPI_ENABLED: + MPI = importlib.import_module("mpi4py").MPI + + runtime = skalaxc.RuntimeEnvironment(MPI.COMM_SELF, device_settings) + else: + runtime = skalaxc.RuntimeEnvironment(device_settings) + elif skalaxc.MPI_ENABLED: + MPI = importlib.import_module("mpi4py").MPI + + runtime = skalaxc.RuntimeEnvironment(MPI.COMM_SELF) + else: + runtime = skalaxc.RuntimeEnvironment() + + load_balancer = skalaxc.LoadBalancerFactory(execution_space).get_instance( + runtime, molecule, grid, basis + ) + weights = skalaxc.MolecularWeightsFactory(execution_space).get_instance() + weights.modify_weights(load_balancer) + model = _resolve_skalaxc_model(payload["functional"], skalaxc) + integrator = skalaxc.XCIntegratorFactory(execution_space).get_instance( + skalaxc.Functional(model), load_balancer + ) + initial_diagnostics = _skalaxc_diagnostics(integrator) + skalaxc_grid_points = int(initial_diagnostics["points"]) + + def evaluate() -> tuple[Any, Any, Any]: + return cast( + tuple[Any, Any, Any], + integrator.eval_exc_vxc(scalar_density, spin_density), + ) + + def make_fingerprint(result: tuple[Any, Any, Any]) -> dict[str, float]: + xc_energy, scalar_potential, spin_potential = result + scalar_matrix = np.asarray(scalar_potential, dtype=np.float64) + spin_matrix = np.asarray(spin_potential, dtype=np.float64) + return { + "xc_energy": float(xc_energy), + "vxc_sum": float(scalar_matrix.sum()), + "vxc_trace": float(np.trace(scalar_matrix)), + "vxc_frobenius_norm": float(np.linalg.norm(scalar_matrix)), + "vxc_max_abs": float(np.max(np.abs(scalar_matrix))), + "spin_vxc_frobenius_norm": float(np.linalg.norm(spin_matrix)), + } + + point_difference = skalaxc_grid_points - pyscf_grid_points + system = { + "formula": molecule_spec["formula"], + "carbon_count": int(molecule_spec["carbon_count"]), + "electron_count": int(mol.nelectron), + "actual_aos": int(mol.nao_nr()), + "grid_points": skalaxc_grid_points, + "pyscf_grid_points": pyscf_grid_points, + "grid_point_difference": point_difference, + "grid_point_ratio": skalaxc_grid_points / pyscf_grid_points, + "grid_size": _enum_name(grid_size), + "coordinate_sha256": molecule_spec["coordinate_sha256"], + "imported_skala": imported_skala, + "imported_skalaxc": str(module_path(skalaxc)), + "skalaxc_model": model, + } + return { + "backend": backend, + "evaluate": evaluate, + "make_fingerprint": make_fingerprint, + "synchronize": synchronize, + "route": None, + "diagnostics": lambda: _skalaxc_diagnostics(integrator), + "system": system, + } + + def build_case(payload: dict[str, Any]) -> dict[str, Any]: + implementation = payload.get("implementation", "skala") + if implementation == "skalaxc": + return _build_skalaxc_case(payload) + if implementation != "skala": + raise ValueError(f"Unknown implementation: {implementation}") + import numpy as np import torch @@ -512,6 +789,19 @@ def synchronize() -> None: numint = ks._numint forced_dense = bool(payload["forced_dense"]) route = route_metadata(numint, mol, forced_dense) + + def evaluate() -> tuple[Any, Any, Any]: + return numint.nr_rks( + mol, + ks.grids, + None, + dm, + max_memory=int(payload["max_memory_mb"]), + ) + + def make_fingerprint(result: tuple[Any, Any, Any]) -> dict[str, float]: + return fingerprint(result, to_numpy) + system = { "formula": molecule["formula"], "carbon_count": int(molecule["carbon_count"]), @@ -527,6 +817,8 @@ def synchronize() -> None: "dm": dm, "numint": numint, "backend": backend, + "evaluate": evaluate, + "make_fingerprint": make_fingerprint, "synchronize": synchronize, "to_numpy": to_numpy, "route": route, @@ -552,32 +844,38 @@ def fingerprint(result: tuple[Any, Any, Any], to_numpy: Any) -> dict[str, float] def run_measurement(payload: dict[str, Any]) -> dict[str, Any]: import torch + if ( + payload.get("implementation", "skala") == "skalaxc" + and payload["measurement"] == "memory" + and payload["backend"] == "gpu" + ): + return { + "status": "unsupported", + "implementation": "skalaxc", + "measurement": "memory", + "mode": payload["mode"], + "error": ( + "PyTorch allocator counters do not observe native " + "SkalaXC/GauXC CUDA allocations" + ), + } + case = build_case(payload) - numint = case["numint"] dense_route_override: AbstractContextManager[Any] if not payload["forced_dense"]: dense_route_override = nullcontext() else: - dense_route_override = force_dense_route(numint) - - def evaluate() -> tuple[Any, Any, Any]: - return numint.nr_rks( - case["mol"], - case["grids"], - None, - case["dm"], - max_memory=int(payload["max_memory_mb"]), - ) + dense_route_override = force_dense_route(case["numint"]) result: tuple[Any, Any, Any] | None = None with dense_route_override: measurement = payload["measurement"] if measurement == "runtime": for _ in range(int(payload["runtime_warmup_runs"])): - evaluate() + case["evaluate"]() case["synchronize"]() started = time.perf_counter() - result = evaluate() + result = case["evaluate"]() case["synchronize"]() elapsed_seconds = time.perf_counter() - started measurement_data = {"runtime_seconds": elapsed_seconds} @@ -587,7 +885,7 @@ def evaluate() -> tuple[Any, Any, Any]: with tempfile.TemporaryDirectory() as temp_dir: profile_path = Path(temp_dir) / "allocations.bin" with memray.Tracker(profile_path): - result = evaluate() + result = case["evaluate"]() peak_bytes = int(memray.FileReader(profile_path).metadata.peak_memory) measurement_data = {"incremental_peak_bytes": peak_bytes} elif measurement == "memory" and case["backend"] == "gpu": @@ -596,7 +894,7 @@ def evaluate() -> tuple[Any, Any, Any]: case["synchronize"]() baseline_bytes = torch.cuda.memory_allocated() torch.cuda.reset_peak_memory_stats() - result = evaluate() + result = case["evaluate"]() case["synchronize"]() peak_bytes = max(0, torch.cuda.max_memory_allocated() - baseline_bytes) measurement_data = { @@ -607,15 +905,19 @@ def evaluate() -> tuple[Any, Any, Any]: raise ValueError(f"Unknown measurement: {measurement}") assert result is not None - return { + response = { "status": "ok", + "implementation": payload.get("implementation", "skala"), "measurement": payload["measurement"], "mode": payload["mode"], "route": case["route"], "system": case["system"], - "fingerprint": fingerprint(result, case["to_numpy"]), + "fingerprint": case["make_fingerprint"](result), **measurement_data, } + if "diagnostics" in case: + response["diagnostics"] = case["diagnostics"]() + return response def classify_exception(error: Exception) -> str: @@ -651,6 +953,7 @@ def worker_main() -> None: "error_type": type(error).__name__, "error": str(error), "traceback": traceback.format_exc()[-12000:], + "implementation": payload.get("implementation", "skala"), "measurement": payload.get("measurement"), "mode": payload.get("mode"), } @@ -711,6 +1014,7 @@ def execute_worker(payload: dict[str, Any], config: BenchmarkConfig) -> dict[str except subprocess.TimeoutExpired as error: return { "status": "timeout", + "implementation": payload.get("implementation", "skala"), "measurement": payload.get("measurement"), "mode": payload.get("mode"), "error": f"Worker exceeded {config.worker_timeout_seconds} seconds", @@ -724,7 +1028,7 @@ def execute_worker(payload: dict[str, Any], config: BenchmarkConfig) -> dict[str if line.startswith(WORKER_RESULT_PREFIX) ] if marker_lines: - record = json.loads(marker_lines[-1]) + record = cast(dict[str, Any], json.loads(marker_lines[-1])) if record["status"] != "ok": record["stderr_tail"] = completed.stderr[-4000:] return record @@ -737,6 +1041,7 @@ def execute_worker(payload: dict[str, Any], config: BenchmarkConfig) -> dict[str ) return { "status": status, + "implementation": payload.get("implementation", "skala"), "measurement": payload.get("measurement"), "mode": payload.get("mode"), "error": f"Worker exited with code {completed.returncode} without a result record", @@ -802,19 +1107,26 @@ def worker_payload( molecule: MoleculeSpec, mode: str, measurement: str, + implementation: str = "skala", ) -> dict[str, Any]: + if implementation not in IMPLEMENTATION_MODES: + raise ValueError(f"Unknown implementation: {implementation}") + if mode not in IMPLEMENTATION_MODES[implementation]: + raise ValueError(f"Mode {mode!r} is not valid for {implementation}") backend = "gpu" if mode.startswith("gpu") else "cpu" return { "operation": "measure", + "implementation": implementation, "source_root": str(config.source_root), "functional": config.functional, + "skalaxc_grid_size": config.skalaxc_grid_size, "basis": config.basis, "grid_level": config.grid_level, "grid_alignment": config.grid_alignment, "max_memory_mb": config.max_memory_mb, "cpu_threads": config.cpu_threads, "backend": backend, - "forced_dense": mode.endswith("_dense"), + "forced_dense": implementation == "skala" and mode.endswith("_dense"), "mode": mode, "measurement": measurement, "runtime_warmup_runs": config.runtime_warmup_runs, @@ -834,8 +1146,20 @@ def new_result_document( environment: dict[str, Any], ) -> dict[str, Any]: created_at = utc_now() + + def molecule_records(modes: tuple[str, ...]) -> dict[str, Any]: + return { + molecule.formula: { + **molecule.as_json(), + "observed": None, + "modes": {mode: {} for mode in modes}, + } + for molecule in molecules + } + return { - "schema_version": 1, + "schema_version": 2, + "benchmark": "pyscf_ao_screening", "created_at": created_at, "updated_at": created_at, "run_label": config.run_label, @@ -844,13 +1168,12 @@ def new_result_document( "configuration": config.as_json(), "geometry": GEOMETRY_PARAMETERS, "worker_sha256": runner_sha256(), - "molecules": { - molecule.formula: { - **molecule.as_json(), - "observed": None, - "modes": {mode: {} for mode in MODES}, + "implementations": { + implementation: { + "modes": list(modes), + "molecules": molecule_records(modes), } - for molecule in molecules + for implementation, modes in IMPLEMENTATION_MODES.items() }, } @@ -858,8 +1181,8 @@ def new_result_document( def validate_resume_document( document: dict[str, Any], config: BenchmarkConfig, source: dict[str, Any] ) -> None: - if document.get("schema_version") != 1: - raise ValueError("Cannot resume a result file with a different schema version") + if document.get("schema_version") != 2: + raise ValueError("Cannot resume a result file that is not schema version 2") if document.get("worker_sha256") != runner_sha256(): raise ValueError( "Cannot resume results created by a different runner implementation" @@ -904,7 +1227,7 @@ def result_path(config: BenchmarkConfig, source: dict[str, Any]) -> Path: raise ValueError("The run label must contain a filename-safe character") return ( config.results_dir - / f"skala-pyscf-ao-screening-{safe_label}-{source['commit'][:12]}.json" + / f"skala-pyscf-ao-screening-{safe_label}-{source['commit'][:12]}-v2.json" ) @@ -914,7 +1237,7 @@ def run_worker_preflight(config: BenchmarkConfig) -> dict[str, Any]: ) if result["status"] != "ok": raise RuntimeError(f"Benchmark preflight failed: {result}") - environment = result["environment"] + environment = cast(dict[str, Any], result["environment"]) imported_path = Path(environment["imported_skala"]) imported_path.relative_to(config.source_root / "src") required_packages = ("skala", "pyscf", "torch", "memray") @@ -923,9 +1246,24 @@ def run_worker_preflight(config: BenchmarkConfig) -> dict[str, Any]: ] if missing: raise RuntimeError(f"Worker environment is missing packages: {missing}") + if not environment["skalaxc"]["available"]: + raise RuntimeError( + "SkalaXC is unavailable in the worker environment: " + f"{environment['skalaxc'].get('error', 'unknown import error')}" + ) return environment +def _gpu_available( + implementation: str, environment: dict[str, Any] +) -> tuple[bool, str]: + if not bool(environment["cuda"]["available"]): + return False, "CUDA is not available in the worker environment" + if implementation == "skalaxc" and not bool(environment["skalaxc"]["cuda_enabled"]): + return False, "SkalaXC was built without CUDA support" + return True, "" + + def atom_distance(left: Atom, right: Atom) -> float: return math.dist(left[1:], right[1:]) @@ -989,54 +1327,69 @@ def run_benchmark( document = new_result_document(config, molecules, source, environment) atomic_write_json(output_path, document) - cuda_available = bool(document["environment"]["cuda"]["available"]) - for mode in MODES: - backend = "gpu" if mode.startswith("gpu") else "cpu" - for measurement in MEASUREMENTS: - blocked_by: dict[str, Any] | None = None - for molecule in molecules: - molecule_record = document["molecules"][molecule.formula] - existing = molecule_record["modes"][mode].get(measurement) - if existing and existing.get("status") in TERMINAL_STATUSES: - if existing["status"] in {"oom", "timeout"}: + for implementation, modes in IMPLEMENTATION_MODES.items(): + implementation_record = document["implementations"][implementation] + for mode in modes: + backend = "gpu" if mode.startswith("gpu") else "cpu" + for measurement in MEASUREMENTS: + blocked_by: dict[str, Any] | None = None + for molecule in molecules: + molecule_record = implementation_record["molecules"][ + molecule.formula + ] + existing = molecule_record["modes"][mode].get(measurement) + if existing and existing.get("status") in TERMINAL_STATUSES: + if existing["status"] in {"oom", "timeout"}: + blocked_by = { + "formula": molecule.formula, + "status": existing["status"], + } + continue + + result: dict[str, Any] + gpu_available, gpu_error = _gpu_available( + implementation, document["environment"] + ) + if backend == "gpu" and not gpu_available: + result = { + "status": "error", + "implementation": implementation, + "mode": mode, + "measurement": measurement, + "error": gpu_error, + } + elif blocked_by is not None: + result = { + "status": "skipped_after_resource_failure", + "implementation": implementation, + "mode": mode, + "measurement": measurement, + "blocked_by": blocked_by, + } + else: + result = execute_measurement( + worker_payload( + config, + molecule, + mode, + measurement, + implementation, + ), + config, + ) + + merge_worker_result(molecule_record, mode, measurement, result) + document["updated_at"] = utc_now() + atomic_write_json(output_path, document) + if result["status"] in {"oom", "timeout"}: blocked_by = { "formula": molecule.formula, - "status": existing["status"], + "status": result["status"], } - continue - - result: dict[str, Any] - if backend == "gpu" and not cuda_available: - result = { - "status": "error", - "mode": mode, - "measurement": measurement, - "error": "CUDA is not available in the worker environment", - } - elif blocked_by is not None: - result = { - "status": "skipped_after_resource_failure", - "mode": mode, - "measurement": measurement, - "blocked_by": blocked_by, - } - else: - result = execute_measurement( - worker_payload(config, molecule, mode, measurement), config + print( + f"{implementation:7s} {mode:9s} {measurement:7s} " + f"{molecule.formula:8s} {result['status']}" ) - - merge_worker_result(molecule_record, mode, measurement, result) - document["updated_at"] = utc_now() - atomic_write_json(output_path, document) - if result["status"] in {"oom", "timeout"}: - blocked_by = { - "formula": molecule.formula, - "status": result["status"], - } - print( - f"{mode:9s} {measurement:7s} {molecule.formula:8s} " - f"{result['status']}" - ) return output_path @@ -1063,6 +1416,13 @@ def parse_arguments(argv: list[str]) -> argparse.Namespace: help="Directory for commit-labelled JSON output.", ) parser.add_argument("--functional", default="skala-1.1") + parser.add_argument( + "--skalaxc-grid-size", + type=lambda value: value.upper().replace("-", "_"), + choices=("FINE", "ULTRA_FINE", "SUPER_FINE", "GM3", "GM5"), + default="GM3", + help="SkalaXC atomic grid preset; GM3 is closest to PySCF level 1.", + ) parser.add_argument("--basis", default="def2-qzvpp") parser.add_argument("--grid-level", type=int, default=1) parser.add_argument("--max-memory-mb", type=int, default=2000) @@ -1100,6 +1460,7 @@ def config_from_arguments(arguments: argparse.Namespace) -> BenchmarkConfig: results_dir=arguments.results_dir.expanduser().resolve(), run_label=arguments.label, functional=arguments.functional, + skalaxc_grid_size=arguments.skalaxc_grid_size, basis=arguments.basis, grid_level=arguments.grid_level, max_memory_mb=arguments.max_memory_mb, @@ -1119,6 +1480,7 @@ def main(argv: list[str] | None = None) -> int: print("Benchmark configuration:") print(json.dumps(config.as_json(), indent=2, sort_keys=True)) print(f"Skala import: {environment['imported_skala']}") + print(f"SkalaXC: {environment['skalaxc']}") print(f"Python: {environment['python_executable']}") print(f"CUDA: {environment['cuda']}") if arguments.preflight_only: diff --git a/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py b/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py index a81ccd08..58f33b98 100644 --- a/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py +++ b/benchmarks/run_pyscf_ao_screening_rotation_benchmark.py @@ -15,11 +15,17 @@ import sys from dataclasses import asdict, dataclass from pathlib import Path -from typing import Any +from typing import Any, cast -import run_pyscf_ao_screening_benchmark as benchmark +import run_pyscf_ao_screening_benchmark as benchmark # type: ignore[import-not-found] -MODES = ("gpu", "cpu_dense", "cpu_screened") +SKALA_MODES = ("gpu", "cpu_dense", "cpu_screened") +SKALAXC_MODES = benchmark.SKALAXC_MODES +MODES = SKALA_MODES +IMPLEMENTATION_MODES = { + "skala": SKALA_MODES, + "skalaxc": SKALAXC_MODES, +} MEASUREMENTS = ("runtime", "memory") BASE_MOLECULE = benchmark.make_molecule_spec(7) @@ -41,7 +47,7 @@ def as_json(self) -> dict[str, int]: @dataclass(frozen=True) -class RotationBenchmarkConfig(benchmark.BenchmarkConfig): +class RotationBenchmarkConfig(benchmark.BenchmarkConfig): # type: ignore[misc] azimuth_step_degrees: int = 30 polar_step_degrees: int = 30 @@ -74,7 +80,10 @@ def as_json(self) -> dict[str, Any]: data["polar_angles_degrees"] = list(self.polar_angles) data["orientation_count"] = len(self.orientations) data["full_orientation_count"] = len(self.full_orientations) - data["modes"] = list(MODES) + data["implementation_modes"] = { + implementation: list(modes) + for implementation, modes in IMPLEMENTATION_MODES.items() + } data["measurements"] = list(MEASUREMENTS) data["worker_thread_environment"] = self.worker_thread_environment return data @@ -158,30 +167,34 @@ def validate_rotation_grid(config: RotationBenchmarkConfig) -> None: def run_worker_preflight(config: RotationBenchmarkConfig) -> dict[str, Any]: - result = benchmark.execute_worker( - {"operation": "environment", "source_root": str(config.source_root)}, config + return cast(dict[str, Any], benchmark.run_worker_preflight(config)) + + +def worker_payload( + config: RotationBenchmarkConfig, + molecule: benchmark.MoleculeSpec, + mode: str, + measurement: str, + implementation: str, +) -> dict[str, Any]: + shared_mode = "cpu" if mode == "cpu_screened" else mode + payload = cast( + dict[str, Any], + benchmark.worker_payload( + config, molecule, shared_mode, measurement, implementation + ), ) - if result["status"] != "ok": - raise RuntimeError(f"Benchmark preflight failed: {result}") - environment = result["environment"] - imported_path = Path(environment["imported_skala"]) - imported_path.relative_to(config.source_root / "src") - required_packages = ("skala", "pyscf", "torch", "memray") - missing = [ - name for name in required_packages if not environment["packages"].get(name) - ] - if missing: - raise RuntimeError(f"Worker environment is missing packages: {missing}") - return environment + payload["mode"] = mode + return payload def result_path(config: RotationBenchmarkConfig, source: dict[str, Any]) -> Path: safe_label = re.sub(r"[^A-Za-z0-9_.-]+", "-", config.run_label).strip("-.") if not safe_label: raise ValueError("The run label must contain a filename-safe character") - return ( - config.results_dir - / f"skala-pyscf-ao-screening-rotations-{safe_label}-{source['commit'][:12]}.json" + return Path(config.results_dir) / ( + "skala-pyscf-ao-screening-rotations-" + f"{safe_label}-{source['commit'][:12]}-v2.json" ) @@ -191,8 +204,21 @@ def new_result_document( environment: dict[str, Any], ) -> dict[str, Any]: created_at = benchmark.utc_now() + + def orientation_records(modes: tuple[str, ...]) -> dict[str, Any]: + return { + orientation.key: { + "index": index, + **orientation.as_json(), + "coordinate_sha256": rotated_molecule(orientation).coordinate_sha256, + "observed": None, + "modes": {mode: {} for mode in modes}, + } + for index, orientation in enumerate(config.orientations) + } + return { - "schema_version": 1, + "schema_version": 2, "benchmark": "pyscf_ao_screening_rotations", "created_at": created_at, "updated_at": created_at, @@ -206,15 +232,12 @@ def new_result_document( "rotation_convention": "active Cartesian rotation Rz(azimuth) @ Ry(polar)", }, "runner_hashes": runner_hashes(), - "orientations": { - orientation.key: { - "index": index, - **orientation.as_json(), - "coordinate_sha256": rotated_molecule(orientation).coordinate_sha256, - "observed": None, - "modes": {mode: {} for mode in MODES}, + "implementations": { + implementation: { + "modes": list(modes), + "orientations": orientation_records(modes), } - for index, orientation in enumerate(config.orientations) + for implementation, modes in IMPLEMENTATION_MODES.items() }, } @@ -224,8 +247,8 @@ def validate_resume_document( config: RotationBenchmarkConfig, source: dict[str, Any], ) -> None: - if document.get("schema_version") != 1: - raise ValueError("Cannot resume a result file with a different schema version") + if document.get("schema_version") != 2: + raise ValueError("Cannot resume a result file that is not schema version 2") if document.get("runner_hashes") != runner_hashes(): raise ValueError( "Cannot resume results created by different runner implementations" @@ -248,57 +271,74 @@ def run_benchmark(config: RotationBenchmarkConfig, environment: dict[str, Any]) document = new_result_document(config, source, environment) benchmark.atomic_write_json(output_path, document) - cuda_available = bool(document["environment"]["cuda"]["available"]) - for mode in MODES: - for measurement in MEASUREMENTS: - blocked_by: dict[str, Any] | None = None - for orientation in config.orientations: - orientation_record = document["orientations"][orientation.key] - existing = orientation_record["modes"][mode].get(measurement) - if existing and existing.get("status") in benchmark.TERMINAL_STATUSES: - if existing["status"] in {"oom", "timeout"}: + for implementation, modes in IMPLEMENTATION_MODES.items(): + implementation_record = document["implementations"][implementation] + for mode in modes: + backend = "gpu" if mode.startswith("gpu") else "cpu" + for measurement in MEASUREMENTS: + blocked_by: dict[str, Any] | None = None + for orientation in config.orientations: + orientation_record = implementation_record["orientations"][ + orientation.key + ] + existing = orientation_record["modes"][mode].get(measurement) + if ( + existing + and existing.get("status") in benchmark.TERMINAL_STATUSES + ): + if existing["status"] in {"oom", "timeout"}: + blocked_by = { + "orientation": orientation.key, + "status": existing["status"], + } + continue + + result: dict[str, Any] + gpu_available, gpu_error = benchmark._gpu_available( + implementation, document["environment"] + ) + if backend == "gpu" and not gpu_available: + result = { + "status": "error", + "implementation": implementation, + "mode": mode, + "measurement": measurement, + "error": gpu_error, + } + elif blocked_by is not None: + result = { + "status": "skipped_after_resource_failure", + "implementation": implementation, + "mode": mode, + "measurement": measurement, + "blocked_by": blocked_by, + } + else: + molecule = rotated_molecule(orientation) + payload = worker_payload( + config, + molecule, + mode, + measurement, + implementation, + ) + payload["orientation"] = orientation.as_json() + result = benchmark.execute_measurement(payload, config) + + benchmark.merge_worker_result( + orientation_record, mode, measurement, result + ) + document["updated_at"] = benchmark.utc_now() + benchmark.atomic_write_json(output_path, document) + if result["status"] in {"oom", "timeout"}: blocked_by = { "orientation": orientation.key, - "status": existing["status"], + "status": result["status"], } - continue - - result: dict[str, Any] - if mode == "gpu" and not cuda_available: - result = { - "status": "error", - "mode": mode, - "measurement": measurement, - "error": "CUDA is not available in the worker environment", - } - elif blocked_by is not None: - result = { - "status": "skipped_after_resource_failure", - "mode": mode, - "measurement": measurement, - "blocked_by": blocked_by, - } - else: - molecule = rotated_molecule(orientation) - payload = benchmark.worker_payload( - config, molecule, mode, measurement + print( + f"{implementation:7s} {mode:12s} {measurement:7s} " + f"{orientation.key} {result['status']}" ) - payload["orientation"] = orientation.as_json() - result = benchmark.execute_measurement(payload, config) - - benchmark.merge_worker_result( - orientation_record, mode, measurement, result - ) - document["updated_at"] = benchmark.utc_now() - benchmark.atomic_write_json(output_path, document) - if result["status"] in {"oom", "timeout"}: - blocked_by = { - "orientation": orientation.key, - "status": result["status"], - } - print( - f"{mode:12s} {measurement:7s} {orientation.key} {result['status']}" - ) return output_path @@ -328,6 +368,13 @@ def parse_arguments(argv: list[str]) -> argparse.Namespace: help="Directory for commit-labelled JSON output.", ) parser.add_argument("--functional", default="skala-1.1") + parser.add_argument( + "--skalaxc-grid-size", + type=lambda value: value.upper().replace("-", "_"), + choices=("FINE", "ULTRA_FINE", "SUPER_FINE", "GM3", "GM5"), + default="GM3", + help="SkalaXC atomic grid preset; GM3 is closest to PySCF level 1.", + ) parser.add_argument("--basis", default="def2-qzvpp") parser.add_argument("--grid-level", type=int, default=1) parser.add_argument("--max-memory-mb", type=int, default=2000) @@ -373,6 +420,7 @@ def config_from_arguments( results_dir=arguments.results_dir.expanduser().resolve(), run_label=arguments.label, functional=arguments.functional, + skalaxc_grid_size=arguments.skalaxc_grid_size, basis=arguments.basis, grid_level=arguments.grid_level, max_memory_mb=arguments.max_memory_mb, @@ -398,6 +446,7 @@ def main(argv: list[str] | None = None) -> int: f"{BASE_MOLECULE.expected_aos} AOs with {config.basis}" ) print(f"Skala import: {environment['imported_skala']}") + print(f"SkalaXC: {environment['skalaxc']}") print(f"Python: {environment['python_executable']}") print(f"CUDA: {environment['cuda']}") if arguments.preflight_only: diff --git a/pixi.lock b/pixi.lock index 3a2f368b..d53cab0e 100644 --- a/pixi.lock +++ b/pixi.lock @@ -3566,6 +3566,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h2d75abc_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-h19c2612_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -3581,6 +3582,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/git-2.55.0-pl5321h5685339_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-14.4.0-hc6a0c74_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.4.0-hc436dd5_4.conda @@ -3597,6 +3599,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-10_h5875eb1_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_4.conda @@ -3632,10 +3635,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-ha7672b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -3653,9 +3658,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda129_mkl_h546cc0b_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda @@ -3665,8 +3673,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda @@ -3674,6 +3685,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-2.3.1-py312h89dfda2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h4d09622_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -3682,6 +3694,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openmpi-5.0.10-hee33aa4_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda @@ -3689,6 +3702,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cuda129_mkl_py312_h0509a7e_302.conda @@ -3763,6 +3777,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-14.4.0-hd9a9cd0_104.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libnvptxcompiler-dev_linux-64-12.9.86-ha770c72_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-14.4.0-ha5b54cb_104.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpi-1.0.1-openmpi.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -3772,6 +3790,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.2.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.8-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -3787,17 +3806,20 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-1.0.3-pyh04d0eab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - pypi: ./skala @@ -3862,6 +3884,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h15eaa2f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-2.0.0-hdab9b82_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-h19c2612_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -3877,6 +3900,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/git-2.55.0-pl5321h5685339_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-15.3.0-hc6a0c74_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-15.3.0-h90d9265_4.conda @@ -3893,6 +3917,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-10_h5875eb1_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_4.conda @@ -3928,10 +3953,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-hd93470c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -3949,9 +3976,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda130_mkl_h1ca3d63_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda @@ -3961,8 +3991,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda @@ -3970,6 +4003,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-2.3.1-py312h89dfda2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h1aa9b5a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -3978,6 +4012,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openmpi-5.0.10-hee33aa4_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda @@ -3985,6 +4020,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cuda130_mkl_py312_hcdc9d04_302.conda @@ -4059,6 +4095,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-15.3.0-h2b852eb_104.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libnvptxcompiler-dev_linux-64-13.3.73-ha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-15.3.0-hb2c5482_104.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpi-1.0.1-openmpi.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -4068,6 +4108,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.2.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.8-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -4083,17 +4124,20 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-1.0.3-pyh04d0eab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - pypi: ./skala @@ -4164,6 +4208,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cutensor-2.7.0.5-h15eaa2f_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-2.0.0-hdab9b82_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-h19c2612_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -4178,6 +4223,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/git-2.55.0-pl5321h5685339_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-15.2.0-hd47ba16_20.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-15.2.0-he8f701c_20.conda @@ -4194,6 +4240,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-10_h5875eb1_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_4.conda @@ -4230,11 +4277,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.8-hf7376ad_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.10.0-hd93470c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.11.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -4252,9 +4301,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cuda130_mkl_h1ca3d63_302.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libudev1-257.13-h084b8d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda @@ -4264,8 +4316,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda @@ -4273,6 +4328,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-2.3.1-py312h89dfda2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nccl-2.30.7.1-h1aa9b5a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -4281,6 +4337,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openmpi-5.0.10-hee33aa4_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda @@ -4288,6 +4345,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cuda130_mkl_py312_hcdc9d04_302.conda @@ -4363,6 +4421,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-15.2.0-hcc6f6b0_120.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libnvptxcompiler-dev_linux-64-13.3.73-ha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-15.2.0-hd446a21_120.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpi-1.0.1-openmpi.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda @@ -4372,6 +4434,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.2.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.8-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -4387,17 +4450,20 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-1.0.3-pyh04d0eab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - pypi: ./skala @@ -5806,6 +5872,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.16.0-py312h8b7ec3f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-2.0.0-hdab9b82_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-h19c2612_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -5816,6 +5883,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/git-2.55.0-pl5321h5685339_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-15.3.0-hc6a0c74_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-15.3.0-h90d9265_4.conda @@ -5832,6 +5900,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-10_h5875eb1_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_4.conda @@ -5854,9 +5923,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h922cc85_1.conda @@ -5869,8 +5940,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-h6154650_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cpu_mkl_h40bd1c6_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda @@ -5880,8 +5954,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda @@ -5889,6 +5966,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/mpi4py-4.1.2-py312h18f78f0_100.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-2.3.1-py312h89dfda2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -5896,6 +5974,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-heb1ab33_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda @@ -5903,6 +5982,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda @@ -5961,6 +6041,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-15.3.0-h2b852eb_104.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-15.3.0-hb2c5482_104.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda @@ -5969,6 +6053,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.2.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.8-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -5984,17 +6069,20 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-1.0.3-pyh04d0eab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - pypi: ./skala @@ -6026,6 +6114,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.16.0-py312h8b7ec3f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-2.0.0-hdab9b82_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-h19c2612_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -6036,6 +6125,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/git-2.55.0-pl5321h5685339_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-15.3.0-hc6a0c74_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-15.3.0-h90d9265_4.conda @@ -6052,6 +6142,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-10_h5875eb1_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_4.conda @@ -6074,9 +6165,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h922cc85_1.conda @@ -6089,8 +6182,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-h6154650_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cpu_mkl_h40bd1c6_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda @@ -6100,8 +6196,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda @@ -6109,6 +6208,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/mpi4py-4.1.2-py312h18f78f0_100.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-2.3.1-py312h89dfda2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -6116,6 +6216,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-heb1ab33_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda @@ -6123,6 +6224,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda @@ -6181,6 +6283,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-15.3.0-h2b852eb_104.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-15.3.0-hb2c5482_104.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda @@ -6189,6 +6295,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.2.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.8-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -6204,17 +6311,20 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-1.0.3-pyh04d0eab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - pypi: ./skala @@ -6246,6 +6356,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.16.0-py312h8b7ec3f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-2.0.0-hdab9b82_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-5.0.1-h19c2612_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/elfutils-0.194-h849f50c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-h76c4fd7_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py312h8a5da7c_0.conda @@ -6256,6 +6367,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/git-2.55.0-pl5321h5685339_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hfd2156b_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.3.1-py312h04c1168_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.8.13-h18acefa_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-15.3.0-hc6a0c74_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-15.3.0-h90d9265_4.conda @@ -6272,6 +6384,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260526.0-cxx17_h0dc7533_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_h3152399_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-10_h5875eb1_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-h39a168f_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-ha411449_4.conda @@ -6294,9 +6407,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libharfbuzz-14.4.0-h23af247_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h0cb94f2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.8-hfac485b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-10_h5e43f62_mkl.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmicrohttpd-1.0.10-hc2fc477_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h74cf4be_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h922cc85_1.conda @@ -6309,8 +6424,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-h6154650_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.21.0-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.13.0-cpu_mkl_h40bd1c6_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.52.1-h280c20c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_1.conda @@ -6320,8 +6438,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-23.1.0-h7148c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-hee9eb32_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-hebe6cf0_1003.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.11.1-py312h4c94fcb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/memray-1.19.3-py312ha9ecdfb_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2026.1.0-hd2095e1_245.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.4.0-ha2cb11d_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.2-ha2cb11d_1.conda @@ -6329,6 +6450,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/mpi4py-4.1.2-py312h18f78f0_100.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-2.3.1-py312h89dfda2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.10.1-h5ef0d04_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -6336,6 +6458,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-heb1ab33_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/optree-0.20.0-py312ha5105d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.26.5-h8d769aa_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-h8b3dc9c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/perl-5.32.1-7_hd590300_perl5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py312h38079b3_1.conda @@ -6343,6 +6466,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h1114479_1012.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h7cc23a3_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/py-spy-0.4.2-hbe0e3b8_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.14-h5f976f7_3_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-librt-0.15.0-py312h1b36aeb_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.13.0-cpu_mkl_py312_h999dc20_102.conda @@ -6401,6 +6525,10 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-15.3.0-h2b852eb_104.conda - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-15.3.0-hb2c5482_104.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/linkify-it-py-2.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.6.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda @@ -6409,6 +6537,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.2.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.8-pyh5ded981_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/py-cpuinfo-9.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.4-pyh293190f_0.conda @@ -6424,17 +6553,20 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.14-hd8ed1ab_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-9_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-1.0.3-pyh04d0eab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.14.0-pyh2585a3b_106.conda - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/textual-8.2.8-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.70.0-pyh8f84b5b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-2.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - pypi: ./skala @@ -21051,6 +21183,18 @@ packages: run_exports: {} size: 27515 timestamp: 1788271419073 +- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.11.8-pyh5ded981_0.conda + sha256: 8cbae1fed8437e63c9bcc691927402edb3809fccb26b15eb095df7dd2eb73e5f + md5: 48e9ecf08b0578a4313f13b2e2b0fd72 + depends: + - python >=3.11 + - python + license: MIT + purls: + - pkg:pypi/platformdirs?source=compressed-mapping + run_exports: {} + size: 27718 + timestamp: 1788959137036 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e md5: d7585b6550ad04c8c5e21097ada2888e diff --git a/pixi.toml b/pixi.toml index 11ad0a88..788c5ade 100644 --- a/pixi.toml +++ b/pixi.toml @@ -317,9 +317,9 @@ cpp-integration = { features = ["python-runtime", "model-definition", "component ftorch = { features = ["python-312", "model-assets", "torch-213-cpu", "native-toolchain", "fortran"], no-default-feature = true, platforms = ["linux-64"] } skalaxc-host = { features = ["python-312", "torch-213-cpu", "native-toolchain", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "test"], no-default-feature = true, platforms = ["linux-64", "linux-aarch64", "osx-arm64"] } skalaxc-host-clang = { features = ["python-312", "torch-213-cpu", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "skalaxc-clang", "test"], no-default-feature = true, platforms = ["linux-64"] } -skalaxc-cuda12 = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-gpu", "cuda-12", "native-toolchain", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "skalaxc-cuda12-build", "test"], no-default-feature = true, platforms = ["linux-64-cuda12"] } -skalaxc-cuda13 = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-gpu", "cuda-13", "native-toolchain", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "skalaxc-cuda13-build", "test"], no-default-feature = true, platforms = ["linux-64-cuda13"] } -skalaxc-cuda13-clang = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-gpu", "cuda-13", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "skalaxc-cuda13-clang-build", "test"], no-default-feature = true, platforms = ["linux-64-cuda13"] } -skalaxc-parity = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-cpu", "native-toolchain", "skalaxc-core", "skalaxc-python", "skalaxc-parity", "test"], no-default-feature = true, platforms = ["linux-64"] } +skalaxc-cuda12 = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-gpu", "cuda-12", "native-toolchain", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "skalaxc-cuda12-build", "test", "profiling"], no-default-feature = true, platforms = ["linux-64-cuda12"] } +skalaxc-cuda13 = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-gpu", "cuda-13", "native-toolchain", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "skalaxc-cuda13-build", "test", "profiling"], no-default-feature = true, platforms = ["linux-64-cuda13"] } +skalaxc-cuda13-clang = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-gpu", "cuda-13", "fortran", "skalaxc-core", "skalaxc-mpi", "skalaxc-python", "skalaxc-cuda13-clang-build", "test", "profiling"], no-default-feature = true, platforms = ["linux-64-cuda13"] } +skalaxc-parity = { features = ["python-runtime", "model-assets", "python-312", "pyscf-214", "torch-213-cpu", "native-toolchain", "skalaxc-core", "skalaxc-python", "skalaxc-parity", "test", "profiling"], no-default-feature = true, platforms = ["linux-64"] } skalaxc-tools = { features = ["python-312", "torch-213-cpu", "skalaxc-core", "skalaxc-tools"], no-default-feature = true, platforms = ["linux-64"] } skalaxc-package = { features = ["skalaxc-package"], no-default-feature = true, platforms = ["linux-64", "linux-aarch64", "osx-arm64"] }