Skip to content

Commit

Permalink
Merge pull request #1 from 0xb-s/add-equation-solver
Browse files Browse the repository at this point in the history
Add equation solver
  • Loading branch information
0xb-s authored Sep 18, 2024
2 parents c1d83cd + ac6f273 commit f66132a
Show file tree
Hide file tree
Showing 11 changed files with 1,867 additions and 70 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ edition = "2021"

[[example]]
name = "foo"
[[example]]
name = "bar"
21 changes: 21 additions & 0 deletions examples/bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use math::solver::solve_equation;

fn main() {
let equations = vec![
"2x + 3 = 7",
"x/0 = 5",
"x^2 - 4 = 0",
"x^3 - 1 = 0",
"5 = 5",
"3 = 7",
"x^4 + 1 = 0",
];

for equation_str in equations {
println!("\nSolving Equation: {}", equation_str);
match solve_equation(equation_str) {
Ok(solution) => println!("Solution: {}", solution),
Err(e) => println!("Error: {}", e),
}
}
}
39 changes: 37 additions & 2 deletions src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
// src/ast.rs

#[derive(Debug, Clone)]
use std::fmt;
use std::ops::Div;
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Number(f64),
Variable(String),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Mul(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
Pow(Box<Expr>, Box<Expr>),
Undefined,
}

impl Div for Expr {
type Output = Self;

fn div(self, rhs: Self) -> Self::Output {
match (self, rhs) {
(Expr::Mul(ll, lr), Expr::Mul(rl, rr)) if *ll == *rl => Expr::Div(lr, rr),

(l, r) => Expr::Div(Box::new(l), Box::new(r)),
}
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expr::Number(n) => {
if n.fract() == 0.0 {
write!(f, "{}", n.round())
} else {
write!(f, "{}", n)
}
}
Expr::Variable(var) => write!(f, "{}", var),
Expr::Add(lhs, rhs) => write!(f, "({} + {})", lhs, rhs),
Expr::Sub(lhs, rhs) => write!(f, "({} - {})", lhs, rhs),
Expr::Mul(lhs, rhs) => write!(f, "({} * {})", lhs, rhs),
Expr::Div(lhs, rhs) => write!(f, "({} / {})", lhs, rhs),
Expr::Undefined => write!(f, "undefined"),
Expr::Pow(_, _) => todo!(),
}
}
}
28 changes: 24 additions & 4 deletions src/format.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// src/format.rs

use crate::ast::Expr;

pub fn format_expr(expr: &Expr) -> String {
Expand All @@ -26,14 +24,36 @@ pub fn format_expr(expr: &Expr) -> String {
Expr::Div(lhs, rhs) => {
format!("({})/({})", format_expr(lhs), format_expr(rhs))
}
Expr::Pow(lhs, rhs) => {
format!("{}^{}", format_factor(lhs), format_factor(rhs))
}
Expr::Undefined => "undefined".to_string(),
}
}

fn format_factor(expr: &Expr) -> String {
match expr {
Expr::Add(_, _) | Expr::Sub(_, _) => {
Expr::Number(n) => {
if n.fract() == 0.0 {
format!("{}", n.round())
} else {
format!("{}", n)
}
}
Expr::Variable(var) => var.clone(),
Expr::Mul(lhs, rhs) => {
let left = format_factor(lhs);
let right = format_factor(rhs);
format!("{}{}", left, right)
}
Expr::Div(lhs, rhs) => {
format!("({})/({})", format_expr(lhs), format_expr(rhs))
}
Expr::Pow(lhs, rhs) => {
format!("({})^({})", format_expr(lhs), format_expr(rhs))
}
Expr::Add(_, _) | Expr::Sub(_, _) | Expr::Undefined => {
format!("({})", format_expr(expr))
}
_ => format_expr(expr),
}
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@ pub mod parser;

pub mod format;
pub mod simplify;

pub mod token;
pub mod tokenizer;

pub mod solver;
mod tests;
27 changes: 20 additions & 7 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// src/parser.rs

use crate::ast::Expr;
use crate::token::Token;

Expand Down Expand Up @@ -43,24 +41,24 @@ impl Parser {
}

fn parse_multiplication(&mut self) -> Result<Expr, String> {
let mut expr = self.parse_factor()?;
let mut expr = self.parse_exponentiation()?;

loop {
if let Some(token) = self.current_token() {
match token {
Token::Star => {
self.advance();
let rhs = self.parse_factor()?;
let rhs = self.parse_exponentiation()?;
expr = Expr::Mul(Box::new(expr), Box::new(rhs));
}
Token::Slash => {
self.advance();
let rhs = self.parse_factor()?;
let rhs = self.parse_exponentiation()?;
expr = Expr::Div(Box::new(expr), Box::new(rhs));
}
// Handle implicit multiplication
// Handle implicit multiplication (e.g., 2x, (a)(b))
Token::Number(_) | Token::Variable(_) | Token::LParen => {
let rhs = self.parse_factor()?;
let rhs = self.parse_exponentiation()?;
expr = Expr::Mul(Box::new(expr), Box::new(rhs));
}
_ => break,
Expand All @@ -73,6 +71,21 @@ impl Parser {
Ok(expr)
}

fn parse_exponentiation(&mut self) -> Result<Expr, String> {
let expr = self.parse_factor()?;
self.parse_exponentiation_rhs(expr)
}

fn parse_exponentiation_rhs(&mut self, left: Expr) -> Result<Expr, String> {
if let Some(Token::Pow) = self.current_token() {
self.advance();
let right = self.parse_exponentiation()?;
Ok(Expr::Pow(Box::new(left), Box::new(right)))
} else {
Ok(left)
}
}

fn parse_factor(&mut self) -> Result<Expr, String> {
if let Some(token) = self.current_token() {
match token {
Expand Down
Loading

0 comments on commit f66132a

Please sign in to comment.