diff --git a/.githooks/.sr-hooks-hash b/.githooks/.sr-hooks-hash index a014cb5b..9bb230f7 100644 --- a/.githooks/.sr-hooks-hash +++ b/.githooks/.sr-hooks-hash @@ -1 +1 @@ -0343981e584c25d0 \ No newline at end of file +8d0fafc1174a9d02 \ No newline at end of file diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..129409b7 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +# Generated by sr — edit the hooks section in sr.yaml to modify. +exec sr hook run pre-commit -- "$@" diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 00000000..53251938 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +# Generated by sr — edit the hooks section in sr.yaml to modify. +exec sr hook run pre-push -- "$@" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 025f5912..28819c22 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,6 +25,7 @@ jobs: contents: write outputs: released: ${{ steps.sr.outputs.released }} + tag: ${{ steps.sr.outputs.tag }} steps: - name: Generate app token id: app-token @@ -89,6 +90,56 @@ jobs: env: CARGO_REGISTRY_TOKEN: ${{ steps.crates-token.outputs.token }} + binaries: + needs: release + if: needs.release.outputs.released == 'true' + strategy: + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + - target: x86_64-apple-darwin + os: macos-latest + - target: aarch64-apple-darwin + os: macos-latest + runs-on: ${{ matrix.os }} + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ needs.release.outputs.tag }} + + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Install cross-compilation tools + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + echo '[target.aarch64-unknown-linux-gnu]' >> ~/.cargo/config.toml + echo 'linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config.toml + + - name: Build binary + run: cargo build --release --target ${{ matrix.target }} -p lgp-cli + + - name: Package binary + run: | + cd target/${{ matrix.target }}/release + tar -czf lgp-${{ matrix.target }}.tar.gz lgp + mv lgp-${{ matrix.target }}.tar.gz "$GITHUB_WORKSPACE/" + + - name: Upload release asset + env: + GH_TOKEN: ${{ github.token }} + run: gh release upload ${{ needs.release.outputs.tag }} lgp-${{ matrix.target }}.tar.gz --clobber + experiments: needs: release if: needs.release.outputs.released == 'true' diff --git a/AGENTS.md b/AGENTS.md index bc926725..6a6f3ff9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,18 +38,18 @@ Pure Rust workspace: | Task | Command | |------|---------| -| Build | `just build` or `cargo build --release` | -| Build (with plots) | `just build-plot` or `cargo build --release --features plot` | -| Test | `just test` or `cargo test --release` | -| Bench | `just bench` or `cargo bench` | -| Lint | `just lint` or `cargo clippy -- -D warnings` | -| Format | `just fmt` or `cargo fmt` | -| Run experiment | `just run ` (e.g., `just run cart_pole_lgp`) | -| List experiments | `just list` | -| Hyperparameter search | `just search ` or `lgp search ` | -| Analyze results | `just analyze` or `lgp analyze` | -| Full pipeline | `just experiment ` (search -> run -> analyze) | -| Setup | `just init` (Rust build + git hooks) | +| Install | `cargo install --path crates/lgp-cli` | +| Build | `cargo build` | +| Build (with plots) | `cargo build --features plot` | +| Test | `cargo test` | +| Bench | `cargo bench` | +| Lint | `cargo clippy -- -D warnings` | +| Format | `cargo fmt` | +| Run experiment | `lgp run ` (e.g., `lgp run cart_pole_lgp`) | +| List experiments | `lgp list` | +| Hyperparameter search | `lgp search ` | +| Analyze results | `lgp analyze` | +| Full pipeline | `lgp experiment ` (search -> run -> analyze) | ## Code Style diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c07dc9e4..b52f9ac9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,6 @@ Ensure you have the following installed: | Tool | Version | Purpose | |------|---------|---------| | Rust | 1.70+ | Core framework | -| just | Latest | Task runner | ### Initial Setup @@ -28,22 +27,11 @@ Ensure you have the following installed: git clone https://github.com/urmzd/linear-gp.git cd linear-gp -# Install just (task runner) -cargo install just +# Install the lgp binary +cargo install --path crates/lgp-cli -# Run setup (builds binary, installs git hooks) -just init - -# Verify everything is working -just verify -just test -``` - -### Manual Setup - -```bash -# Build the project -cargo build --release +# Run tests to verify +cargo test ``` ### IDE Setup @@ -59,20 +47,7 @@ cargo build --release ### Pre-commit Hooks -This project uses custom git hooks in `scripts/` to enforce code quality. - -**Setup:** -```bash -# Install hooks -just init_ - -# Run checks manually -just check -``` - -**Hooks included:** -- **General:** trailing-whitespace, merge-conflict check -- **Rust:** cargo fmt and clippy on commit, cargo test on push +Git hooks are managed by `sr`. See `sr.yaml` for configuration. ## Code Style @@ -83,7 +58,7 @@ We follow standard Rust conventions with some project-specific guidelines: **Formatting:** ```bash # Format all code -just fmt +cargo fmt # Check formatting without modifying cargo fmt -- --check @@ -92,9 +67,6 @@ cargo fmt -- --check **Linting:** ```bash # Run clippy with strict warnings -just lint - -# Or directly cargo clippy -- -D warnings ``` @@ -156,23 +128,20 @@ pub fn run_experiment(name: &str) -> Result<()> { ```bash # Run all tests -just test +cargo test # Run tests for specific crate cargo test -p lgp cargo test -p lgp-cli # Run tests with output -just test-verbose +cargo test -- --nocapture # Run specific test suite cargo test -p lgp iris -# Run with nextest (faster) -just test-nextest - # Run benchmarks -just bench +cargo bench # Test experiment CLI (dry-run) lgp run iris_baseline --dry-run @@ -219,10 +188,10 @@ After making changes that affect evolution: ```bash # Run baseline experiments -just run iris_baseline +lgp run iris_baseline # Generate analysis -just analyze +lgp analyze ``` ## Pull Request Process @@ -249,7 +218,7 @@ just analyze 3. **Run checks locally:** ```bash - just check # Runs fmt, lint, and test + cargo fmt && cargo clippy -- -D warnings && cargo test ``` 4. **Commit your changes:** @@ -273,9 +242,9 @@ just analyze ### PR Requirements -- [ ] All tests pass (`just test`) -- [ ] Code is formatted (`just fmt`) -- [ ] No clippy warnings (`just lint`) +- [ ] All tests pass (`cargo test`) +- [ ] Code is formatted (`cargo fmt`) +- [ ] No clippy warnings (`cargo clippy -- -D warnings`) - [ ] Documentation updated if needed - [ ] Commit messages follow convention - [ ] PR description explains the change diff --git a/README.md b/README.md index 1c045512..0c188985 100644 --- a/README.md +++ b/README.md @@ -48,19 +48,6 @@ Linear Genetic Programming (LGP) is a variant of genetic programming that evolve | Dependency | Version | Installation | |------------|---------|--------------| | Rust | 1.70+ | [rustup.rs](https://rustup.rs/) | -| just | Latest | `cargo install just` | - -**macOS:** -```bash -brew install rust -cargo install just -``` - -**Ubuntu:** -```bash -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -cargo install just -``` ### Installation @@ -69,27 +56,27 @@ cargo install just git clone https://github.com/urmzd/linear-gp.git cd linear-gp -# Build and install git hooks -just init +# Install the lgp binary +cargo install --path crates/lgp-cli ``` ### First Experiment ```bash # List available experiments -just list +lgp list # Run CartPole with pure LGP -just run cart_pole_lgp +lgp run cart_pole_lgp # Run Iris classification -just run iris_baseline +lgp run iris_baseline # Run an example -just run-example cart_pole +lgp example cart_pole # Run benchmarks -just bench +cargo bench ``` ## Packages @@ -285,24 +272,6 @@ Results are saved to: ## Running Experiments -### Quick Start with Just - -```bash -# List available experiments -just list - -# Run individual experiments -just run cart_pole_lgp -just run cart_pole_with_q -just run mountain_car_lgp -just run iris_baseline - -# Run with dry-run to preview config -just run iris_baseline --dry-run -``` - -### Running with lgp - ```bash # Run with default config lgp run cart_pole_lgp @@ -321,7 +290,7 @@ lgp run cart_pole_lgp --override hyperparameters.n_generations=200 lgp analyze # Build with plot feature for PNG chart generation -cargo build --release --features plot +cargo install --path crates/lgp-cli --features plot lgp analyze ``` diff --git a/crates/lgp-cli/README.md b/crates/lgp-cli/README.md index 0a4a3cb3..c8092770 100644 --- a/crates/lgp-cli/README.md +++ b/crates/lgp-cli/README.md @@ -17,10 +17,10 @@ cargo install lgp-cli Or build from source: ```bash -cargo build --release -p lgp-cli +cargo install --path crates/lgp-cli # With plot support (PNG chart generation) -cargo build --release -p lgp-cli --features plot +cargo install --path crates/lgp-cli --features plot ``` ## Usage diff --git a/install.sh b/install.sh new file mode 100755 index 00000000..9f4eac38 --- /dev/null +++ b/install.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO="urmzd/linear-gp" +BINARY="lgp" + +# Allow overriding version; default to latest +VERSION="${LGP_VERSION:-}" +INSTALL_DIR="${LGP_INSTALL_DIR:-/usr/local/bin}" + +die() { echo "error: $*" >&2; exit 1; } + +detect_target() { + local os arch target + + os="$(uname -s)" + arch="$(uname -m)" + + case "$os" in + Linux) os="unknown-linux-gnu" ;; + Darwin) os="apple-darwin" ;; + *) die "unsupported OS: $os" ;; + esac + + case "$arch" in + x86_64|amd64) arch="x86_64" ;; + arm64|aarch64) arch="aarch64" ;; + *) die "unsupported architecture: $arch" ;; + esac + + target="${arch}-${os}" + echo "$target" +} + +get_latest_version() { + local url="https://api.github.com/repos/${REPO}/releases/latest" + local tag + tag="$(curl -fsSL "$url" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"//;s/".*//')" + [ -n "$tag" ] || die "failed to fetch latest release" + echo "$tag" +} + +main() { + local target version archive_name url tmpdir + + target="$(detect_target)" + + if [ -z "$VERSION" ]; then + echo "fetching latest release..." + version="$(get_latest_version)" + else + version="$VERSION" + # Ensure version starts with 'v' + [[ "$version" == v* ]] || version="v${version}" + fi + + archive_name="${BINARY}-${target}.tar.gz" + url="https://github.com/${REPO}/releases/download/${version}/${archive_name}" + + echo "downloading ${BINARY} ${version} for ${target}..." + tmpdir="$(mktemp -d)" + trap 'rm -rf "$tmpdir"' EXIT + + if ! curl -fsSL "$url" -o "${tmpdir}/${archive_name}"; then + die "download failed. Check that ${version} has a prebuilt binary for ${target}. +Available releases: https://github.com/${REPO}/releases" + fi + + echo "extracting..." + tar -xzf "${tmpdir}/${archive_name}" -C "$tmpdir" + + echo "installing to ${INSTALL_DIR}..." + if [ -w "$INSTALL_DIR" ]; then + mv "${tmpdir}/${BINARY}" "${INSTALL_DIR}/${BINARY}" + else + sudo mv "${tmpdir}/${BINARY}" "${INSTALL_DIR}/${BINARY}" + fi + chmod +x "${INSTALL_DIR}/${BINARY}" + + echo "installed ${BINARY} ${version} to ${INSTALL_DIR}/${BINARY}" +} + +main diff --git a/justfile b/justfile index 66213710..5505f478 100644 --- a/justfile +++ b/justfile @@ -1,163 +1,17 @@ # Linear Genetic Programming Framework -# Run `just --list` to see all available recipes -default: - @just --list +# Install binary to PATH +install: + cargo install --path crates/lgp-cli -# === BUILD === - -# Build release binary +# Build debug binary build: - cargo build --release - -# Build with plot feature -build-plot: - cargo build --release --features plot - -# Build with debug symbols -build-dev: cargo build -# Clean build artifacts -clean: - cargo clean - -# === TEST === - # Run all tests test: - cargo test --release - -# Run tests with verbose output -test-verbose: - cargo test --release -- --nocapture - -# Run tests with nextest (faster) -test-nextest: - cargo nextest run --release - -# Run benchmarks -bench: - cargo bench - -# === RUN EXPERIMENTS === - -# Default log level for experiments (can be overridden) -export RUST_LOG := env_var_or_default("RUST_LOG", "lgp=info,lgp_cli=info") - -# Run an experiment by name -run name *args: - cargo run -p lgp-cli --release -- run {{name}} {{args}} - -# Run an experiment with verbose (debug) logging (logs to file) -run-verbose name *args: - RUST_LOG=lgp=debug,lgp_cli=debug cargo run -p lgp-cli --release -- --log-file debug-{{name}}.log run {{name}} {{args}} - -# Run an experiment with trace logging (very verbose, logs to file) -run-trace name *args: - RUST_LOG=lgp=trace,lgp_cli=trace cargo run -p lgp-cli --release -- --log-file trace-{{name}}.log run {{name}} {{args}} - -# Run example by name -run-example name: - cargo run -p lgp-cli --release -- example {{name}} - -# List available experiments -list: - cargo run -p lgp-cli --release -- list - -# List available examples -list-examples: - cargo run -p lgp-cli --release -- example --list - -# === EXPERIMENT PIPELINE === - -# Run full experiment pipeline (search -> run -> analyze) -experiment config="" *args: - cargo run -p lgp-cli --release -- experiment {{config}} {{args}} - -# Run experiments without search (use existing optimal.toml) -experiment-quick config="" n="10": - cargo run -p lgp-cli --release -- experiment {{config}} --skip-search -n {{n}} + cargo test -# === HYPERPARAMETER SEARCH === - -# Search hyperparameters for a config -search config *args: - cargo run -p lgp-cli --release -- search {{config}} {{args}} - -# === ANALYSIS === - -# Analyze experiment results -analyze *args: - cargo run -p lgp-cli --release -- analyze {{args}} - -# === DEVELOPMENT === - -# Format Rust code +# Format code fmt: cargo fmt - -# Run clippy linter -lint: - cargo clippy -- -D warnings - -# Run all checks (format, lint, test) -check: fmt lint test - -# Install git hooks from scripts/ -init_: - cp scripts/pre-commit .git/hooks/pre-commit - cp scripts/pre-push .git/hooks/pre-push - chmod +x .git/hooks/pre-commit .git/hooks/pre-push - @echo "Git hooks installed." - -# Generate and open documentation -docs: - cargo doc --open - -# Watch for changes and run tests -watch: - cargo watch -x test - -# === RELEASE === - -# Preview the next release -release-plan: - sr plan - -# Dry-run a release (no side effects) -release-dry-run: - sr release --dry-run - -# Execute a full release -release: - sr release - -# Generate/update changelog -changelog: - sr changelog - -# Show next version -next-version: - sr version - -# === SETUP === - -# Initialize dev environment: build Rust and install git hooks -init: - #!/usr/bin/env bash - set -euo pipefail - echo "Building release binary..." - cargo build --release - echo "Installing git hooks..." - just init_ - echo "Ready to go." - -# Verify all dependencies are installed -verify: - #!/usr/bin/env bash - set -euo pipefail - echo "Verifying dependencies..." - rustc --version - cargo --version - echo "All dependencies verified!" diff --git a/scripts/compile_latex.sh b/scripts/compile_latex.sh deleted file mode 100755 index 98c7601a..00000000 --- a/scripts/compile_latex.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -# Remove the file extension -filename=$(basename -- "$1") -filename="${filename%.*}" - -# Compile using latexmk, which will handle multiple runs of pdflatex, bibtex, etc. -# Make sure to have the 'latexmk' and 'pygmentize' commands installed on your system. -latexmk -pdf -pdflatex="pdflatex -shell-escape -interaction=nonstopmode" -use-make "$filename.tex" - -# Clean up auxiliary files -latexmk -c "$filename.tex" diff --git a/scripts/pre-commit b/scripts/pre-commit deleted file mode 100755 index ea46fd7e..00000000 --- a/scripts/pre-commit +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -echo "==> Checking for trailing whitespace and merge conflicts..." -git diff --cached --check - -echo "==> Formatting Rust..." -cargo fmt --all -- --check - -echo "==> Running Clippy..." -cargo clippy --all-targets -- -D warnings - -echo "All pre-commit checks passed." diff --git a/scripts/pre-push b/scripts/pre-push deleted file mode 100755 index 162759ae..00000000 --- a/scripts/pre-push +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -echo "==> Running tests..." -cargo test --release - -echo "All pre-push checks passed." diff --git a/skills/lgp-experiment/SKILL.md b/skills/lgp-experiment/SKILL.md index 01e5f775..082a8d01 100644 --- a/skills/lgp-experiment/SKILL.md +++ b/skills/lgp-experiment/SKILL.md @@ -13,13 +13,13 @@ Run and manage LGP experiments. ```sh # List available experiments -just list +lgp list # Run an experiment -just run cart_pole_lgp +lgp run cart_pole_lgp # Run with optimized hyperparameters -just run cart_pole_lgp --config optimal +lgp run cart_pole_lgp --config optimal ``` ## Available Experiments @@ -39,20 +39,20 @@ just run cart_pole_lgp --config optimal ```sh # Search -> Run -> Analyze (end-to-end) -just experiment cart_pole_lgp +lgp experiment cart_pole_lgp # Hyperparameter search only -just search cart_pole_lgp +lgp search cart_pole_lgp # Analyze existing results -just analyze +lgp analyze ``` ## Logging ```sh -RUST_LOG=lgp=debug just run iris_baseline # Debug output -RUST_LOG=lgp=trace just run iris_baseline # Instruction-level trace +RUST_LOG=lgp=debug lgp run iris_baseline # Debug output +RUST_LOG=lgp=trace lgp run iris_baseline # Instruction-level trace ``` ## Output Structure diff --git a/sr.yaml b/sr.yaml index 8a9c7f67..369d911a 100644 --- a/sr.yaml +++ b/sr.yaml @@ -1,32 +1,62 @@ -branches: - - main - -tag_prefix: "v" +# sr configuration — merged with new defaults +# Run 'sr init --force' for a fully-commented template. +branches: +- main +tag_prefix: v types: - - name: feat - bump: minor - section: Features - - name: fix - bump: patch - section: Bug Fixes - - name: perf - bump: patch - section: Performance - - name: docs - section: Documentation - - name: refactor - section: Refactoring - - name: revert - section: Reverts - - name: chore - - name: ci - - name: test - - name: build - - name: style - +- name: feat + bump: minor + section: Features +- name: fix + bump: patch + section: Bug Fixes +- name: perf + bump: patch + section: Performance +- name: docs + section: Documentation +- name: refactor + section: Refactoring +- name: revert + section: Reverts +- name: chore +- name: ci +- name: test +- name: build +- name: style version_files: - - Cargo.toml - +- Cargo.toml changelog: file: CHANGELOG.md + template: null +hooks: + commit-msg: + - sr hook commit-msg + pre-commit: + - step: format + patterns: + - '*.rs' + rules: + - rustfmt --check --edition 2021 {files} + - step: lint + patterns: + - '*.rs' + rules: + - cargo clippy --workspace -- -D warnings + pre-push: + - cargo test --workspace +commit_pattern: ^(?P\w+)(?:\((?P[^)]+)\))?(?P!)?:\s+(?P.+) +breaking_section: Breaking Changes +misc_section: Miscellaneous +version_files_strict: false +artifacts: [] +floating_tags: false +build_command: null +stage_files: [] +prerelease: null +pre_release_command: null +post_release_command: null +sign_tags: false +draft: false +release_name_template: null