From f8673bbcef779bca84ae24735a98fd768816c19e Mon Sep 17 00:00:00 2001 From: Graham Enos Date: Thu, 2 Jun 2022 12:29:35 -0400 Subject: [PATCH] Update: use lexical for writing floating point values --- Cargo.lock | 74 ++++++++++++++++++++++++++++++++++---- Cargo.toml | 3 +- src/expression.rs | 24 ++++++++++--- src/instruction.rs | 2 +- src/parser/expression.rs | 4 +-- src/program/calibration.rs | 10 +++--- src/program/mod.rs | 6 ++-- 7 files changed, 99 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03618985..902e5089 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,12 +372,11 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lexical" -version = "5.2.2" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f404a90a744e32e8be729034fc33b90cf2a56418fbf594d69aa3c0214ad414e5" +checksum = "c7aefb36fd43fef7003334742cbf77b243fcd36418a1d1bdd480d613a67968f6" dependencies = [ - "cfg-if", - "lexical-core", + "lexical-core 0.8.5", ] [[package]] @@ -393,6 +392,70 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125e1f93e5003d4bd89758c2ca2771bfae13632df633cde581efe07c87d354e5" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.126" @@ -437,7 +500,7 @@ checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" dependencies = [ "bitvec", "funty", - "lexical-core", + "lexical-core 0.7.6", "memchr", "version_check", ] @@ -601,7 +664,6 @@ dependencies = [ "petgraph", "proptest", "proptest-derive", - "ryu", "serde", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 82d88a59..575f2492 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,10 @@ categories = ["parser-implementations", "science", "compilers", "emulators"] [dependencies] dot-writer = { version = "0.1.2", optional = true } indexmap = "1.6.1" -lexical = "5.2.0" +lexical = "6.1.1" nom = "6.1.0" num-complex = "0.4.0" petgraph = "0.5.1" -ryu = "1.0.10" serde = { version = "1.0.125", features = ["derive"] } thiserror = "1.0.30" diff --git a/src/expression.rs b/src/expression.rs index 949d9be1..c8e02cb7 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -17,6 +17,7 @@ use std::collections::{hash_map::DefaultHasher, HashMap}; use std::f64::consts::PI; use std::fmt; use std::hash::{Hash, Hasher}; +use std::num::NonZeroI32; use std::str::FromStr; #[cfg(test)] @@ -435,16 +436,29 @@ impl<'a> FromStr for Expression { /// - When both are non-zero, show with the correct operator in between #[inline(always)] fn format_complex(value: &Complex64) -> String { + const FORMAT: u128 = lexical::format::STANDARD; + let options = lexical::WriteFloatOptions::builder() + .negative_exponent_break(NonZeroI32::new(-5)) + .positive_exponent_break(NonZeroI32::new(15)) + .trim_floats(true) + .build() + .unwrap(); if value.re == 0f64 && value.im == 0f64 { "0".to_owned() } else if value.im == 0f64 { - ryu::Buffer::new().format(value.re).to_owned() + lexical::to_string_with_options::<_, FORMAT>(value.re, &options) } else if value.re == 0f64 { - ryu::Buffer::new().format(value.im).to_owned() + "i" + lexical::to_string_with_options::<_, FORMAT>(value.im, &options) + "i" } else { - let mut buf = ryu::Buffer::new(); - let op = if value.im > 0f64 { "+" } else { "" }; - buf.format(value.re).to_owned() + op + buf.format(value.im) + "i" + let mut out = lexical::to_string_with_options::<_, FORMAT>(value.re, &options); + if value.im > 0f64 { + out.push_str("+") + } + out.push_str(&lexical::to_string_with_options::<_, FORMAT>( + value.im, &options, + )); + out.push_str("i"); + out } } diff --git a/src/instruction.rs b/src/instruction.rs index d2c56b8d..68410d4a 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -886,7 +886,7 @@ impl Instruction { /// let mut instructions = program.to_instructions(true); /// instructions.iter_mut().for_each(|inst| inst.apply_to_expressions(Expression::simplify)); /// - /// assert_eq!(instructions[0].to_string(), String::from("SHIFT-PHASE 0 \"rf\" 4.0")) + /// assert_eq!(instructions[0].to_string(), String::from("SHIFT-PHASE 0 \"rf\" 4")) /// /// ``` pub fn apply_to_expressions(&mut self, mut closure: impl FnMut(&mut Expression)) { diff --git a/src/parser/expression.rs b/src/parser/expression.rs index 1a068413..a9cddba6 100644 --- a/src/parser/expression.rs +++ b/src/parser/expression.rs @@ -261,8 +261,8 @@ mod tests { let cases = vec![ "pi", "sin(pi)", - "(1.0+(2.0*3.0))", - "((1.0+2.0)*3.0)", + "(1+(2*3))", + "((1+2)*3)", "%theta", "cis(%theta)", "(%a+%b)", diff --git a/src/program/calibration.rs b/src/program/calibration.rs index 89bca9ff..3167f94a 100644 --- a/src/program/calibration.rs +++ b/src/program/calibration.rs @@ -353,9 +353,9 @@ mod tests { "RX(pi/2) 0\n" ), expected: concat!( - "PULSE 1 \"xy\" gaussian(duration: 1.0, fwhm: 2.0, t0: 3.0)\n", - "PULSE 2 \"xy\" gaussian(duration: 1.0, fwhm: 2.0, t0: 3.0)\n", - "PULSE 3 \"xy\" gaussian(duration: 1.0, fwhm: 2.0, t0: 3.0)\n" + "PULSE 1 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", + "PULSE 2 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", + "PULSE 3 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n" ), }, TestCase { @@ -364,7 +364,7 @@ mod tests { " PULSE 0 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", "X 0\n" ), - expected: "PULSE 0 \"xy\" gaussian(duration: 1.0, fwhm: 2.0, t0: 3.0)\n", + expected: "PULSE 0 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", }, TestCase { input: concat!( @@ -374,7 +374,7 @@ mod tests { " PULSE 0 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", "X 0\n" ), - expected: "PULSE 0 \"xy\" gaussian(duration: 1.0, fwhm: 2.0, t0: 3.0)\n", + expected: "PULSE 0 \"xy\" gaussian(duration: 1, fwhm: 2, t0: 3)\n", }, TestCase { input: concat!( diff --git a/src/program/mod.rs b/src/program/mod.rs index e18644cf..c4ccab37 100644 --- a/src/program/mod.rs +++ b/src/program/mod.rs @@ -272,7 +272,7 @@ DEFCAL I 0: DEFFRAME 0 \"rx\": HARDWARE-OBJECT: \"hardware\" DEFWAVEFORM custom: - 1.0, 2.0 + 1, 2 I 0 "; let program = Program::from_str(input).unwrap(); @@ -290,9 +290,9 @@ I 0 DEFFRAME 0 \"rx\": \tHARDWARE-OBJECT: \"hardware\" DEFWAVEFORM custom: -\t1.0, 2.0 +\t1, 2 DEFCAL I 0: -\tDELAY 0 1.0 +\tDELAY 0 1 I 0 " );