Added tests for calculus.rs

This commit is contained in:
bakk 2021-05-23 15:58:23 +02:00
parent 33de7f034c
commit eaf712e01f
3 changed files with 175 additions and 35 deletions

View File

@ -49,6 +49,22 @@ impl Identifier {
}
}
pub fn build_literal_ast(kalk_num: &crate::kalk_num::KalkNum) -> Expr {
if kalk_num.has_imaginary() {
Expr::Binary(
Box::new(Expr::Literal(kalk_num.to_f64())),
TokenKind::Plus,
Box::new(Expr::Binary(
Box::new(Expr::Literal(kalk_num.imaginary_to_f64())),
TokenKind::Star,
Box::new(Expr::Var(Identifier::from_full_name("i"))),
)),
)
} else {
Expr::Literal(kalk_num.to_f64())
}
}
fn separate_identifier_and_prime(identifier: &str) -> (String, u32) {
let mut prim_count = 0;
let mut pure_identifier = identifier.to_string();

View File

@ -1,3 +1,4 @@
use crate::ast;
use crate::ast::Expr;
use crate::ast::Identifier;
use crate::ast::Stmt;
@ -14,8 +15,8 @@ pub fn derive_func(
const H: f64 = 0.000001;
let unit = &argument.unit.to_string();
let argument_with_h = Expr::Literal(argument.clone().add(context, H.into()).to_f64());
let argument_without_h = Expr::Literal(argument.sub(context, H.into()).to_f64());
let argument_with_h = ast::build_literal_ast(&argument.clone().add_without_unit(H.into()));
let argument_without_h = ast::build_literal_ast(&argument.sub_without_unit(H.into()));
let new_identifier = Identifier::from_name_and_primes(&name.pure_name, name.prime_count - 1);
let f_x_h = interpreter::eval_fn_call_expr(context, &new_identifier, &[argument_with_h], unit)?;
@ -23,8 +24,8 @@ pub fn derive_func(
interpreter::eval_fn_call_expr(context, &new_identifier, &[argument_without_h], unit)?;
Ok(f_x_h
.sub(context, f_x)
.div(context, (2f64 * H).into())
.sub_without_unit(f_x)
.div_without_unit((2f64 * H).into())
.round_if_needed())
}
@ -89,19 +90,7 @@ fn simpsons_rule(
.add_without_unit(KalkNum::from(i).mul_without_unit(h.clone()));
context.symbol_table.set(Stmt::VarDecl(
Identifier::from_full_name(integration_variable),
if variable_value.has_imaginary() {
Box::new(Expr::Binary(
Box::new(Expr::Literal(variable_value.to_f64())),
TokenKind::Plus,
Box::new(Expr::Binary(
Box::new(Expr::Literal(variable_value.imaginary_to_f64())),
TokenKind::Star,
Box::new(Expr::Var(Identifier::from_full_name("i"))),
)),
))
} else {
Box::new(Expr::Literal(variable_value.to_f64()))
},
Box::new(crate::ast::build_literal_ast(&variable_value)),
));
let factor = KalkNum::from(match i {
@ -122,3 +111,154 @@ fn simpsons_rule(
3f64 / 8f64 * h.imaginary_value,
)))
}
#[cfg(test)]
mod tests {
use crate::ast;
use crate::calculus::Identifier;
use crate::calculus::Stmt;
use crate::interpreter;
use crate::kalk_num::KalkNum;
use crate::lexer::TokenKind::*;
use crate::symbol_table::SymbolTable;
use crate::test_helpers::*;
fn get_context<'a>(symbol_table: &'a mut SymbolTable) -> interpreter::Context<'a> {
interpreter::Context::new(
symbol_table,
"",
#[cfg(feature = "rug")]
63u32,
None,
)
}
fn cmp(x: f64, y: f64) -> bool {
(x - y).abs() < 0.0001
}
#[test]
fn test_derive_func() {
let mut symbol_table = SymbolTable::new();
let mut context = get_context(&mut symbol_table);
context.symbol_table.insert(Stmt::FnDecl(
Identifier::from_full_name("f"),
vec![String::from("x")],
binary(
literal(2.5f64),
Star,
binary(var("x"), Power, literal(3f64)),
),
));
let call = Stmt::Expr(fn_call("f'", vec![*literal(12.3456f64)]));
assert!(cmp(
context.interpret(vec![call]).unwrap().unwrap().to_f64(),
1143.10379f64
));
}
#[test]
fn test_derive_complex_func() {
let mut symbol_table = SymbolTable::new();
let mut context = get_context(&mut symbol_table);
context.symbol_table.insert(Stmt::FnDecl(
Identifier::from_full_name("f"),
vec![String::from("x")],
binary(
binary(
literal(1.5f64),
Star,
binary(var("x"), Power, literal(2f64)),
),
Plus,
binary(binary(var("x"), Power, literal(2f64)), Star, var("i")),
),
));
let call = Stmt::Expr(fn_call("f'", vec![*var("e")]));
let result = context.interpret(vec![call]).unwrap().unwrap();
assert!(cmp(result.to_f64(), 8.15484f64));
assert!(cmp(result.imaginary_to_f64(), 5.43656));
}
#[test]
fn test_derive_func_with_complex_argument() {
let mut symbol_table = SymbolTable::new();
let mut context = get_context(&mut symbol_table);
context.symbol_table.insert(Stmt::FnDecl(
Identifier::from_full_name("f"),
vec![String::from("x")],
binary(
binary(literal(3f64), Star, var("x")),
Plus,
binary(
literal(0.5f64),
Star,
binary(var("x"), Power, literal(3f64)),
),
),
));
let result = super::derive_func(
&mut context,
&Identifier::from_full_name("f'"),
KalkNum::new_with_imaginary(KalkNum::from(2f64).value, "", KalkNum::from(3f64).value),
)
.unwrap();
assert!(cmp(result.to_f64(), -4.5f64) || cmp(result.to_f64(), -4.499999f64));
assert!(cmp(result.imaginary_to_f64(), 18f64));
}
#[test]
fn test_integrate_with_unknown_variable() {
let mut symbol_table = SymbolTable::new();
let mut context = get_context(&mut symbol_table);
let result = super::integrate_with_unknown_variable(
&mut context,
&*literal(2f64),
&*literal(4f64),
&*binary(var("x"), Star, var("dx")),
)
.unwrap();
assert!(cmp(result.to_f64(), 6f64));
}
#[test]
fn test_integrate() {
let mut symbol_table = SymbolTable::new();
let mut context = get_context(&mut symbol_table);
let result = super::integrate(
&mut context,
&*literal(2f64),
&*literal(4f64),
&*var("x"),
"x",
)
.unwrap();
assert!(cmp(result.to_f64(), 6f64));
}
#[test]
fn test_integrate_complex() {
let mut symbol_table = SymbolTable::new();
let mut context = get_context(&mut symbol_table);
let result = super::integrate(
&mut context,
&*literal(2f64),
&ast::build_literal_ast(&KalkNum::new_with_imaginary(
KalkNum::from(3f64).value,
"",
KalkNum::from(4f64).value,
)),
&*binary(var("x"), Star, var("i")),
"x",
)
.unwrap();
assert!(cmp(result.to_f64(), -12f64));
assert!(cmp(result.imaginary_to_f64(), -5.5f64));
}
}

View File

@ -50,29 +50,13 @@ impl<'a> Context<'a> {
Identifier::from_full_name("ans"),
Box::new(Expr::Unit(
num.unit.clone(),
Box::new(Expr::Binary(
Box::new(Expr::Literal(num.to_f64())),
TokenKind::Plus,
Box::new(Expr::Binary(
Box::new(Expr::Literal(num.imaginary_to_f64())),
TokenKind::Star,
Box::new(Expr::Var(Identifier::from_full_name("i"))),
)),
)),
Box::new(crate::ast::build_literal_ast(&num)),
)),
)
} else {
Stmt::VarDecl(
Identifier::from_full_name("ans"),
Box::new(Expr::Binary(
Box::new(Expr::Literal(num.to_f64())),
TokenKind::Plus,
Box::new(Expr::Binary(
Box::new(Expr::Literal(num.imaginary_to_f64())),
TokenKind::Star,
Box::new(Expr::Var(Identifier::from_full_name("i"))),
)),
)),
Box::new(crate::ast::build_literal_ast(&num)),
)
});