Skip to content

Commit

Permalink
Allow wildcards in Relation evaluation
Browse files Browse the repository at this point in the history
- Rename fun! to function!
- Allow empty function in function! macro
- Implement Display for Replacement and PatternRestriction
  • Loading branch information
benruijl committed Feb 2, 2025
1 parent 4cbdf48 commit 728ee05
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 21 deletions.
4 changes: 2 additions & 2 deletions examples/builder.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use symbolica::{fun, symbol};
use symbolica::{function, symbol};

fn main() {
let (x, y, f) = symbol!("x", "y", "f");

let f = fun!(f, x, y, 2);
let f = function!(f, x, y, 2);

let xb = (-(y + x + 2) * y * 6).npow(5) / y * f / 4;

Expand Down
6 changes: 3 additions & 3 deletions examples/collect.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use symbolica::{
atom::{Atom, AtomCore},
fun, parse, symbol,
function, parse, symbol,
};

fn main() {
Expand Down Expand Up @@ -31,11 +31,11 @@ fn main() {
&x,
Some(Box::new(move |a, out| {
out.set_from_view(&a);
*out = fun!(key, out);
*out = function!(key, out);
})),
Some(Box::new(move |a, out| {
out.set_from_view(&a);
*out = fun!(coeff, out);
*out = function!(coeff, out);
})),
);
println!("\t{}", out);
Expand Down
37 changes: 28 additions & 9 deletions src/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
//! Define a function with attributes and use it in an expression:
//!
//! ```
//! use symbolica::{fun, parse, symbol};
//! use symbolica::{function, parse, symbol};
//! use symbolica::atom::{Symbol, FunctionAttribute, Atom, AtomCore};
//!
//! let f = symbol!("f"; Symmetric).unwrap();
//! let expr = fun!(f, 3, 2) + (1, 4);
//! let expr = function!(f, 3, 2) + (1, 4);
//! let p = parse!("f(2,3) + 1/4").unwrap();
//! assert_eq!(expr, p);
//! ```
Expand Down Expand Up @@ -638,6 +638,19 @@ pub enum AtomType {
Fun,
}

impl std::fmt::Display for AtomType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AtomType::Num => write!(f, "Num"),
AtomType::Var => write!(f, "Var"),
AtomType::Add => write!(f, "Add"),
AtomType::Mul => write!(f, "Mul"),
AtomType::Pow => write!(f, "Pow"),
AtomType::Fun => write!(f, "Fun"),
}
}
}

/// The type (variant) of a slice.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SliceType {
Expand Down Expand Up @@ -1020,11 +1033,11 @@ impl<'a> AtomView<'a> {
/// Define a function with attributes and use it in an expression:
///
/// ```
/// use symbolica::{fun, parse, symbol};
/// use symbolica::{function, parse, symbol};
/// use symbolica::atom::{Symbol, FunctionAttribute, Atom, AtomCore};
///
/// let f = symbol!("f"; Symmetric).unwrap();
/// let expr = fun!(f, 3, 2) + (1, 4);
/// let expr = function!(f, 3, 2) + (1, 4);
/// let p = parse!("f(2,3) + 1/4").unwrap();
/// assert_eq!(expr, p);
/// ```
Expand Down Expand Up @@ -1402,6 +1415,7 @@ impl Atom {
/// println!("{}", a);
/// # }
/// ```
#[derive(Clone)]
pub struct FunctionBuilder {
handle: RecycledAtom,
}
Expand Down Expand Up @@ -1498,12 +1512,17 @@ impl<'a, T: Into<Coefficient> + Clone> FunctionArgument for T {
/// # Examples
///
/// ```
/// use symbolica::{atom::Atom, atom::Symbol, fun, symbol, parse};
/// use symbolica::{atom::Atom, atom::Symbol, function, symbol, parse};
/// let f_id = symbol!("f");
/// let f = fun!(f_id, Atom::new_num(3), parse!("x").unwrap());
/// let f = function!(symbol!("f"), 3, parse!("x").unwrap());
/// ```
#[macro_export]
macro_rules! fun {
macro_rules! function {
($name: expr) => {
{
$crate::atom::FunctionBuilder::new($name).finish()
}
};
($name: expr, $($id: expr),*) => {
{
let mut f = $crate::atom::FunctionBuilder::new($name);
Expand Down Expand Up @@ -2249,7 +2268,7 @@ impl AsRef<Atom> for Atom {
mod test {
use crate::{
atom::{Atom, AtomCore},
fun,
function,
};

#[test]
Expand Down Expand Up @@ -2282,7 +2301,7 @@ mod test {
let v2 = parse!("v2").unwrap();
let f1_id = symbol!("f1");

let f1 = fun!(f1_id, v1, v2, Atom::new_num(2));
let f1 = function!(f1_id, v1, v2, Atom::new_num(2));

let r = (-(&v2 + &v1 + 2) * &v2 * 6).npow(5) / &v2.pow(&v1) * &f1 / 4;

Expand Down
6 changes: 3 additions & 3 deletions src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ impl<'a> AtomView<'a> {
mod test {
use crate::{
atom::{representation::InlineVar, Atom, AtomCore},
fun, parse, symbol,
function, parse, symbol,
};

#[test]
Expand Down Expand Up @@ -646,11 +646,11 @@ mod test {
x.into(),
Some(Box::new(move |a, out| {
out.set_from_view(&a);
*out = fun!(key, out);
*out = function!(key, out);
})),
Some(Box::new(move |a, out| {
out.set_from_view(&a);
*out = fun!(coeff, out);
*out = function!(coeff, out);
})),
);

Expand Down
68 changes: 64 additions & 4 deletions src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ pub enum Pattern {
Transformer(Box<(Option<Pattern>, Vec<Transformer>)>),
}

impl From<Symbol> for Pattern {
/// Convert the symbol to a pattern.
///
/// # Examples
///
/// ```
/// use symbolica::{symbol, id::Pattern};
///
/// let p = symbol!("x_").into();
/// assert!(matches!(p, Pattern::Wildcard(_)));
/// ```
fn from(symbol: Symbol) -> Pattern {
InlineVar::new(symbol).to_pattern()
}
}

impl From<Atom> for Pattern {
fn from(atom: Atom) -> Self {
Pattern::new(atom)
Expand Down Expand Up @@ -165,6 +181,27 @@ pub struct Replacement {
settings: Option<MatchSettings>,
}

impl std::fmt::Display for Replacement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} -> {}", self.pat, self.rhs)?;

if let Some(c) = &self.conditions {
write!(f, "; {}", c)?;
}

Ok(())
}
}

impl std::fmt::Display for PatternOrMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PatternOrMap::Pattern(p) => write!(f, "{}", p),
PatternOrMap::Map(_) => write!(f, "Map"),
}
}
}

impl Replacement {
pub fn new<R: Into<PatternOrMap>>(pat: Pattern, rhs: R) -> Self {
Replacement {
Expand Down Expand Up @@ -1738,6 +1775,20 @@ pub enum WildcardRestriction {
NotGreedy,
}

impl std::fmt::Display for WildcardRestriction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WildcardRestriction::Length(min, Some(max)) => write!(f, "length={}-{}", min, max),
WildcardRestriction::Length(min, None) => write!(f, "length > {}", min),
WildcardRestriction::IsAtomType(t) => write!(f, "type = {}", t),
WildcardRestriction::IsLiteralWildcard(s) => write!(f, "= {}", s),
WildcardRestriction::Filter(_) => write!(f, "filter"),
WildcardRestriction::Cmp(s, _) => write!(f, "cmp with {}", s),
WildcardRestriction::NotGreedy => write!(f, "not greedy"),
}
}
}

pub type WildcardAndRestriction = (Symbol, WildcardRestriction);

/// A restriction on a wildcard or wildcards.
Expand All @@ -1749,6 +1800,15 @@ pub enum PatternRestriction {
MatchStack(Box<dyn MatchStackFn>),
}

impl std::fmt::Display for PatternRestriction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PatternRestriction::Wildcard((s, r)) => write!(f, "{}: {}", s, r),
PatternRestriction::MatchStack(_) => write!(f, "match_function"),
}
}
}

impl Clone for PatternRestriction {
fn clone(&self) -> Self {
match self {
Expand Down Expand Up @@ -1977,12 +2037,12 @@ impl Evaluate for Relation {
| Relation::Lt(a, b)
| Relation::Le(a, b)
| Relation::Contains(a, b) => {
a.replace_wildcards_with_matches_impl(ws, &mut out1, &m, false, pat.as_ref())
a.replace_wildcards_with_matches_impl(ws, &mut out1, &m, true, pat.as_ref())
.map_err(|e| match e {
TransformerError::Interrupt => "Interrupted by user".into(),
TransformerError::ValueError(v) => v,
})?;
b.replace_wildcards_with_matches_impl(ws, &mut out2, &m, false, pat.as_ref())
b.replace_wildcards_with_matches_impl(ws, &mut out2, &m, true, pat.as_ref())
.map_err(|e| match e {
TransformerError::Interrupt => "Interrupted by user".into(),
TransformerError::ValueError(v) => v,
Expand All @@ -2000,7 +2060,7 @@ impl Evaluate for Relation {
}
}
Relation::Matches(a, pattern, cond, settings) => {
a.replace_wildcards_with_matches_impl(ws, &mut out1, &m, false, pat.as_ref())
a.replace_wildcards_with_matches_impl(ws, &mut out1, &m, true, pat.as_ref())
.map_err(|e| match e {
TransformerError::Interrupt => "Interrupted by user".into(),
TransformerError::ValueError(v) => v,
Expand All @@ -2011,7 +2071,7 @@ impl Evaluate for Relation {
.is_some()
}
Relation::IsType(a, b) => {
a.replace_wildcards_with_matches_impl(ws, &mut out1, &m, false, pat.as_ref())
a.replace_wildcards_with_matches_impl(ws, &mut out1, &m, true, pat.as_ref())
.map_err(|e| match e {
TransformerError::Interrupt => "Interrupted by user".into(),
TransformerError::ValueError(v) => v,
Expand Down

0 comments on commit 728ee05

Please sign in to comment.