Skip to content
This repository has been archived by the owner on Jan 8, 2025. It is now read-only.

Commit

Permalink
Translation of MathExpressionTree structs to infix math expression st…
Browse files Browse the repository at this point in the history
…rings. (ml4ai#348)

Incorporating a method called `to_infix_expression()` for
MathExpressionTree that returns strings representing infix mathematical expressions ( e.g., `((α*ρ)*I))` to be used by TA4 to display over transitions in their HMI.

---------

Co-authored-by: Deepsana Shahi <[email protected]>
Co-authored-by: Adarsh Pyarelal <[email protected]>
  • Loading branch information
3 people authored Jul 17, 2023
1 parent d88d335 commit 80a9866
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 1 deletion.
2 changes: 2 additions & 0 deletions skema/skema-rs/mathml/src/ast/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub enum Operator {
Rparen,
Compose,
Factorial,
Exp,
Derivative(Derivative),
// Catchall for operators we haven't explicitly defined as enum variants yet.
Other(String),
Expand All @@ -41,6 +42,7 @@ impl fmt::Display for Operator {
Operator::Derivative(Derivative { order, var_index }) => {
write!(f, "D({order}, {var_index})")
}
Operator::Exp => write!(f, "Exp"),
Operator::Other(op) => write!(f, "{op}"),
}
}
Expand Down
2 changes: 1 addition & 1 deletion skema/skema-rs/mathml/src/bin/mml2pn.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
///! Program to parse MathML and convert it to a Petri Net
//! Program to parse MathML and convert it to a Petri Net
use clap::{Parser, ValueEnum};
use mathml::mml2pn::ACSet;

Expand Down
95 changes: 95 additions & 0 deletions skema/skema-rs/mathml/src/parsers/math_expression_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,48 @@ impl MathExpressionTree {
}
content_mathml
}

/// Translates to infix math expression to provide "string expressions" (e.g. ((α*ρ)*I) )
/// TA-4 uses "string expressions" to display over the transitions in their visual front end.
pub fn to_infix_expression(&self) -> String {
let mut expression = String::new();
match self {
MathExpressionTree::Atom(i) => match i {
MathExpression::Ci(x) => {
expression.push_str(&format!("{}", x.content));
}
MathExpression::Mi(Mi(id)) => {
expression.push_str(&id.to_string());
}
MathExpression::Mn(number) => {
expression.push_str(&number.to_string());
}
MathExpression::Mrow(_) => {
panic!("All Mrows should have been removed by now!");
}
t => panic!("Unhandled MathExpression: {:?}", t),
},

MathExpressionTree::Cons(head, rest) => {
let mut operation = String::new();
match head {
Operator::Add => operation.push('+'),
Operator::Subtract => operation.push('-'),
Operator::Multiply => operation.push('*'),
Operator::Equals => operation.push('='),
Operator::Divide => operation.push('/'),
_ => {}
}
let mut component = Vec::new();
for s in rest {
component.push(s.to_infix_expression());
}
let math_exp = format!("({})", component.join(&operation.to_string()));
expression.push_str(&math_exp);
}
}
expression
}
}

/// Represents a token for the Pratt parsing algorithm.
Expand Down Expand Up @@ -545,3 +587,56 @@ fn test_content_hackathon2_scenario1_eq8() {
"<apply><eq/><ci>β</ci><apply><times/><ci>κ</ci><ci>m</ci></apply></apply>"
);
}

#[test]
fn test_expression1() {
let input = "<math><mi>γ</mi><mi>I</mi></math>";
let exp = input.parse::<MathExpressionTree>().unwrap();
let math = exp.to_infix_expression();
assert_eq!(math, "(γ*I)");
}

#[test]
fn test_expression2() {
let input = "
<math>
<mi>α</mi>
<mi>ρ</mi>
<mi>I</mi><mo>(</mo><mi>t</mi><mo>)</mo>
</math>
";
let exp = input.parse::<MathExpressionTree>().unwrap();
let math = exp.to_infix_expression();
assert_eq!(math, "((α*ρ)*I)");
}

#[test]
fn test_expression3() {
let input = "
<math>
<mi>β</mi>
<mi>I</mi><mo>(</mo><mi>t</mi><mo>)</mo>
<mfrac><mrow><mi>S</mi><mo>(</mo><mi>t</mi><mo>)</mo></mrow><mi>N</mi></mfrac>
<mo>−</mo>
<mi>δ</mi><mi>E</mi><mo>(</mo><mi>t</mi><mo>)</mo>
</math>
";
let exp = input.parse::<MathExpressionTree>().unwrap();
let math = exp.to_infix_expression();
assert_eq!(math, "((((β*I)*S)/N)-(δ*E))")
}

#[test]
fn test_expression4() {
let input = "
<math>
<mo>(</mo><mn>1</mn><mo>−</mo><mi>α</mi><mo>)</mo><mi>γ</mi><mi>I</mi><mo>(</mo><mi>t</mi><mo>)</mo>
<mo>-</mo>
<mi>ϵ</mi>
<mi>R</mi><mo>(</mo><mi>t</mi><mo>)</mo>
</math>
";
let exp = input.parse::<MathExpressionTree>().unwrap();
let math = exp.to_infix_expression();
assert_eq!(math, "((((1-α)*γ)*I)-(ϵ*R))")
}

0 comments on commit 80a9866

Please sign in to comment.