diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b1ab7cf..4016297 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,6 +1,6 @@ version: 2 updates: - - package-ecosystem: "cargo" - directory: "/ladderz" # Location of package manifests - schedule: - interval: "weekly" + - package-ecosystem: "cargo" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 6fb0278..10bf6d5 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -18,8 +18,7 @@ jobs: - name: Build Documentation run: | - cd ladderz - cargo doc + cargo doc --no-deps echo '' > ./target/doc/index.html cd .. @@ -27,4 +26,4 @@ jobs: uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./ladderz/target/doc + publish_dir: ./target/doc diff --git a/.gitignore b/.gitignore index 5ceb386..2826e6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,17 @@ -venv +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Python virtual environment +venv \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d64456a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] +resolver = "2" +members = [ + "ladderz", + "lz", +] diff --git a/README.md b/README.md index fc5f021..b535bf2 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,61 @@ The `ladderz` project is a collection of math and tech concepts implemented in code. -- **[`ladderz` crate](https://rzmk.github.io/ladderz/)** - A Rust library crate for running concept implementations +- **[`ladderz` library](https://rzmk.github.io/ladderz/)** - A Rust library for running concept implementations +- **[`lz` CLI](lz)** - A command line tool for running ladderz functions - **[notebooks](notebooks)** - Jupyter notebooks with concept exercises and solutions in Python > If you're looking for a more efficient implementation of a concept (e.g., for use in your programs), other resources may be more useful. -### `ladderz` crate +## Demos -#### Demo +### `lz` CLI Demo -![ladderz-crate-demo](ladderz-crate-demo.png) -![ladderz-crate-demo-output](ladderz-crate-demo-output.png) +### ladderz Library Demo -#### Example +## CLI Example + +The `lz` CLI tool can be used to run ladderz functions from the command line. Built with the [clap](https://clap.rs) crate, users may select a subject and concept to run on their given input. + +First let's install the `lz` CLI tool using [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html): + +```bash +cargo install --git https://github.com/rzmk/ladderz --branch main +``` + +You may read the help text for the `lz` CLI tool and its subcommands with a `-h` or `--help` flag. For example, to read the help text for the `prealgebra` subject run: + +```bash +lz prealgebra -h +``` + +Now let's run the `lz` CLI tool with the `prealgebra` subject and `get-factors` concept as an example. We want to get the factors of the positive integer `12`: + +```bash +lz prealgebra get-factors 12 +``` + +The printed output should be: + +```console +The factors of 12 are {2, 3, 6, 1, 4, 12}. +``` + +We can use the `--raw` flag to get the raw output of the function: + +```bash +lz prealgebra get-factors 12 --raw +``` + +The printed output should be: + +```console +{1, 2, 3, 4, 6, 12} +``` + +Note that the numbers may not be sorted. + +## Library Example Here's an example of using the `ladderz` crate to get the factors and factor pairs of a positive integer in sorted order. @@ -34,7 +76,7 @@ ladderz = { git = "https://github.com/rzmk/ladderz", branch = "main" } Now in `src/main.rs` let's replace the contents with the following code: ```rust -use ladderz::pre_algebra::{get_factors, get_factor_pairs}; +use ladderz::prealgebra::{get_factors, get_factor_pairs}; use std::env; fn main() { @@ -67,7 +109,6 @@ fn main() { None => println!("No input provided."), } } - ``` Now let's build the project's binary file so we can run it from the command line: @@ -109,6 +150,6 @@ Not currently implemented, but ideas that may be useful: - Statistics - Discrete Math - Algorithms -- **py-ladderz** - A package for running implementations of mathematical concepts in Python -- **ladderz CLI** - A CLI tool for ladderz in Rust -- **ladderz App** - An interactive multi-platform (web, desktop, mobile) app potentially including visualizations, practice problems, & a course-like structure (potentially in Flutter or Tauri with Next.js & Rust) + - Bioinformatics +- **ladderz-py** - A package for running implementations of mathematical concepts in Python +- **ladderz-app** - An interactive cross-platform (web, desktop, mobile) app potentially including visualizations, practice problems, & a course-like structure (potentially in Flutter or Tauri with Next.js & Rust) diff --git a/ladderz-crate-demo-output.png b/ladderz-crate-demo-output.png deleted file mode 100644 index 9d25d07..0000000 Binary files a/ladderz-crate-demo-output.png and /dev/null differ diff --git a/ladderz-crate-demo.png b/ladderz-crate-demo.png deleted file mode 100644 index 35e9e47..0000000 Binary files a/ladderz-crate-demo.png and /dev/null differ diff --git a/ladderz/.gitignore b/ladderz/.gitignore deleted file mode 100644 index ada8be9..0000000 --- a/ladderz/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb \ No newline at end of file diff --git a/ladderz/Cargo.toml b/ladderz/Cargo.toml index 424e8a1..23ff4bc 100644 --- a/ladderz/Cargo.toml +++ b/ladderz/Cargo.toml @@ -3,10 +3,4 @@ name = "ladderz" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -name = "ladderz" -path = "src/lib.rs" - [dependencies] diff --git a/ladderz/src/lib.rs b/ladderz/src/lib.rs index 4bab4c8..c29077c 100644 --- a/ladderz/src/lib.rs +++ b/ladderz/src/lib.rs @@ -2,18 +2,18 @@ //! //! Implementations of mathematical and technical concepts in Rust. //! -//! # Installing the crate +//! # Installation //! -//! To add the crate to your project, add the following dependency under your `[dependencies]` section in your `Cargo.toml`: +//! To add the library crate to your project, add the following dependency under your `[dependencies]` section in your `Cargo.toml`: //! //! ```toml //! ladderz = { git = "https://github.com/rzmk/ladderz", branch = "main" } //! ``` -//! +//! //! # Example //! //! ```rust -//!use ladderz::pre_algebra::get_factors; +//!use ladderz::prealgebra::get_factors; //! //!let x: u32 = 10; //!println!("The factors of {x} are {:?}.", get_factors(x)); @@ -23,7 +23,7 @@ //! The factors of 10 are {1, 5, 2, 10}. //! ``` //! -//! For a more detailed example of how to use the `ladderz` crate, please see the [example on GitHub](https://github.com/rzmk/ladderz#example). +//! For a more detailed example of how to use the `ladderz` crate, please see the [library example on GitHub](https://github.com/rzmk/ladderz#library-example). //! //! Choose a module to view its available functions. @@ -32,7 +32,7 @@ /// # Example /// /// ```rust -/// use ladderz::pre_algebra::get_factors; +/// use ladderz::prealgebra::get_factors; /// /// let x: u32 = 10; /// println!("The factors of {x} are {:?}.", get_factors(x)); @@ -42,4 +42,4 @@ /// The factors of 10 are {1, 5, 2, 10}. /// ``` /// -pub mod pre_algebra; +pub mod prealgebra; diff --git a/ladderz/src/pre_algebra.rs b/ladderz/src/prealgebra.rs similarity index 96% rename from ladderz/src/pre_algebra.rs rename to ladderz/src/prealgebra.rs index f69f25f..ab110f0 100644 --- a/ladderz/src/pre_algebra.rs +++ b/ladderz/src/prealgebra.rs @@ -12,7 +12,7 @@ use std::collections::{HashMap, HashSet}; /// /// ```rust /// use std::collections::HashSet; -/// use ladderz::pre_algebra::get_factor_pairs; +/// use ladderz::prealgebra::get_factor_pairs; /// /// let result_pairs = get_factor_pairs(12); /// let expected_pairs: HashSet<(u32, u32)> = [(1, 12), (2, 6), (3, 4)].into(); @@ -53,7 +53,7 @@ pub fn get_factor_pairs(n: u32) -> HashSet<(u32, u32)> { /// /// ```rust /// use std::collections::HashSet; -/// use ladderz::pre_algebra::get_factors; +/// use ladderz::prealgebra::get_factors; /// /// let result_factors = get_factors(16); /// let expected_factors: HashSet = [1, 2, 4, 8, 16].into(); @@ -83,7 +83,7 @@ pub fn get_factors(n: u32) -> HashSet { /// # Examples /// /// ```rust -/// use ladderz::pre_algebra::is_factor; +/// use ladderz::prealgebra::is_factor; /// /// assert!(is_factor(2, 16)); // 2 is a factor of 16 /// assert!(!is_factor(3, 16)); // 3 is not a factor of 16 @@ -104,7 +104,7 @@ pub fn is_factor(x: u32, y: u32) -> bool { /// # Examples /// /// ```rust -/// use ladderz::pre_algebra::is_multiple; +/// use ladderz::prealgebra::is_multiple; /// /// assert!(is_multiple(16, 2)); // 16 is a multiple of 2 /// assert!(!is_multiple(16, 3)); // 16 is not a multiple of 3 @@ -120,7 +120,7 @@ pub fn is_multiple(x: u32, y: u32) -> bool { /// # Examples /// /// ```rust -/// use ladderz::pre_algebra::get_multiples_in_range; +/// use ladderz::prealgebra::get_multiples_in_range; /// use std::collections::HashSet; /// /// let result: HashSet = get_multiples_in_range(2, 10); @@ -144,7 +144,7 @@ pub fn get_multiples_in_range(n: u32, end: u32) -> HashSet { /// # Examples /// /// ```rust -/// use ladderz::pre_algebra::is_prime; +/// use ladderz::prealgebra::is_prime; /// /// assert!(!is_prime(1)); // 1 is not a prime number /// assert!(is_prime(2)); // 2 is a prime number @@ -176,7 +176,7 @@ pub fn is_prime(n: u32) -> bool { /// # Examples /// /// ```rust -/// use ladderz::pre_algebra::is_composite; +/// use ladderz::prealgebra::is_composite; /// /// assert!(!is_composite(1)); // 1 is not a composite number /// assert!(!is_composite(2)); // 2 is not a composite number @@ -200,7 +200,7 @@ pub fn is_composite(n: u32) -> bool { /// # Examples /// /// ```rust -/// use ladderz::pre_algebra::get_primes_in_range; +/// use ladderz::prealgebra::get_primes_in_range; /// use std::collections::HashSet; /// /// let result: HashSet = get_primes_in_range(2, 10); @@ -226,7 +226,7 @@ pub fn get_primes_in_range(start: u32, end: u32) -> HashSet { /// # Examples /// /// ```rust -/// use ladderz::pre_algebra::get_prime_factorization; +/// use ladderz::prealgebra::get_prime_factorization; /// use std::collections::HashMap; /// /// let result: HashMap = get_prime_factorization(12); diff --git a/lz/Cargo.toml b/lz/Cargo.toml new file mode 100644 index 0000000..cc4ed89 --- /dev/null +++ b/lz/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "lz" +version = "0.1.0" +edition = "2021" + +[dependencies] +ladderz = { git = "https://github.com/rzmk/ladderz", branch = "main" } +# For local development, use: +# ladderz = { path = "../ladderz" } +clap = { version = "4.4.12", features = ["derive"] } diff --git a/lz/src/main.rs b/lz/src/main.rs new file mode 100644 index 0000000..46027d4 --- /dev/null +++ b/lz/src/main.rs @@ -0,0 +1,71 @@ +//! # lz +//! +//! A command-line interface for various math/tech subjects. Based on the [ladderz](https://github.com/rzmk/ladderz) library. +//! +//! # Installation +//! +//! To install the command-line interface, run the following command in your terminal: +//! +//! ```bash +//! cargo install --git https://github.com/rzmk/ladderz --branch main +//! ``` +//! +//! # Example +//! +//! ```bash +//! lz prealgebra is-factor 3 12 +//! ``` +//! +//! ```console +//! 3 is a factor of 12. +//! ``` +//! +//! You may view the help menu for a subject and a function by running the command with the `-h` or `--help` flag: +//! +//! ```bash +//! lz prealgebra is-factor -h +//! ``` +//! +//! Learn more on [GitHub](https://github.com/rzmk/ladderz). + +// External modules +use clap::{Parser, Subcommand}; + +// Local modules +pub mod prealgebra; +use prealgebra::{match_prealgebra, Prealgebra}; + +#[derive(Parser)] +#[command( + author = "Mueez Khan", + about = "Run various functions from a range of math/tech subjects on the command line.", + subcommand_value_name = "SUBJECT", + arg_required_else_help(true) +)] +struct Cli { + #[command(subcommand)] + subject: Option, +} + +/// The subjects that can be used. +#[derive(Subcommand)] +#[command(arg_required_else_help(true))] +enum Subjects { + Prealgebra { + /// The function (command) to run. + #[command(subcommand)] + function: Option, + }, +} + +fn main() { + let cli: Cli = Cli::parse(); + + // Match the subject to run the correct function. + match cli.subject { + Some(Subjects::Prealgebra { function }) => match_prealgebra(function), + None => { + println!("Please provide a subject to use."); + } + } +} diff --git a/lz/src/prealgebra.rs b/lz/src/prealgebra.rs new file mode 100644 index 0000000..46298a2 --- /dev/null +++ b/lz/src/prealgebra.rs @@ -0,0 +1,347 @@ +use clap::Subcommand; + +#[derive(Subcommand)] +#[command(arg_required_else_help(true))] +pub enum Prealgebra { + /// Finds all factor pairs for a positive integer. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra factor-pairs 12 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// The factor pairs of 12 are [(1, 12), (2, 6), (3, 4)]. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// [(1, 12), (2, 6), (3, 4)] + /// ``` + FactorPairs { + /// The positive integer to find factor pairs for. + n: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Finds all factors for a positive integer. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra factors 12 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// The factors of 12 are [1, 2, 3, 4, 6, 12]. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// [1, 2, 3, 4, 6, 12] + /// ``` + Factors { + /// The positive integer to find factors for. + n: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Finds all multiples of a positive integer in a given range. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra multiples-in-range 3 10 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// The multiples of 3 in the range [1, 10] are [3, 6, 9]. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// [3, 6, 9] + /// ``` + MultiplesInRange { + /// The positive integer to find multiples for. + n: u32, + /// The upper bound of the range to find multiples in. + upper_bound: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Finds all primes in a given range. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra primes-in-range 1 10 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// The primes in the range [1, 10] are [2, 3, 5, 7]. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// [2, 3, 5, 7] + /// ``` + PrimesInRange { + /// The lower bound of the range to find primes in. + lower_bound: u32, + /// The upper bound of the range to find primes in. + upper_bound: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Finds the prime factorization of a positive integer. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra prime-factorization 12 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// The prime factorization of 12 is {2: 2, 3: 1}. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// {2: 2, 3: 1} + /// ``` + PrimeFactorization { + /// The positive integer to find the prime factorization of. + n: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Determines if a positive integer is composite. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra is-composite 12 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// 12 is composite. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// true + /// ``` + IsComposite { + /// The positive integer to determine if it is composite. + n: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Determines if a positive integer is prime. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra is-prime 12 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// 12 is not prime. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// false + /// ``` + IsPrime { + /// The positive integer to determine if it is prime. + n: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Determines if a positive integer is a factor of another positive integer. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra is-factor 3 12 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// 3 is a factor of 12. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// true + /// ``` + IsFactor { + /// The positive integer to determine if it is a factor. + n: u32, + /// The positive integer to determine if it is a multiple. + m: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, + /// Determines if a positive integer is a multiple of another positive integer. + /// + /// ## Example + /// + /// ### Input + /// + /// ```bash + /// lz prealgebra is-multiple 12 3 + /// ``` + /// + /// ### Output + /// + /// ```bash + /// 12 is a multiple of 3. + /// ``` + /// + /// ## Raw Output (use `-r` or `--raw`) + /// + /// ```bash + /// true + /// ``` + IsMultiple { + /// The positive integer to determine if it is a multiple. + n: u32, + /// The positive integer to determine if it is a factor. + m: u32, + /// Whether or not to return the raw output. + #[arg(short = 'r', long)] + raw: bool, + }, +} + +pub fn match_prealgebra(function: Option) { + use ladderz::prealgebra::*; + match function { + Some(Prealgebra::FactorPairs { n, raw }) => match raw { + true => println!("{:?}", get_factor_pairs(n)), + false => println!("The factor pairs of {} are {:?}.", n, get_factor_pairs(n)), + }, + Some(Prealgebra::Factors { n, raw }) => match raw { + true => println!("{:?}", get_factors(n)), + false => println!("The factors of {} are {:?}.", n, get_factors(n)), + }, + Some(Prealgebra::MultiplesInRange { + n, + upper_bound, + raw, + }) => match raw { + true => println!("{:?}", get_multiples_in_range(n, upper_bound)), + false => println!( + "The multiples of {} in the range [1, {}] are {:?}.", + n, + upper_bound, + get_multiples_in_range(n, upper_bound) + ), + }, + Some(Prealgebra::PrimesInRange { + lower_bound, + upper_bound, + raw, + }) => match raw { + true => println!("{:?}", get_primes_in_range(lower_bound, upper_bound)), + false => println!( + "The primes in the range [{}, {}] are {:?}.", + lower_bound, + upper_bound, + get_primes_in_range(lower_bound, upper_bound) + ), + }, + Some(Prealgebra::PrimeFactorization { n, raw }) => match raw { + true => println!("{:?}", get_prime_factorization(n)), + false => println!( + "The prime factorization of {} is {:?}.", + n, + get_prime_factorization(n) + ), + }, + Some(Prealgebra::IsComposite { n, raw }) => match raw { + true => println!("{:?}", is_composite(n)), + false => println!( + "{} is {}composite.", + n, + if is_composite(n) { "" } else { "not " } + ), + }, + Some(Prealgebra::IsPrime { n, raw }) => match raw { + true => println!("{:?}", is_prime(n)), + false => println!("{} is {}prime.", n, if is_prime(n) { "" } else { "not " }), + }, + Some(Prealgebra::IsFactor { n, m, raw }) => match raw { + true => println!("{:?}", is_factor(n, m)), + false => println!( + "{} is {}a factor of {}.", + n, + if is_factor(n, m) { "" } else { "not " }, + m + ), + }, + Some(Prealgebra::IsMultiple { n, m, raw }) => match raw { + true => println!("{:?}", is_multiple(n, m)), + false => println!( + "{} is {}a multiple of {}.", + n, + if is_multiple(n, m) { "" } else { "not " }, + m + ), + }, + None => { + println!("Please provide a function to use."); + } + } +}