Skip to content

Commit

Permalink
fix[pallas-math]: use malachite as default
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewWestberg committed Sep 12, 2024
1 parent efdc102 commit 518215f
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 145 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ jobs:

- name: Run cargo check Windows
if: matrix.os == 'windows-latest'
run: cargo check --no-default-features --features num
run: cargo check

- name: Run cargo check
if: matrix.os != 'windows-latest'
run: cargo check
run: cargo check --features gmp

test:
name: Test Suite
Expand All @@ -46,7 +46,7 @@ jobs:
toolchain: stable

- name: Run cargo test
run: cargo test
run: cargo test --features gmp

test-windows:
name: Test Suite Windows
Expand All @@ -61,7 +61,7 @@ jobs:
toolchain: stable

- name: Run cargo test
run: cargo test --no-default-features --features num
run: cargo test

lints:
name: Lints
Expand All @@ -82,4 +82,4 @@ jobs:
- name: Run cargo clippy
run: |
cargo clippy -- -D warnings
cargo clippy --no-default-features --features num -- -D warnings
cargo clippy --features gmp -- -D warnings
3 changes: 1 addition & 2 deletions pallas-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ rand_core = "0.6"
pallas-codec = { version = "=0.30.1", path = "../pallas-codec" }
serde = "1.0.143"

# FIXME: This needs to be a properly deployed crate from the input-output-hk/vrf repository after my PR is merged
# The vrf crate has not been fully tested in production environments and still has several upstream issues that
# are open PRs but not merged yet.
vrf_dalek = { git = "https://github.com/AndrewWestberg/vrf", rev = "6fc1440b197098feb6d75e2b71517019b8e2e9c2" }
vrf_dalek = { git = "https://github.com/input-output-hk/vrf", rev = "a3185620b72e6a9647285941b961021186f16693" }

[dev-dependencies]
itertools = "0.13"
Expand Down
7 changes: 2 additions & 5 deletions pallas-math/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,13 @@ authors = ["Andrew Westberg <andrewwestberg@gmail.com>"]
exclude = ["tests/data/*"]

[features]
default = ["gmp"]
gmp = ["dep:gmp-mpfr-sys"]
num = ["dep:num-bigint", "dep:num-integer", "dep:num-traits"]

[dependencies]
gmp-mpfr-sys = { version = "1.6.4", features = ["mpc"], default-features = false, optional = true }
once_cell = "1.19.0"
num-bigint = { version = "0.4.6", optional = true }
num-integer = { version = "0.1.46", optional = true }
num-traits = { version = "0.2.19", optional = true }
malachite = "0.4.16"
malachite-base = "0.4.16"
regex = "1.10.5"
thiserror = "1.0.61"

Expand Down
12 changes: 2 additions & 10 deletions pallas-math/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
pub mod math;

// Ensure only one of `gmp` or `num` is enabled, not both.
#[cfg(all(feature = "gmp", feature = "num"))]
compile_error!("Features `gmp` and `num` are mutually exclusive.");

#[cfg(all(not(feature = "gmp"), not(feature = "num")))]
compile_error!("One of the features `gmp` or `num` must be enabled.");

#[cfg(feature = "gmp")]
pub mod math_gmp;

#[cfg(feature = "num")]
pub mod math_num;
#[cfg(not(feature = "gmp"))]
pub mod math_malachite;
67 changes: 36 additions & 31 deletions pallas-math/src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use std::ops::{Div, Mul, Neg, Sub};
use thiserror::Error;

#[cfg(feature = "gmp")]
use crate::math_gmp::Decimal;
#[cfg(feature = "num")]
use crate::math_num::Decimal;
pub type FixedDecimal = crate::math_gmp::Decimal;
#[cfg(not(feature = "gmp"))]
pub type FixedDecimal = crate::math_malachite::Decimal;

#[derive(Debug, Error)]
pub enum Error {
Expand Down Expand Up @@ -72,63 +72,62 @@ impl From<&str> for ExpOrdering {
pub struct ExpCmpOrdering {
pub iterations: u64,
pub estimation: ExpOrdering,
pub approx: Decimal,
pub approx: FixedDecimal,
}

#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use std::io::BufRead;
use std::path::PathBuf;

#[cfg(feature = "gmp")]
use crate::math_gmp::Decimal;
#[cfg(feature = "num")]
use crate::math_num::Decimal;

use super::*;

#[test]
fn test_fixed_precision() {
let fp: Decimal = Decimal::new(34);
let fp: FixedDecimal = FixedDecimal::new(34);
assert_eq!(fp.precision(), 34);
assert_eq!(fp.to_string(), "0.0000000000000000000000000000000000");
}

#[test]
fn test_fixed_precision_eq() {
let fp1: Decimal = Decimal::new(34);
let fp2: Decimal = Decimal::new(34);
let fp1: FixedDecimal = FixedDecimal::new(34);
let fp2: FixedDecimal = FixedDecimal::new(34);
assert_eq!(fp1, fp2);
}

#[test]
fn test_fixed_precision_from_str() {
let fp: Decimal = Decimal::from_str("1234567890123456789012345678901234", 34).unwrap();
let fp: FixedDecimal =
FixedDecimal::from_str("1234567890123456789012345678901234", 34).unwrap();
assert_eq!(fp.precision(), 34);
assert_eq!(fp.to_string(), "0.1234567890123456789012345678901234");

let fp: Decimal = Decimal::from_str("-1234567890123456789012345678901234", 30).unwrap();
let fp: FixedDecimal =
FixedDecimal::from_str("-1234567890123456789012345678901234", 30).unwrap();
assert_eq!(fp.precision(), 30);
assert_eq!(fp.to_string(), "-1234.567890123456789012345678901234");

let fp: Decimal = Decimal::from_str("-1234567890123456789012345678901234", 34).unwrap();
let fp: FixedDecimal =
FixedDecimal::from_str("-1234567890123456789012345678901234", 34).unwrap();
assert_eq!(fp.precision(), 34);
assert_eq!(fp.to_string(), "-0.1234567890123456789012345678901234");
}

#[test]
fn test_fixed_precision_exp() {
let fp: Decimal = Decimal::from(1u64);
let fp: FixedDecimal = FixedDecimal::from(1u64);
assert_eq!(fp.to_string(), "1.0000000000000000000000000000000000");
let exp_fp = fp.exp();
assert_eq!(exp_fp.to_string(), "2.7182818284590452353602874043083282");
}

#[test]
fn test_fixed_precision_mul() {
let fp1: Decimal = Decimal::from_str("52500000000000000000000000000000000", 34).unwrap();
let fp2: Decimal = Decimal::from_str("43000000000000000000000000000000000", 34).unwrap();
let fp1: FixedDecimal =
FixedDecimal::from_str("52500000000000000000000000000000000", 34).unwrap();
let fp2: FixedDecimal =
FixedDecimal::from_str("43000000000000000000000000000000000", 34).unwrap();
let fp3 = &fp1 * &fp2;
assert_eq!(fp3.to_string(), "22.5750000000000000000000000000000000");
let fp4 = fp1 * fp2;
Expand All @@ -137,8 +136,8 @@ mod tests {

#[test]
fn test_fixed_precision_div() {
let fp1: Decimal = Decimal::from_str("1", 34).unwrap();
let fp2: Decimal = Decimal::from_str("10", 34).unwrap();
let fp1: FixedDecimal = FixedDecimal::from_str("1", 34).unwrap();
let fp2: FixedDecimal = FixedDecimal::from_str("10", 34).unwrap();
let fp3 = &fp1 / &fp2;
assert_eq!(fp3.to_string(), "0.1000000000000000000000000000000000");
let fp4 = fp1 / fp2;
Expand All @@ -147,9 +146,9 @@ mod tests {

#[test]
fn test_fixed_precision_sub() {
let fp1: Decimal = Decimal::from_str("1", 34).unwrap();
let fp1: FixedDecimal = FixedDecimal::from_str("1", 34).unwrap();
assert_eq!(fp1.to_string(), "0.0000000000000000000000000000000001");
let fp2: Decimal = Decimal::from_str("10", 34).unwrap();
let fp2: FixedDecimal = FixedDecimal::from_str("10", 34).unwrap();
assert_eq!(fp2.to_string(), "0.0000000000000000000000000000000010");
let fp3 = &fp1 - &fp2;
assert_eq!(fp3.to_string(), "-0.0000000000000000000000000000000009");
Expand All @@ -172,20 +171,20 @@ mod tests {
let file = File::open(data_path).expect("golden_tests_result.txt: file not found");
let result_reader = std::io::BufReader::new(file);

let one: Decimal = Decimal::from(1u64);
let ten: Decimal = Decimal::from(10u64);
let f: Decimal = &one / &ten;
let one: FixedDecimal = FixedDecimal::from(1u64);
let ten: FixedDecimal = FixedDecimal::from(10u64);
let f: FixedDecimal = &one / &ten;
assert_eq!(f.to_string(), "0.1000000000000000000000000000000000");

for (test_line, result_line) in reader.lines().zip(result_reader.lines()) {
let test_line = test_line.expect("failed to read line");
// println!("test_line: {}", test_line);
let mut parts = test_line.split_whitespace();
let x = Decimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION)
let x = FixedDecimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION)
.expect("failed to parse x");
let a = Decimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION)
let a = FixedDecimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION)
.expect("failed to parse a");
let b = Decimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION)
let b = FixedDecimal::from_str(parts.next().unwrap(), DEFAULT_PRECISION)
.expect("failed to parse b");
let result_line = result_line.expect("failed to read line");
// println!("result_line: {}", result_line);
Expand All @@ -210,7 +209,13 @@ mod tests {
let c = &one - &f;
assert_eq!(c.to_string(), "0.9000000000000000000000000000000000");
let threshold_b = c.pow(&b);
assert_eq!((&one - &threshold_b).to_string(), expected_threshold_b);
assert_eq!(
(&one - &threshold_b).to_string(),
expected_threshold_b,
"(1 - f) *** b failed to match! - (1 - f)={}, b={}",
&c,
&b
);

// do Taylor approximation for
// a < 1 - (1 - f) *** b <=> 1/(1-a) < exp(-b * ln' (1 - f))
Expand Down
13 changes: 13 additions & 0 deletions pallas-math/src/math_gmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ impl Neg for Decimal {
}
}

// Implement Neg for a reference to Decimal
impl<'a> Neg for &'a Decimal {
type Output = Decimal;

fn neg(self) -> Self::Output {
unsafe {
let mut result = Decimal::new(self.precision);
mpz_neg(&mut result.data, &self.data);
result
}
}
}

impl Mul for Decimal {
type Output = Self;

Expand Down
Loading

0 comments on commit 518215f

Please sign in to comment.