diff --git a/.github/workflows/experiments.yml b/.github/workflows/experiments.yml index 9a99a729..d5a0185c 100644 --- a/.github/workflows/experiments.yml +++ b/.github/workflows/experiments.yml @@ -48,11 +48,11 @@ jobs: - name: Run baseline if: inputs.experiment_type == 'baseline' - run: cargo run -p lgp-cli --release -- experiment iris_baseline --skip-search + run: cargo run -p lgp --release -- experiment iris_baseline --skip-search - name: Run experiments if: inputs.experiment_type == 'experiments' - run: cargo run -p lgp-cli --release -- experiment --skip-search -n ${{ inputs.iterations }} + run: cargo run -p lgp --release -- experiment --skip-search -n ${{ inputs.iterations }} - name: Upload artifacts uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28819c22..4ab8126a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,8 +85,8 @@ jobs: - name: Wait for crates.io index update run: sleep 30 - - name: Publish lgp-cli to crates.io - run: cargo publish -p lgp-cli + - name: Publish lgp to crates.io + run: cargo publish -p lgp env: CARGO_REGISTRY_TOKEN: ${{ steps.crates-token.outputs.token }} @@ -127,7 +127,7 @@ jobs: echo 'linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config.toml - name: Build binary - run: cargo build --release --target ${{ matrix.target }} -p lgp-cli + run: cargo build --release --target ${{ matrix.target }} -p lgp - name: Package binary run: | diff --git a/Cargo.lock b/Cargo.lock index 40e7ef0e..7c795784 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1082,54 +1082,54 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lgp" -version = "1.5.0" +version = "1.6.0" dependencies = [ "chrono", "clap 4.5.58", - "config", - "criterion", + "crossterm", "csv", - "derivative", - "derive_builder", - "derive_more", - "glob", "gymnasia", + "indicatif", "itertools", - "lazy_static", + "lgp-core", + "plotters", "rand", - "rand_xoshiro", "rayon", "serde", "serde_json", - "strum", - "strum_macros", "toml 0.8.23", "tracing", - "tracing-appender", "tracing-subscriber", - "uuid", ] [[package]] -name = "lgp-cli" -version = "1.5.0" +name = "lgp-core" +version = "1.6.0" dependencies = [ "chrono", "clap 4.5.58", - "crossterm", + "config", + "criterion", "csv", + "derivative", + "derive_builder", + "derive_more", + "glob", "gymnasia", - "indicatif", "itertools", - "lgp", - "plotters", + "lazy_static", "rand", + "rand_xoshiro", "rayon", "serde", "serde_json", + "strum", + "strum_macros", "toml 0.8.23", "tracing", + "tracing-appender", "tracing-subscriber", + "uuid", ] [[package]] diff --git a/README.md b/README.md index 9842e531..0f81aaad 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,15 @@ lgp run cart_pole_lgp # Run Iris classification lgp run iris_baseline -# Run a Rust example -lgp example cart_pole +``` + +### Examples + +Run the standalone Rust examples directly with cargo: + +```bash +cargo run -p lgp --example cart_pole --features gym +cargo run -p lgp --example iris_classification ``` ## CLI Reference @@ -109,12 +116,6 @@ lgp analyze --input outputs --output outputs lgp experiment iris_baseline lgp experiment iris_baseline --iterations 20 lgp experiment --skip-search - -# Run a Rust example -lgp example cart_pole - -# List available examples -lgp example --list ``` ### Available Experiments diff --git a/crates/lgp-cli/Cargo.toml b/crates/lgp-cli/Cargo.toml index 714da0be..31155f0d 100644 --- a/crates/lgp-cli/Cargo.toml +++ b/crates/lgp-cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "lgp-cli" +name = "lgp" version.workspace = true edition.workspace = true authors.workspace = true @@ -12,7 +12,7 @@ name = "lgp" path = "src/main.rs" [dependencies] -lgp = { path = "../lgp", version = "1.1", features = ["gym"] } +lgp = { package = "lgp-core", path = "../lgp", version = "1.1", features = ["gym"] } clap = { version = "4.1.8", features = ["derive"] } chrono = "0.4" toml = "0.8" diff --git a/crates/lgp-cli/src/commands/example.rs b/crates/lgp-cli/src/commands/example.rs deleted file mode 100644 index 510cfb81..00000000 --- a/crates/lgp-cli/src/commands/example.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Example command: run Rust examples - -use clap::Args; -use std::fs; -use std::path::Path; -use std::process::Command; - -use crate::ui; - -#[derive(Args)] -pub struct ExampleArgs { - /// Example name to run (without .rs extension) - #[arg(required_unless_present = "list")] - pub name: Option, - - /// List available examples - #[arg(short, long)] - pub list: bool, -} - -pub fn execute(args: &ExampleArgs) -> Result<(), Box> { - if args.list { - list_examples() - } else if let Some(name) = &args.name { - run_example(name) - } else { - Err("Either provide an example name or use --list".into()) - } -} - -fn list_examples() -> Result<(), Box> { - let examples_dir = Path::new("examples"); - - if !examples_dir.exists() { - ui::warn("No examples directory found"); - return Ok(()); - } - - let mut examples: Vec = fs::read_dir(examples_dir)? - .filter_map(|entry| { - let entry = entry.ok()?; - let path = entry.path(); - if path.extension()?.to_str()? == "rs" { - path.file_stem()?.to_str().map(String::from) - } else { - None - } - }) - .collect(); - - if examples.is_empty() { - ui::warn("No examples found in examples/"); - return Ok(()); - } - - examples.sort(); - - ui::header("Available examples"); - for example in examples { - ui::line(&example); - } - ui::info("Run with: lgp example "); - - Ok(()) -} - -fn run_example(name: &str) -> Result<(), Box> { - let example_path = Path::new("examples").join(format!("{}.rs", name)); - - if !example_path.exists() { - return Err(format!( - "Example '{}' not found. Use 'lgp example --list' to see available examples.", - name - ) - .into()); - } - - ui::header(&format!("Running example: {}", name)); - - let sp = ui::spinner("Compiling and running..."); - let status = Command::new("cargo") - .args(["run", "--example", name, "--release"]) - .status()?; - sp.finish_and_clear(); - - if !status.success() { - return Err(format!( - "Example '{}' failed with exit code: {:?}", - name, - status.code() - ) - .into()); - } - - ui::phase_ok(&format!("Example '{}' completed", name)); - - Ok(()) -} diff --git a/crates/lgp-cli/src/commands/mod.rs b/crates/lgp-cli/src/commands/mod.rs index e157583a..1fc01e5b 100644 --- a/crates/lgp-cli/src/commands/mod.rs +++ b/crates/lgp-cli/src/commands/mod.rs @@ -1,5 +1,4 @@ pub mod analyze; -pub mod example; pub mod experiment; pub mod list; pub mod run; diff --git a/crates/lgp-cli/src/main.rs b/crates/lgp-cli/src/main.rs index 7abd7b8f..8e1e655c 100644 --- a/crates/lgp-cli/src/main.rs +++ b/crates/lgp-cli/src/main.rs @@ -61,9 +61,6 @@ enum Commands { /// Run an experiment from config Run(commands::run::RunArgs), - /// Run a Rust example - Example(commands::example::ExampleArgs), - /// Analyze experiment results (generate tables and optional plots) Analyze(commands::analyze::AnalyzeArgs), @@ -103,7 +100,6 @@ fn main() { let result: Result<(), Box> = match cli.command { Commands::List(args) => commands::list::execute(&args), Commands::Run(args) => commands::run::execute(&args), - Commands::Example(args) => commands::example::execute(&args), Commands::Analyze(args) => commands::analyze::execute(&args), Commands::Search(args) => commands::search::execute(&args), Commands::Experiment(args) => commands::experiment::execute(&args), diff --git a/crates/lgp/Cargo.toml b/crates/lgp/Cargo.toml index 9f676dac..5402614d 100644 --- a/crates/lgp/Cargo.toml +++ b/crates/lgp/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "lgp" +name = "lgp-core" version.workspace = true edition.workspace = true authors.workspace = true @@ -7,6 +7,9 @@ description = "A library to solve problems using linear genetic programming" license = "Apache-2.0" repository = "https://github.com/urmzd/linear-gp" +[lib] +name = "lgp" + [dependencies] csv = "1.1" serde = { version = "1.0", features = ["derive"] } @@ -37,6 +40,7 @@ gym = ["dep:gymnasia"] [dev-dependencies] criterion = "0.4.0" +itertools = "0.10" [[bench]] name = "performance_after_training" @@ -46,3 +50,10 @@ required-features = ["gym"] [[bench]] name = "parallel_fitness" harness = false + +[[example]] +name = "cart_pole" +required-features = ["gym"] + +[[example]] +name = "iris_classification" diff --git a/examples/cart_pole.rs b/crates/lgp/examples/cart_pole.rs similarity index 98% rename from examples/cart_pole.rs rename to crates/lgp/examples/cart_pole.rs index eaed7732..b5066328 100644 --- a/examples/cart_pole.rs +++ b/crates/lgp/examples/cart_pole.rs @@ -3,7 +3,7 @@ //! This example demonstrates how to use the LGP framework to evolve programs //! that can balance a pole on a cart (the classic CartPole control problem). //! -//! Run with: `cargo run --example cart_pole` +//! Run with: `cargo run -p lgp --example cart_pole --features gym` use itertools::Itertools; diff --git a/examples/iris_classification.rs b/crates/lgp/examples/iris_classification.rs similarity index 98% rename from examples/iris_classification.rs rename to crates/lgp/examples/iris_classification.rs index 7ed5f31e..3e13cac3 100644 --- a/examples/iris_classification.rs +++ b/crates/lgp/examples/iris_classification.rs @@ -3,7 +3,7 @@ //! This example demonstrates how to use the LGP framework for a classification task //! using the classic Iris flower dataset. //! -//! Run with: `cargo run --example iris_classification` +//! Run with: `cargo run -p lgp --example iris_classification` use itertools::Itertools; diff --git a/teasr.toml b/teasr.toml index d0ea8177..adc88572 100644 --- a/teasr.toml +++ b/teasr.toml @@ -17,7 +17,7 @@ rows = 50 [[scenes.interactions]] type = "type" -text = "RUSTUP_HOME=/Users/urmzd/.rustup CARGO_HOME=/Users/urmzd/.cargo /Users/urmzd/.cargo/bin/cargo run -p lgp-cli -- run iris_baseline 2>&1" +text = "RUSTUP_HOME=/Users/urmzd/.rustup CARGO_HOME=/Users/urmzd/.cargo /Users/urmzd/.cargo/bin/cargo run -p lgp -- run iris_baseline 2>&1" speed = 50 [[scenes.interactions]] type = "key"