Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/build-bingo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Build Bingo Docker Image

on:
workflow_dispatch: # manual trigger
push:
branches:
- image.pull
paths:
- 'algorithms/bingo/**'
- 'Dockerfile.bingo'

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.bingo
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/srbench-bingo:latest
build-args: |
ALGORITHM=bingo
28 changes: 28 additions & 0 deletions Dockerfile.bingo
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM srbench/base:latest

# Build argument for algorithm name
ARG ALGORITHM=bingo

# Copy install script and algorithm files
COPY scripts/install_algorithm.sh /install/install_algorithm.sh
COPY base_environment.yml /install/base_environment.yml
COPY algorithms/${ALGORITHM} /install/algorithms/${ALGORITHM}

# Run installation
WORKDIR /install
RUN eval "$(micromamba shell hook --shell bash)" && \
micromamba activate base && \
bash install_algorithm.sh "/install/algorithms/${ALGORITHM}" && \
micromamba clean --all --yes && \
mkdir -p /srbench

# Set environment
ENV ALGORITHM=${ALGORITHM}
ENV LD_LIBRARY_PATH=/opt/conda/lib:${LD_LIBRARY_PATH}

# Default working directory
WORKDIR /srbench

# Entrypoint that activates micromamba
ENTRYPOINT ["/bin/bash", "-c", "eval \"$(micromamba shell hook --shell bash)\" && micromamba activate base && cd /srbench && exec \"$@\"", "--"]
CMD ["bash"]
Binary file added experiment/hall_of_fame_2026-10-16_124419.865.pkl
Binary file not shown.
Binary file added experiment/hall_of_fame_2026-10-16_124605.771.pkl
Binary file not shown.
105 changes: 105 additions & 0 deletions scripts/run_srbench.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/bash
# Submit one SLURM job per SRBench algorithm, each running analyze.py
# inside its Apptainer/Singularity container. Modeled on run_distributed.sh.
#
# Usage (from the srbench repo root):
# bash scripts/run_srbench.sh -a gplearn -d /path/to/pmlb/datasets
# bash scripts/run_srbench.sh -a gplearn,feat -d /path/to/pmlb/datasets -- -n_trials 10 -time_limit 9:00
#
# Options:
# -a ALGS Comma-separated algorithms (default: gplearn). Each must have
# a SIF at $SIF_DIR/srbench-<alg>.sif (see scripts/singularity_pull_all.sh).
# -d DIR PMLB datasets directory (required). Bound read-only into the container.
# -c CPUS CPUs per task / parallel jobs per algorithm (default: 8)
# -t TIME SLURM walltime, e.g. 24:00:00 (default: 24:00:00)
# -m MEM Memory per node, e.g. 32G (default: 32G)
# -p PART SLURM partition (default: cpu_batch)
# -r RDIR Results dir, relative to experiment/ (default: results)
# -n Dry run: print the sbatch commands without submitting
# -- ARGS Everything after -- is passed verbatim to analyze.py
# (e.g. -n_trials 10 -tuned -target_noise 0.01)
set -uo pipefail

CURRENT_DIR=$(pwd)
if [[ $CURRENT_DIR == */scripts ]]; then
cd ..
fi
echo "[srbench] Running from $(pwd)"

# --- Configuration (override via environment) ---------------------------------
SIF_DIR=${SIF_DIR:-/pgeoprj/dxt6/maromba/notebooks/container/output_dir}
LOG_DIRECTORY=${LOG_DIRECTORY:-logs}
mkdir -p "$LOG_DIRECTORY"

# --- Defaults -----------------------------------------------------------------
ALGS="gplearn"
DATASETS=""
CPUS=8
TIME="24:00:00"
MEM="32G"
PARTITION="cpu_batch"
RDIR="results"
DRYRUN=0
ANALYZE_ARGS=""

# --- Parse arguments ------------------------------------------------------------
while [[ "$#" -gt 0 ]]; do
case $1 in
-a) ALGS="$2"; shift 2 ;;
-d) DATASETS="$2"; shift 2 ;;
-c) CPUS="$2"; shift 2 ;;
-t) TIME="$2"; shift 2 ;;
-m) MEM="$2"; shift 2 ;;
-p) PARTITION="$2"; shift 2 ;;
-r) RDIR="$2"; shift 2 ;;
-n) DRYRUN=1; shift ;;
--) shift; ANALYZE_ARGS="$@"; break ;;
*) echo "[Error] Unknown option: $1"; exit 1 ;;
esac
done

if [ -z "$DATASETS" ]; then
echo "[Error] Missing required -d /path/to/pmlb/datasets"
exit 1
fi
if [ ! -d "$DATASETS" ]; then
echo "[Error] Datasets directory not found: $DATASETS"
exit 1
fi

# --- Submit one job per algorithm ---------------------------------------------
IFS=',' read -ra ALG_LIST <<< "$ALGS"
for ALG in "${ALG_LIST[@]}"; do
SIF="$SIF_DIR/srbench-${ALG}.sif"
if [ ! -f "$SIF" ]; then
echo "[Error] Missing image: $SIF"
echo " Pull it first: bash scripts/singularity_pull_all.sh $ALG"
continue
fi

NOW=$(date +"%Y-%m-%d_%H-%M-%S")
echo "[srbench] Submitting $ALG (cpus=$CPUS, time=$TIME, mem=$MEM, partition=$PARTITION)"
echo "[srbench] image: $SIF"
echo "[srbench] analyze: python analyze.py /pmlb/datasets --local -ml $ALG -n_jobs $CPUS -results $RDIR $ANALYZE_ARGS"

SBATCH_CMD=(
sbatch
--job-name="srbench-${ALG}"
--output="${LOG_DIRECTORY}/srbench-${ALG}-${NOW}.out"
--error="${LOG_DIRECTORY}/srbench-${ALG}-${NOW}.err"
--nodes=1
--ntasks=1
--cpus-per-task="${CPUS}"
--time="${TIME}"
--mem="${MEM}"
--partition="${PARTITION}"
--export=ALL,ALG="${ALG}",SIF="${SIF}",DATASETS="${DATASETS}",CPUS="${CPUS}",RDIR="${RDIR}",ANALYZE_ARGS="${ANALYZE_ARGS}"
scripts/run_srbench.slurm
)

if [ "$DRYRUN" -eq 1 ]; then
echo "[dryrun] ${SBATCH_CMD[*]}"
else
"${SBATCH_CMD[@]}"
fi
done
46 changes: 46 additions & 0 deletions scripts/run_srbench.slurm
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash
# SLURM batch script: run SRBench analyze.py for ONE algorithm inside its
# Apptainer/Singularity container. Submitted by scripts/run_srbench.sh,
# which exports: ALG, SIF, DATASETS, CPUS, RDIR, ANALYZE_ARGS.
# Modeled on run_distributed.slurm.

# Inform user
echo "[srbench] $USER @ $(hostname) | Algorithm: $ALG"
echo "[srbench] $USER @ $(hostname) | Image: $SIF"
echo "[srbench] $USER @ $(hostname) | Datasets: $DATASETS"
echo "[srbench] $USER @ $(hostname) | CWD: $(pwd)"
echo "[srbench] $USER @ $(hostname) | analyze.py args: $ANALYZE_ARGS"

# --- Runtime ------------------------------------------------------------------
if command -v apptainer >/dev/null 2>&1; then
CONTAINER=apptainer
else
CONTAINER=singularity
fi
echo "[srbench] Using runtime: $CONTAINER ($($CONTAINER --version 2>/dev/null))"

# Keep per-job cache/tmp off $HOME (quota) and on local/scratch disk.
export APPTAINER_CACHEDIR=${APPTAINER_CACHEDIR:-/tmp/$USER/apptainer_cache}
export APPTAINER_TMPDIR=${APPTAINER_TMPDIR:-/tmp/$USER/apptainer_tmp}
export SINGULARITY_CACHEDIR=$APPTAINER_CACHEDIR
export SINGULARITY_TMPDIR=$APPTAINER_TMPDIR
mkdir -p "$APPTAINER_CACHEDIR" "$APPTAINER_TMPDIR"

# --- Bind mounts ----------------------------------------------------------------
# experiment/ -> /srbench (the image's WORKDIR; results are written here)
# datasets -> /pmlb/datasets (read-only)
# /pgeoprj,/tatu kept for consistency with your other jobs.
BINDS="$PWD/experiment:/srbench,$DATASETS:/pmlb/datasets:ro,/pgeoprj,/tatu"

# --- Run ------------------------------------------------------------------------
# `run` (not `exec`) so the image entrypoint activates the conda base env,
# matching `docker compose run <alg> ...`.
$CONTAINER run --pwd /srbench -B "$BINDS" "$SIF" \
python analyze.py /pmlb/datasets \
--local \
-ml "$ALG" \
-n_jobs "$CPUS" \
-results "$RDIR" \
$ANALYZE_ARGS

echo "[srbench] $USER @ $(hostname) | Done ($ALG). Results in experiment/$RDIR"
111 changes: 111 additions & 0 deletions scripts/singularity_pull_all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/bin/bash
# Pull prebuilt SRBench algorithm images from Docker Hub as Singularity SIFs.
#
# Run this on a node WITH internet access (e.g. the login node); compute
# nodes usually can't reach Docker Hub.
#
# Usage:
# bash scripts/singularity_pull_all.sh # pull all available images
# bash scripts/singularity_pull_all.sh gplearn feat # pull specific ones
#
# Env overrides:
# OUTPUT_DIR - where .sif files are written
# (default: /tatu/container_images/srbench)
# SINGULARITY_CACHEDIR - docker layer cache (default: /tatu/$USER/singularity_cache)
# SINGULARITY_TMPDIR - temp dir during conversion (default: /tatu/$USER/singularity_tmp)
#
# NOTE: images are large (some >10 GB uncompressed). Do NOT let the cache
# default to $HOME or you may fill your home quota.
set -uo pipefail

# --- Pick a container runtime -------------------------------------------------
# "ERROR: pull is only supported for shub URIs" means singularity 2.x, which
# cannot pull from docker://. We need singularity >= 3.x or apptainer.
# Prefer apptainer if installed; otherwise use singularity and check its version.
if command -v apptainer >/dev/null 2>&1; then
SINGULARITY=apptainer
else
SINGULARITY=singularity
fi

VER=$(command $SINGULARITY --version 2>/dev/null | grep -oE '[0-9]+(\.[0-9]+)+' | head -1)
MAJOR=${VER%%.*}
# if [ -z "${MAJOR}" ] || [ "${MAJOR}" -lt 3 ]; then
# echo "ERROR: '$SINGULARITY' is version '${VER:-unknown}', but >= 3.0 (or apptainer)"
# echo " is required to pull from Docker Hub (docker:// URIs)."
# echo
# echo "Look for a newer installation on the cluster, e.g.:"
# echo " module avail singularity"
# echo " module avail apptainer"
# echo " which -a singularity apptainer"
# echo "then 'module load' it and re-run this script."
# exit 1
# fi
echo "Using runtime: $SINGULARITY ($VER)"

# Algorithms published on Docker Hub (srbench org), tag :latest.
# Verified 2026-10-16. The remaining repo algorithms are NOT published:
# brush bsr gp-elite keplearn lightgbm nesymres pantara pir sklearn tpsr udsr xgboost
# (those need a local conda install or a SIF built from a def file).
AVAILABLE=(
afp
bingo
e2et
eplex
eql
feat
ffx
geneticengine
gpgomea
gplearn
gpzgd
itea
operon
ps-tree
pysr
qlattice
rils-rols
tir
)

# OUTPUT_DIR=${OUTPUT_DIR:-/tatu/container_images/srbench}
# export SINGULARITY_CACHEDIR=${SINGULARITY_CACHEDIR:-/tatu/$USER/singularity_cache}
# export SINGULARITY_TMPDIR=${SINGULARITY_TMPDIR:-/tatu/$USER/singularity_tmp}
OUTPUT_DIR=${OUTPUT_DIR:-/pgeoprj/dxt6/maromba/notebooks/container/output_dir}
export SINGULARITY_CACHEDIR=${SINGULARITY_CACHEDIR:-/pgeoprj/dxt6/maromba/notebooks/container/singularity_cache}
export SINGULARITY_TMPDIR=${SINGULARITY_TMPDIR:-/pgeoprj/dxt6/maromba/notebooks/container/singularity_tmp}
mkdir -p "$OUTPUT_DIR" "$SINGULARITY_CACHEDIR" "$SINGULARITY_TMPDIR"

if [ "$#" -gt 0 ]; then
ALGS=("$@")
else
ALGS=("${AVAILABLE[@]}")
fi

FAILED=()
for alg in "${ALGS[@]}"; do
sif="$OUTPUT_DIR/srbench-${alg}.sif"
if [ -f "$sif" ]; then
echo "[skip] $sif already exists"
continue
fi
echo "[pull] docker://srbench/${alg}:latest -> $sif"
if $SINGULARITY pull "$sif" "docker://srbench/${alg}:latest"; then
echo "[ok] $alg"
else
echo "[FAIL] $alg"
FAILED+=("$alg")
fi
done

echo
if [ "${#FAILED[@]}" -gt 0 ]; then
echo "Finished with ${#FAILED[@]} failure(s): ${FAILED[*]}"
else
echo "All images pulled successfully."
fi
echo "SIF files are in: $OUTPUT_DIR"
echo
echo "Smoke-test one image (run from the srbench repo root):"
echo " singularity run --pwd /srbench -B \$PWD/experiment:/srbench \\"
echo " $OUTPUT_DIR/srbench-gplearn.sif bash test.sh"
49 changes: 49 additions & 0 deletions scripts/srbench-alg.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Bootstrap: docker
From: srbench/base:latest
# Build a SIF for one SRBench algorithm, mirroring alg-Dockerfile.
#
# Build with (needs root, --fakeroot, or --remote):
# APPTAINERENV_ALGORITHM=brush apptainer build --fakeroot --no-mount bind-paths srbench-brush.sif scripts/srbench-alg.def
# or, without root:
# APPTAINERENV_ALGORITHM=brush apptainer build --remote srbench-brush.sif scripts/srbench-alg.def
#
# The --no-mount bind-paths flag disables site-configured bind mounts
# (e.g. /exp, /pgeo) that would otherwise fail because the base image
# doesn't have those mountpoints.
#
# %files paths are relative to the build CONTEXT (the current directory),
# so run the build from the srbench repo root.

%files
base_environment.yml /install/base_environment.yml
scripts/install_algorithm.sh /install/install_algorithm.sh
algorithms /install/algorithms

%post
set -e
ALGORITHM="${APPTAINERENV_ALGORITHM:-brush}"
echo "Building for algorithm: ${ALGORITHM}"
cd /install
# alg-Dockerfile relies on MAMBA_DOCKERFILE_ACTIVATE=1 to auto-activate
# the base env in RUN steps; here we activate it explicitly.
eval "$(micromamba shell hook --shell bash)"
micromamba activate base
bash install_algorithm.sh "/install/algorithms/${ALGORITHM}"
micromamba clean --all --yes
# remove all other algorithm sources to keep the image small
find /install/algorithms -mindepth 1 -maxdepth 1 -type d ! -name "${ALGORITHM}" -exec rm -rf {} +
mkdir -p /srbench

%environment
export LD_LIBRARY_PATH=/opt/conda/lib:${LD_LIBRARY_PATH}

%runscript
# The base image's Docker entrypoint (micromamba activation) is NOT run
# by apptainer, so activate base here to match `docker compose run`.
eval "$(micromamba shell hook --shell bash)"
micromamba activate base
cd /srbench
exec "$@"

%labels
Project srbench
Loading