mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-30 18:56:16 +00:00
Add optional science toolbelt probe
This commit is contained in:
parent
f41cf1e9fe
commit
40fbab8aac
6 changed files with 385 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -38,6 +38,7 @@ scripts/venv_unsloth/
|
|||
**/venv_wgpu/
|
||||
**/*.venv/
|
||||
**/venv/
|
||||
.venv-science/
|
||||
|
||||
# API Keys and credentials (NEVER track in git)
|
||||
API KEYS/
|
||||
|
|
|
|||
79
docs/optional-science-toolbelt.md
Normal file
79
docs/optional-science-toolbelt.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Optional Science Toolbelt
|
||||
|
||||
These tools are optional reference surfaces for math-first work. They are not
|
||||
default repo dependencies. Add them to a local environment only when a task
|
||||
needs an executable witness, conversion adapter, or independent solver.
|
||||
|
||||
The operating rule is simple: Lean remains the source of truth; these tools
|
||||
produce receipts, counterexamples, fixtures, and sanity checks.
|
||||
|
||||
## Install Manifests
|
||||
|
||||
Python packages that are reasonable to install into a task-specific virtual
|
||||
environment:
|
||||
|
||||
```bash
|
||||
uv venv .venv-science
|
||||
source .venv-science/bin/activate
|
||||
uv pip install -r requirements-optional-science.txt
|
||||
```
|
||||
|
||||
Equivalent npm convenience commands:
|
||||
|
||||
```bash
|
||||
npm run setup-science-light
|
||||
npm run probe-science
|
||||
```
|
||||
|
||||
Native command-line tools are listed in:
|
||||
|
||||
```text
|
||||
system-packages-optional-science.txt
|
||||
```
|
||||
|
||||
Do not wire these into default CI unless the workflow is explicitly optional or
|
||||
the tool is already installed on the runner.
|
||||
|
||||
## Probe What Is Available
|
||||
|
||||
Use the probe before asking an agent to rely on a domain tool:
|
||||
|
||||
```bash
|
||||
python3 scripts/probe_science_toolbelt.py
|
||||
python3 scripts/probe_science_toolbelt.py --json
|
||||
python3 scripts/probe_science_toolbelt.py --json --out shared-data/artifacts/science_toolbelt/probe.json
|
||||
```
|
||||
|
||||
The probe exits successfully even when optional tools are missing. Missing tools
|
||||
are data, not failure.
|
||||
|
||||
## Domain Priorities
|
||||
|
||||
| Domain | First tools | Use in this stack |
|
||||
| --- | --- | --- |
|
||||
| Genetics / bioinformatics | Biopython, pysam, samtools, bcftools, minimap2 | Validate FASTA/FASTQ/GenBank/SAM/BAM/VCF fixtures for the genetic-code, Hachimoji, and PIST surfaces. |
|
||||
| CFD / PDE | Dedalus, ParaView | Produce spectral PDE reference traces for Burgers/KdV/hyperfluid claims without committing to a heavyweight engineering CFD stack. |
|
||||
| Cryptography | liboqs-python, PyCryptodome, galois | Check post-quantum KEM/signature examples, hashes, finite-field arithmetic, and receipt digests. |
|
||||
| Chemistry / materials | RDKit, Open Babel | Parse/canonicalize SMILES, compute descriptors, and turn molecular claims into inspectable fixtures. |
|
||||
| Formal bridge | Z3, cvc5 | Search bounded counterexamples before spending Lean effort. |
|
||||
| Algebra / graph theory | SageMath, GAP, NetworkX, Graphviz | Generate lattice/group/graph witnesses and diagrams for later Lean or receipt promotion. |
|
||||
| Compression / signal | zstandard, PyWavelets | Provide compression baselines and spectral/wavelet witnesses for signal-shaping claims. |
|
||||
|
||||
## What Not To Do
|
||||
|
||||
- Do not add these packages to the default repo environment.
|
||||
- Do not treat a solver result as a theorem.
|
||||
- Do not commit generated datasets unless they are promoted as small,
|
||||
receipt-bearing evidence.
|
||||
- Do not copy implementation code from external tools into the repo.
|
||||
|
||||
## Receipt Pattern
|
||||
|
||||
For any adapter built on this toolbelt, prefer:
|
||||
|
||||
1. Input fixture path.
|
||||
2. Tool name and version from `probe_science_toolbelt.py`.
|
||||
3. Exact command or Python module call.
|
||||
4. Output hash and short human-readable summary.
|
||||
5. Link to the Lean theorem, claim registry entry, or distilled doc that the
|
||||
receipt supports.
|
||||
|
|
@ -5,7 +5,9 @@
|
|||
"scripts": {
|
||||
"install-python": "uv python install 3.11.15",
|
||||
"setup-cad-env": "cd 5-Applications/text-to-cad && python3.11 -m venv .venv && ./.venv/bin/pip install -r requirements-cad.txt",
|
||||
"verify-cad": "cd 5-Applications/text-to-cad && ./.venv/bin/python -c \"import build123d; import OCP; print('CAD dependencies OK')\""
|
||||
"verify-cad": "cd 5-Applications/text-to-cad && ./.venv/bin/python -c \"import build123d; import OCP; print('CAD dependencies OK')\"",
|
||||
"setup-science-light": "uv venv .venv-science && . .venv-science/bin/activate && uv pip install -r requirements-optional-science.txt",
|
||||
"probe-science": "python3 scripts/probe_science_toolbelt.py"
|
||||
},
|
||||
"dependencies": {
|
||||
"better-sqlite3": "^12.4.1"
|
||||
|
|
|
|||
34
requirements-optional-science.txt
Normal file
34
requirements-optional-science.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Optional science toolbelt for receipt-producing adapters.
|
||||
#
|
||||
# Install only when a task needs these domains:
|
||||
#
|
||||
# uv pip install -r requirements-optional-science.txt
|
||||
#
|
||||
# These packages are intentionally not part of the default repo setup. They
|
||||
# provide reference implementations and data-format adapters for math-first
|
||||
# verification receipts.
|
||||
|
||||
# Genetics / bioinformatics
|
||||
biopython>=1.87
|
||||
pysam>=0.24.0
|
||||
|
||||
# Chemistry / materials
|
||||
rdkit>=2026.3.1
|
||||
|
||||
# SMT / formal-methods bridge
|
||||
z3-solver>=4.16.0.0
|
||||
cvc5>=1.3.4
|
||||
|
||||
# Cryptography / finite fields / symbolic checks
|
||||
pycryptodome>=3.23.0
|
||||
galois>=0.4.6
|
||||
|
||||
# Graphs, signal analysis, and compression baselines
|
||||
networkx>=3.5
|
||||
PyWavelets>=1.9.0
|
||||
zstandard>=0.25.0
|
||||
|
||||
# Heavy or native-stack options. Keep commented unless a task explicitly needs
|
||||
# the solver and the host has the native prerequisites.
|
||||
# dedalus>=3.0.5
|
||||
# liboqs-python>=0.14.1
|
||||
242
scripts/probe_science_toolbelt.py
Executable file
242
scripts/probe_science_toolbelt.py
Executable file
|
|
@ -0,0 +1,242 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Probe optional science tools without requiring them.
|
||||
|
||||
The goal is not to make these tools part of the default stack. The goal is to
|
||||
let agents and CI-adjacent smoke checks discover which reference solvers,
|
||||
format adapters, and verification backends are available on the current host.
|
||||
|
||||
Exit code:
|
||||
0 probe completed; missing optional tools are reported in the payload.
|
||||
2 invalid CLI arguments or unable to write output.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib
|
||||
import json
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PythonTool:
|
||||
key: str
|
||||
domain: str
|
||||
module: str
|
||||
purpose: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CommandTool:
|
||||
key: str
|
||||
domain: str
|
||||
command: str
|
||||
purpose: str
|
||||
version_args: tuple[str, ...] = ("--version",)
|
||||
|
||||
|
||||
PYTHON_TOOLS: tuple[PythonTool, ...] = (
|
||||
PythonTool(
|
||||
"biopython",
|
||||
"genetics",
|
||||
"Bio",
|
||||
"FASTA/FASTQ/GenBank parsing and sequence manipulation",
|
||||
),
|
||||
PythonTool("pysam", "genetics", "pysam", "SAM/BAM/CRAM/VCF access from Python"),
|
||||
PythonTool(
|
||||
"rdkit",
|
||||
"chemistry",
|
||||
"rdkit",
|
||||
"SMILES parsing, canonicalization, descriptors, fingerprints",
|
||||
),
|
||||
PythonTool("z3-solver", "formal-methods", "z3", "SMT checks before Lean proof work"),
|
||||
PythonTool("cvc5", "formal-methods", "cvc5", "SMT checks and model finding"),
|
||||
PythonTool(
|
||||
"pycryptodome",
|
||||
"cryptography",
|
||||
"Crypto",
|
||||
"hash/signature/cipher reference primitives",
|
||||
),
|
||||
PythonTool("galois", "cryptography", "galois", "finite-field arithmetic"),
|
||||
PythonTool(
|
||||
"networkx",
|
||||
"graph-theory",
|
||||
"networkx",
|
||||
"graph certificates and topology receipts",
|
||||
),
|
||||
PythonTool(
|
||||
"pywavelets",
|
||||
"signal-processing",
|
||||
"pywt",
|
||||
"wavelet decompositions for spectral receipts",
|
||||
),
|
||||
PythonTool(
|
||||
"zstandard",
|
||||
"compression",
|
||||
"zstandard",
|
||||
"zstd baseline and dictionary-training adapter",
|
||||
),
|
||||
PythonTool("dedalus", "cfd-pde", "dedalus", "spectral PDE reference solver"),
|
||||
PythonTool(
|
||||
"liboqs-python",
|
||||
"cryptography",
|
||||
"oqs",
|
||||
"Open Quantum Safe KEM/signature reference adapter",
|
||||
),
|
||||
)
|
||||
|
||||
COMMAND_TOOLS: tuple[CommandTool, ...] = (
|
||||
CommandTool(
|
||||
"samtools",
|
||||
"genetics",
|
||||
"samtools",
|
||||
"SAM/BAM/CRAM command-line verification",
|
||||
),
|
||||
CommandTool("bcftools", "genetics", "bcftools", "VCF/BCF command-line verification"),
|
||||
CommandTool("minimap2", "genetics", "minimap2", "sequence alignment smoke checks"),
|
||||
CommandTool(
|
||||
"sage",
|
||||
"algebra-crypto",
|
||||
"sage",
|
||||
"lattice, group, and symbolic mathematics",
|
||||
("--version",),
|
||||
),
|
||||
CommandTool("gap", "algebra", "gap", "computational group-theory checks", ("--version",)),
|
||||
CommandTool("z3", "formal-methods", "z3", "SMT solver CLI", ("--version",)),
|
||||
CommandTool("cvc5", "formal-methods", "cvc5", "SMT solver CLI", ("--version",)),
|
||||
CommandTool("zstd", "compression", "zstd", "compression baseline CLI", ("--version",)),
|
||||
CommandTool("dot", "graph-theory", "dot", "Graphviz graph rendering for witness diagrams", ("-V",)),
|
||||
CommandTool("obabel", "chemistry", "obabel", "Open Babel format conversion", ("-V",)),
|
||||
CommandTool("paraview", "cfd-pde", "paraview", "CFD/PDE visualization frontend", ("--version",)),
|
||||
)
|
||||
|
||||
|
||||
def _module_version(module: Any) -> str | None:
|
||||
for attr in ("__version__", "VERSION", "version"):
|
||||
value = getattr(module, attr, None)
|
||||
if value is None:
|
||||
continue
|
||||
if callable(value):
|
||||
try:
|
||||
value = value()
|
||||
except Exception:
|
||||
continue
|
||||
return str(value)
|
||||
return None
|
||||
|
||||
|
||||
def _probe_python(tool: PythonTool) -> dict[str, Any]:
|
||||
try:
|
||||
module = importlib.import_module(tool.module)
|
||||
except Exception as exc:
|
||||
return {
|
||||
**asdict(tool),
|
||||
"available": False,
|
||||
"error": f"{type(exc).__name__}: {exc}",
|
||||
}
|
||||
return {
|
||||
**asdict(tool),
|
||||
"available": True,
|
||||
"version": _module_version(module),
|
||||
"path": getattr(module, "__file__", None),
|
||||
}
|
||||
|
||||
|
||||
def _run_version(path: str, args: tuple[str, ...]) -> str | None:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[path, *args],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
check=False,
|
||||
)
|
||||
except Exception:
|
||||
return None
|
||||
text = (result.stdout or result.stderr).strip()
|
||||
if not text:
|
||||
return None
|
||||
return text.splitlines()[0]
|
||||
|
||||
|
||||
def _probe_command(tool: CommandTool) -> dict[str, Any]:
|
||||
path = shutil.which(tool.command)
|
||||
if path is None:
|
||||
return {
|
||||
**asdict(tool),
|
||||
"available": False,
|
||||
}
|
||||
return {
|
||||
**asdict(tool),
|
||||
"available": True,
|
||||
"path": path,
|
||||
"version": _run_version(path, tool.version_args),
|
||||
}
|
||||
|
||||
|
||||
def build_report() -> dict[str, Any]:
|
||||
python_results = [_probe_python(tool) for tool in PYTHON_TOOLS]
|
||||
command_results = [_probe_command(tool) for tool in COMMAND_TOOLS]
|
||||
available = sum(1 for item in python_results + command_results if item["available"])
|
||||
total = len(python_results) + len(command_results)
|
||||
by_domain: dict[str, dict[str, int]] = {}
|
||||
for item in python_results + command_results:
|
||||
bucket = by_domain.setdefault(item["domain"], {"available": 0, "total": 0})
|
||||
bucket["total"] += 1
|
||||
if item["available"]:
|
||||
bucket["available"] += 1
|
||||
return {
|
||||
"schema": "research_stack_optional_science_toolbelt_probe_v1",
|
||||
"summary": {
|
||||
"available": available,
|
||||
"total": total,
|
||||
"by_domain": by_domain,
|
||||
},
|
||||
"python": python_results,
|
||||
"commands": command_results,
|
||||
}
|
||||
|
||||
|
||||
def _print_text(report: dict[str, Any]) -> None:
|
||||
summary = report["summary"]
|
||||
print(f"optional science toolbelt: {summary['available']}/{summary['total']} available")
|
||||
for section in ("python", "commands"):
|
||||
print(f"\n{section}:")
|
||||
for item in report[section]:
|
||||
mark = "OK" if item["available"] else "--"
|
||||
version = item.get("version")
|
||||
suffix = f" ({version})" if version else ""
|
||||
print(f" {mark} {item['key']}: {item['purpose']}{suffix}")
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--json", action="store_true", help="emit JSON instead of text")
|
||||
parser.add_argument("--out", type=Path, help="write the JSON report to this path")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
report = build_report()
|
||||
if args.out:
|
||||
try:
|
||||
args.out.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.out.write_text(
|
||||
json.dumps(report, indent=2, sort_keys=True) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
except OSError as exc:
|
||||
print(f"error: failed to write {args.out}: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(report, indent=2, sort_keys=True))
|
||||
else:
|
||||
_print_text(report)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
26
system-packages-optional-science.txt
Normal file
26
system-packages-optional-science.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Optional system packages for science toolbelt adapters.
|
||||
#
|
||||
# These are command-line tools or heavyweight native stacks that Python
|
||||
# requirements cannot reliably install. Names are Debian/Ubuntu-style package
|
||||
# names where available; distro packages vary.
|
||||
|
||||
# Genetics / bioinformatics
|
||||
samtools
|
||||
bcftools
|
||||
minimap2
|
||||
|
||||
# Formal methods / algebra
|
||||
cvc5
|
||||
z3
|
||||
gap
|
||||
sagemath
|
||||
|
||||
# Compression and receipt payload baselines
|
||||
zstd
|
||||
|
||||
# Visualization / data inspection
|
||||
graphviz
|
||||
paraview
|
||||
|
||||
# Chemistry / materials native helpers
|
||||
openbabel
|
||||
Loading…
Add table
Reference in a new issue