diff --git a/src/api/python.rs b/src/api/python.rs index 881d9142..d1bf2dc1 100644 --- a/src/api/python.rs +++ b/src/api/python.rs @@ -2209,6 +2209,11 @@ impl PythonExpression { self.expr.clone().into() } + /// Convert the expression into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(self.to_string()) + } + /// Convert the expression into a human-readable string. pub fn __str__(&self) -> PyResult { Ok(format!("{}", AtomPrinter::new(self.expr.as_view()))) @@ -4572,6 +4577,11 @@ impl PythonSeries { } } + /// Convert the series into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!("{}", self.series)) + } + pub fn __str__(&self) -> PyResult { Ok(format!("{}", self.series)) } @@ -5040,6 +5050,17 @@ impl PythonPolynomial { )) } + /// Convert the polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + PolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file() + } + )) + } + /// Print the polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -5724,6 +5745,17 @@ impl PythonFiniteFieldPolynomial { )) } + /// Convert the polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + PolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file() + } + )) + } + /// Print the polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -6294,6 +6326,17 @@ impl PythonPrimeTwoPolynomial { )) } + /// Convert the polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + PolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file() + } + )) + } + /// Print the polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -6829,6 +6872,17 @@ impl PythonGaloisFieldPrimeTwoPolynomial { )) } + /// Convert the polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + PolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file() + } + )) + } + /// Print the polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -7368,6 +7422,17 @@ impl PythonGaloisFieldPolynomial { )) } + /// Convert the polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + PolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file() + } + )) + } + /// Print the polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -7908,6 +7973,17 @@ impl PythonNumberFieldPolynomial { )) } + /// Convert the polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + PolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file() + } + )) + } + /// Print the polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -8446,6 +8522,18 @@ impl PythonRationalPolynomial { Ok(var_list) } + /// Convert the rational polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + RationalPolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file(), + add_parentheses: false, + } + )) + } + /// Print the rational polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -8760,6 +8848,18 @@ impl PythonFiniteFieldRationalPolynomial { Ok(var_list) } + /// Convert the rational polynomial into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!( + "{}", + RationalPolynomialPrinter { + poly: &self.poly, + opts: PrintOptions::file(), + add_parentheses: false, + } + )) + } + /// Print the rational polynomial in a human-readable format. pub fn __str__(&self) -> PyResult { Ok(format!( @@ -9595,6 +9695,11 @@ impl PythonMatrix { } } + /// Convert the matrix into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!("{}", self.matrix)) + } + /// Convert the matrix into a human-readable string. pub fn __str__(&self) -> PyResult { Ok(format!("{}", self.matrix)) @@ -10081,6 +10186,11 @@ impl PythonGraph { } } + /// Convert the graph into a portable string. + pub fn __repr__(&self) -> PyResult { + Ok(format!("{}", self.graph)) + } + /// Print the graph in a human-readable format. fn __str__(&self) -> String { format!("{}", self.graph) diff --git a/src/atom.rs b/src/atom.rs index 59f0c43d..89f20cb1 100644 --- a/src/atom.rs +++ b/src/atom.rs @@ -6,8 +6,9 @@ use representation::{InlineNum, InlineVar}; use crate::{ coefficient::Coefficient, parser::Token, - printer::AtomPrinter, + printer::{AtomPrinter, PrintOptions}, state::{RecycledAtom, Workspace}, + transformer::StatsOptions, }; use std::{cmp::Ordering, hash::Hash, ops::DerefMut, str::FromStr}; @@ -346,6 +347,20 @@ impl<'a> AtomView<'a> { target.set_from_view(self); } + /// Print the view using the portable [`PrintOptions::file()`] options. + pub fn to_string(&self) -> String { + format!("{}", self.printer(PrintOptions::file())) + } + + /// Print statistics about the operation `op`, such as its duration and term growth. + pub fn with_stats Atom>(&self, op: F, o: &StatsOptions) -> Atom { + let t = std::time::Instant::now(); + let out = op(*self); + let dt = t.elapsed(); + o.print(*self, out.as_view(), dt); + out + } + #[inline] pub fn is_zero(&self) -> bool { if let AtomView::Num(n) = self { @@ -616,6 +631,16 @@ impl Atom { self.as_view().is_one() } + /// Print the atom using the portable [`PrintOptions::file()`] options. + pub fn to_string(&self) -> String { + format!("{}", self.printer(PrintOptions::file())) + } + + /// Print statistics about the operation `op`, such as its duration and term growth. + pub fn with_stats Atom>(&self, op: F, o: &StatsOptions) -> Atom { + self.as_view().with_stats(op, o) + } + /// Repeatedly apply an operation on the atom until the atom no longer changes. pub fn repeat_map Atom>(&mut self, op: F) { let mut res; diff --git a/src/id.rs b/src/id.rs index 64d56b9e..f1c51727 100644 --- a/src/id.rs +++ b/src/id.rs @@ -1369,6 +1369,8 @@ impl Condition { match r { WildcardRestriction::Cmp(v, _) if *v == var => {} _ => { + // TODO: we can actually return True if the v is in the match stack + // same for cmp if both are in the stack return ConditionResult::Inconclusive; } } diff --git a/src/transformer.rs b/src/transformer.rs index 5207fd25..c78105b4 100644 --- a/src/transformer.rs +++ b/src/transformer.rs @@ -50,6 +50,50 @@ impl StatsOptions { pub fn format_count(&self, count: usize) -> String { format!("{}", count) } + + pub fn print(&self, input: AtomView, output: AtomView, dt: std::time::Duration) { + let in_nterms = if let AtomView::Add(a) = input { + a.get_nargs() + } else { + 1 + }; + let in_size = input.get_byte_size(); + + let out_nterms = if let AtomView::Add(a) = output { + a.get_nargs() + } else { + 1 + }; + let out_size = output.get_byte_size(); + + let in_nterms_s = self.format_count(in_nterms); + let out_nterms_s = self.format_count(out_nterms); + + println!( + "Stats for {}: +\tIn │ {:>width$} │ {:>8} │ +\tOut │ {:>width$} │ {:>8} │ ⧗ {:#.2?}", + self.tag.bold(), + in_nterms_s, + self.format_size(in_size), + if out_nterms as f64 / in_nterms as f64 + > self.color_medium_change_threshold.unwrap_or(f64::INFINITY) + { + if out_nterms as f64 / in_nterms as f64 + > self.color_large_change_threshold.unwrap_or(f64::INFINITY) + { + out_nterms_s.red() + } else { + out_nterms_s.bright_magenta() + } + } else { + out_nterms_s.as_str().into() + }, + self.format_size(out_size), + dt, + width = in_nterms_s.len().max(out_nterms_s.len()).min(6), + ); + } } #[derive(Clone, Debug)] @@ -719,50 +763,10 @@ impl Transformer { std::mem::swap(out, &mut tmp); } Transformer::Stats(o, r) => { - let in_nterms = if let AtomView::Add(a) = cur_input { - a.get_nargs() - } else { - 1 - }; - let in_size = cur_input.get_byte_size(); - let t = Instant::now(); Self::execute_chain(cur_input, r, workspace, out)?; - - let out_nterms = if let AtomView::Add(a) = out.as_view() { - a.get_nargs() - } else { - 1 - }; - let out_size = out.as_view().get_byte_size(); - - let in_nterms_s = o.format_count(in_nterms); - let out_nterms_s = o.format_count(out_nterms); - - println!( - "Stats for {}: -\tIn │ {:>width$} │ {:>8} │ -\tOut │ {:>width$} │ {:>8} │ ⧗ {:#.2?}", - o.tag.bold(), - in_nterms_s, - o.format_size(in_size), - if out_nterms as f64 / in_nterms as f64 - > o.color_medium_change_threshold.unwrap_or(f64::INFINITY) - { - if out_nterms as f64 / in_nterms as f64 - > o.color_large_change_threshold.unwrap_or(f64::INFINITY) - { - out_nterms_s.red() - } else { - out_nterms_s.bright_magenta() - } - } else { - out_nterms_s.as_str().into() - }, - o.format_size(out_size), - Instant::now().duration_since(t), - width = in_nterms_s.len().max(out_nterms_s.len()).min(6), - ); + let dt = t.elapsed(); + o.print(cur_input, out.as_view(), dt); } Transformer::FromNumber => { if let AtomView::Num(n) = cur_input {