I've been working on a project to create a Computer Algebra System (CAS) in Rust. My goal is to build something similar to CAS systems available in C, C++, and Python with the added twist of describing the steps to a human much like this library which I found later on, during the creating of my idea. But that feature isn't the problem.
There is another similar CAS Crate in rust however it's not been updated in 3 years and is not documented
In C, C++, and Python, there are established CAS systems (which I can't make heads or tails of), but in Rust, I'm a bit lost on how to proceed. Traditional expression trees use nodes
, however in Rust often enums are used for the same thing.
Now, I've managed to create a Term
struct that handles expressions like 4x^6 * 7xyz
and all the other arithmetic operations like + - * /
(with other basic things like TryFrom<&str> or std::fmt::Display
) and produces the correct output.
/// Represents a collection of variables, each associated with a numerical value.
/// The `Variables` type is an alias for `BTreeMap<char, Number>`.
pub type Variables = BTreeMap<char,num_notation::Number>;
/// A struct representing a mathematical term.
///
/// A `Term` is a basic unit in a mathematical expression. It consists of a coefficient and variables represented as `BTreeMap<char,Number>` .
#[derive(Debug,PartialEq,Clone)]
pub struct Term {
/// The coefficient of the term.
coefficient: num_notation::Number,
/// The variables and their exponents in the term.
variables : Variables,
}
// ...
However, I'm struggling with the next step : how to perform expression operations on these terms with algebra (with only numbers its quite easy ).
Note : I should mention that I've previously attempted a similar project in C++, but the implementation is far from ideal. It relies on lists and lacks the extendability, maintainability, speed and accuracy I'm aiming for in my Rust project
So basically I've started with something like this:
/// An enum representing a mathematical expression.
///
/// The `Expression` enum allows building complex mathematical expressions
#[derive(Debug)]
pub enum Expression {
/// Represents a basic unit in a mathematical expression.
Term(Term),
/// Represents the addition of two terms.
///
/// The `Plus` variant is a binary operator (+) that takes two `Term` values as its operands.
Plus(Box<Expression>,Box<Expression>),
/// Represents the subtraction of two terms.
///
/// The `Minus` variant is a binary operator (-) that takes two `Term` values as its operands.
Minus(Box<Expression>,Box<Expression>),
/// Represents the multiplication of two terms.
///
/// The `Mal` variant is a binary operator (*) that takes two `Term` values as its operands.
Mal(Box<Expression>,Box<Expression>),
/// Represents the division of two terms.
///
/// The `Durch` variant is a binary operator (/) that takes two `Term` values as its operands.
Durch(Box<Expression>,Box<Expression>),
/// Represents a more complex expression that contains nested expressions that contain `()`
Nested(Box<Expression>),
}
I have created some utilitiy functions for this
impl Expression {
/// Create a new `Expression` containing a single `Term`.
///
/// The `new_term` function wraps the provided `Term` into an `Expression::Term` variant.
pub fn new_term(term: Term) -> Self {
Expression::Term(term)
}
/// Create a new `Expression` representing the addition of two expressions.
///
/// The `new_plus` function constructs an `Expression` with the `Expression::Plus` variant,
/// combining two expressions as operands in an addition operation (`+`).
pub fn new_plus(left: Expression, right: Expression) -> Self {
Expression::Plus(Box::new(left), Box::new(right))
}
/// Create a new `Expression` representing the subtraction of two expressions.
///
/// The `new_minus` function constructs an `Expression` with the `Expression::Minus` variant,
/// combining two expressions as operands in a subtraction operation (`-`).
pub fn new_minus(left: Expression, right: Expression) -> Self {
Expression::Minus(Box::new(left), Box::new(right))
}
/// Create a new `Expression` representing the multiplication of two expressions.
///
/// The `new_mal` function constructs an `Expression` with the `Expression::Mal` variant,
/// combining two expressions as operands in a multiplication operation (`*`).
pub fn new_mal(left: Expression, right: Expression) -> Self {
Expression::Mal(Box::new(left), Box::new(right))
}
/// Create a new `Expression` representing the division of two expressions.
///
/// The `new_durch` function constructs an `Expression` with the `Expression::Durch` variant,
/// combining two expressions as operands in a division operation (`/`).
pub fn new_durch(left: Expression, right: Expression) -> Self {
Expression::Durch(Box::new(left), Box::new(right))
}
}
For evalutation I believe something like tihs could be used
impl Expression {
/// Evaluates the expression and returns the result as a new `Expression`.
///
/// This function recursively evaluates the expression tree and returns the result
/// as a new `Expression`. The evaluation process takes into account the values
/// of any variables that are present in the expression. If the expression contains
/// nested expressions, they will be evaluated as well.
pub fn evaluate(&self) -> Self {
match self {
Expression::Plus(left, right) => left.clone() + right.clone(),
Expression::Minus(left, right) => left.clone() - right.clone(),
Expression::Mal(left, right) => left.clone() * right.clone(),
Expression::Durch(left, right) => left.clone() / right.clone(),
Expression::Term(term) => Expression::Term(term.clone()),
// mostly would not work correctly
Expression::Nested(inner) => inner.evaluate()
}
}
}
However this requires + - * /
between the expressions , and I can't seem to find any 'tutorials' or resources for this. But I'm uncertain about how to implement the evaluation of complex expressions and handle operations between them.
If anyone has experience with building CAS systems or has insights into how I can implement arithmetic operations on expression with algebra in Rust, I would greatly appreciate your guidance and suggestions!
Thank you in advance for your help!