use super::ODEResult;
use crate::calculus::integrals::Integration;
use crate::core::{Expression, Symbol};
use crate::simplify::Simplify;
use crate::symbol;
pub struct HomogeneousODESolver;
impl HomogeneousODESolver {
pub fn solve(&self, f: &Expression, _dependent: &Symbol, independent: &Symbol) -> ODEResult {
let v = symbol!(v);
let f_minus_v = Expression::add(vec![
f.clone(),
Expression::mul(vec![Expression::integer(-1), Expression::symbol(v.clone())]),
])
.simplify();
let lhs_integrand = Expression::pow(f_minus_v, Expression::integer(-1)).simplify();
let lhs_integral = lhs_integrand.integrate(v, 0);
let rhs_integral =
Expression::function("log", vec![Expression::symbol(independent.clone())]);
let c = Expression::symbol(symbol!(C));
let solution = Expression::add(vec![
lhs_integral,
Expression::mul(vec![Expression::integer(-1), rhs_integral]),
c,
])
.simplify();
Ok(solution)
}
pub fn is_homogeneous(
&self,
_equation: &Expression,
_dependent: &Symbol,
_independent: &Symbol,
) -> bool {
false
}
pub fn extract_homogeneous_function(
&self,
rhs: &Expression,
dependent: &Symbol,
independent: &Symbol,
) -> Option<Expression> {
let _ = (rhs, dependent, independent);
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{expr, symbol};
#[test]
fn test_homogeneous_simple() {
let x = symbol!(x);
let y = symbol!(y);
let f = expr!(v);
let solver = HomogeneousODESolver;
let solution = solver.solve(&f, &y, &x);
assert!(solution.is_ok());
let sol = solution.unwrap();
let sol_str = sol.to_string();
assert!(sol_str.contains("log") || sol_str.contains("ln"));
}
#[test]
fn test_homogeneous_quadratic() {
let x = symbol!(x);
let y = symbol!(y);
let f = expr!(v ^ 2);
let solver = HomogeneousODESolver;
let solution = solver.solve(&f, &y, &x);
assert!(solution.is_ok());
}
#[test]
fn test_homogeneous_linear_in_v() {
let x = symbol!(x);
let y = symbol!(y);
let f = expr!(2 * v);
let solver = HomogeneousODESolver;
let solution = solver.solve(&f, &y, &x);
assert!(solution.is_ok());
}
#[test]
fn test_homogeneous_rational() {
let x = symbol!(x);
let y = symbol!(y);
let f = Expression::mul(vec![
Expression::add(vec![expr!(v), Expression::integer(1)]),
Expression::pow(
Expression::add(vec![
expr!(v),
Expression::mul(vec![Expression::integer(-1), Expression::integer(1)]),
]),
Expression::integer(-1),
),
]);
let solver = HomogeneousODESolver;
let solution = solver.solve(&f, &y, &x);
assert!(solution.is_ok());
}
#[test]
fn test_homogeneous_with_trig() {
let x = symbol!(x);
let y = symbol!(y);
let f = expr!(sin(v));
let solver = HomogeneousODESolver;
let solution = solver.solve(&f, &y, &x);
assert!(solution.is_ok());
}
#[test]
fn test_homogeneous_solution_structure() {
let x = symbol!(x);
let y = symbol!(y);
let f = expr!(v ^ 2);
let solver = HomogeneousODESolver;
let solution = solver.solve(&f, &y, &x).unwrap();
let sol_str = solution.to_string();
assert!(sol_str.contains("C"));
}
#[test]
fn test_homogeneous_implicit_solution() {
let x = symbol!(x);
let y = symbol!(y);
let f = expr!((v ^ 2) + 1);
let solver = HomogeneousODESolver;
let solution = solver.solve(&f, &y, &x);
assert!(solution.is_ok());
let sol = solution.unwrap();
let sol_str = sol.to_string();
assert!(sol_str.contains("v") || sol_str.contains("x"));
}
}