Skip to content

Commit

Permalink
Merge pull request #8 from crochethk/dynamic-widths
Browse files Browse the repository at this point in the history
Handle widths dynamically
  • Loading branch information
crochethk authored Jul 26, 2024
2 parents 45bf56d + 2ee387a commit 73f0552
Show file tree
Hide file tree
Showing 6 changed files with 497 additions and 290 deletions.
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "mpa_project"
version = "0.1.0"
edition = "2021"
default-run = "cli"

[dependencies]
rand_pcg = "0.3.1"
Expand All @@ -18,3 +19,8 @@ features = []
doctest = true
name = "mpa_lib"
path = "src/lib.rs"


[[bin]]
name = "cli"
path = "src/bin/mpa_demo_cli.rs"
2 changes: 1 addition & 1 deletion rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fn_single_line = true
use_small_heuristics = "Off"
struct_lit_width = 18 # default: 18; related to use_small_heuristics
single_line_if_else_max_width = 50 # default: 50; related to use_small_heuristics
single_line_if_else_max_width = 90 # default: 50; related to use_small_heuristics
102 changes: 74 additions & 28 deletions src/bin/mpa_demo_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,46 @@
//! in `mpa_lib`.
//!
//! ## Usage
//! Please refer to `mpa_demo_cli --help` for actual usage info.
//!
//! There are two modes. Both have in common, that the user must specify the
//! operation (e.g. "add").
//!
//! ### Random test operations mode
//!
//! This mode is meant to automatically generate and simulate a number of runs of
//! a given operation type, on random operands.
//!
//! There are two randomized aspects here:
//! - the operands' `width`s
//! - the operand value within that random width.
//!
//! The width range can be adjusted by specifying the lower and upper boundaries,
//! so that then `[min_width ≤ width ≤ max_width]`. You can also set a particular
//! width by specify `min_width == max_width`.
//!
//! #### Example
//!
//! - Run 2 random `add` operations _(using `cargo`)_:
//! ```shell
//! cargo run --bin cli -- add -b 10 -n 2
//! ```
//!
//! ### Interactive mode
//!
//! This mode starts an "evaluation loop", where you can manually specify the
//! operands and apply the chosen operation.
//!
//! The `base` for operands and result output can be set to either `10` or `16`.
//!
//! #### Example
//!
//! - Multiply in interactive mode with hexadecimal base _(using `cargo`)_:
//! ```shell
//! cargo run --bin cli -- mul -i --base 16
//! ```
//!
//!
//! Please refer to `cli --help` for further usage info.

use clap::{Parser, ValueEnum};
use mpa_lib::mp_int::*;
Expand All @@ -14,40 +52,45 @@ use rand_pcg::Pcg64Mcg;
use std::{
fmt::{Display, Write as _},
io::{self, stdin, Write as _},
ops::RangeInclusive,
str::FromStr,
};

#[derive(Debug, Parser)]
#[command(version, about, long_about = None, arg_required_else_help = true)]
struct Cli {
pub struct Cli {
#[arg(value_enum)]
operation: Operation,

/// Bit-width of operands to perform tests with
#[arg(long, short, default_value_t = 256)]
width: usize,
/// Lower bit-width boundary for randomly chosen operands (≥64).
#[arg(long, default_value_t = 64)]
min_width: usize,

/// Number of operations to perform
#[arg(long, short('n'), default_value_t = 10)]
/// Upper bit-width boundary for randomly chosen operands (≥64).
#[arg(long, default_value_t = 512)]
max_width: usize,

/// Number of test operations to perform
#[arg(long, short('n'), default_value_t = 5)]
test_count: usize,

/// RNG seed (128 bit integer) used for random operands [default: random]
#[arg(long, short)]
seed: Option<u128>,

/// Manually specify operands in a loop.
/// Interactive mode. Allows manually specify operands in a loop.
/// Enter `q` to quit.
#[arg(long, short, conflicts_with_all(["test_count", "seed"]))]
#[arg(long, short, conflicts_with_all([ "min_width", "max_width", "test_count", "seed"]))]
interactive: bool,

/// Base of the input and output in interactive mode.
#[arg(long, short, conflicts_with_all(["test_count", "seed"]), default_value="10",
#[arg(long, short, conflicts_with_all([ "min_width", "max_width", "test_count", "seed"]), default_value="10",
value_parser(clap::builder::PossibleValuesParser::new(["10", "16"])))]
base: String,
}

#[derive(Debug, Copy, Clone, ValueEnum)]
enum Operation {
pub enum Operation {
Add,
Sub,
Mul,
Expand Down Expand Up @@ -86,6 +129,14 @@ fn main() {
const EXIT_CMD: &str = "q";
fn run_interactive_mode(args: &Cli) {
println!("Enter decimal operand, then hit RETURN");

let base = u32::from_str(args.base.as_str()).unwrap();
let to_base_string: fn(&MPint) -> String = match base {
16 => MPint::to_hex_string,
10 => MPint::to_dec_string,
_ => panic!("illegal base"),
};

loop {
let lhs = match get_operand_from_user(args, "lhs: ") {
UserInputResult::Operand(x) => x,
Expand All @@ -99,21 +150,13 @@ fn run_interactive_mode(args: &Cli) {
UserInputResult::ExitCmd => break,
};

let base = u32::from_str(args.base.as_str()).unwrap();

let adapt_base: fn(&MPint) -> String = match base {
16 => MPint::to_hex_string,
10 => MPint::to_dec_string,
_ => panic!("illegal base"),
};

println!(
">>> Calculating <<<\n{}\n{}\n{}",
adapt_base(&lhs),
to_base_string(&lhs),
args.operation,
adapt_base(&rhs)
to_base_string(&rhs)
);
println!(">>> Result <<<\n{}\n", adapt_base(&args.operation.apply(lhs, rhs)));
println!(">>> Result <<<\n{}\n", to_base_string(&args.operation.apply(lhs, rhs)));
}

println!("Good bye!");
Expand All @@ -137,8 +180,8 @@ fn get_operand_from_user(args: &Cli, msg: &str) -> UserInputResult {

match {
match in_base {
16 => MPint::from_hex_str(&input, args.width),
10 => MPint::from_dec_str(&input, args.width),
16 => MPint::from_hex_str(&input),
10 => MPint::from_dec_str(&input),
_ => panic!("illegal base"),
}
} {
Expand Down Expand Up @@ -169,7 +212,8 @@ fn run_randomized_mode(args: &Cli) {
let mut header = String::new();
_ = writeln!(header, "+----------- Test: lhs {} rhs -----------+", args.operation);
_ = writeln!(header, "| - Mode: Random operands");
_ = writeln!(header, "| - Operands width: {} bits", MPint::new(args.width).width());
_ = writeln!(header, "| - min_width: {} bits", MPint::new_with_width(args.min_width).width());
_ = writeln!(header, "| - max_width: {} bits", MPint::new_with_width(args.max_width).width());
_ = writeln!(header, "| - Test count: {}", args.test_count);
_ = writeln!(header, "+---------------------------------------+");
print!("{}", header);
Expand All @@ -183,8 +227,9 @@ fn run_randomized_mode(args: &Cli) {
let mut test_cnt = args.test_count;
while test_cnt > 0 {
// Get random operands
let lhs = random_mpint(&mut rng, args.width);
let rhs = random_mpint(&mut rng, args.width);
let width_range = args.min_width..=args.max_width;
let lhs = random_mpint(&mut rng, width_range.clone());
let rhs = random_mpint(&mut rng, width_range);

let mut str_buff = String::new();
_ = writeln!(str_buff, "~~~~ TEST {} ~~~~", args.test_count - test_cnt + 1);
Expand All @@ -200,7 +245,8 @@ fn run_randomized_mode(args: &Cli) {
}
}

fn random_mpint<R: RngCore>(rng: &mut R, width: usize) -> MPint {
fn random_mpint<R: RngCore>(rng: &mut R, width_range: RangeInclusive<usize>) -> MPint {
let width = rng.gen_range(width_range);
let mut bins = vec![0 as DigitT; MPint::width_to_bins_count(width)];
rng.fill(&mut bins[..]);

Expand Down
Loading

0 comments on commit 73f0552

Please sign in to comment.