use crate::base::arena::Arena;
use crate::base::assumptions::{AssumptionCache, Props};
use crate::base::node::{ExprId, ExprNode};
use crate::base::walk;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Unassumed {
Real,
Complex,
}
pub(crate) fn constant_realness(
arena: &mut Arena,
c: ExprId,
digits: u32,
reals: &mut AssumptionCache,
) -> Option<bool> {
constant_realness_with(arena, c, digits, reals, Unassumed::Real)
}
pub(crate) fn constant_realness_as_declared(
arena: &mut Arena,
c: ExprId,
digits: u32,
reals: &mut AssumptionCache,
) -> Option<bool> {
constant_realness_with(arena, c, digits, reals, Unassumed::Complex)
}
fn constant_realness_with(
arena: &mut Arena,
c: ExprId,
digits: u32,
reals: &mut AssumptionCache,
unassumed: Unassumed,
) -> Option<bool> {
use crate::base::assumptions::Assumptions;
match arena.node(c) {
ExprNode::Num(_)
| ExprNode::Pi
| ExprNode::E
| ExprNode::EulerGamma
| ExprNode::Catalan
| ExprNode::GoldenRatio => return Some(true),
ExprNode::ImaginaryUnit => return Some(false),
_ => {}
}
let params = walk::free_symbols(arena, c);
if unassumed == Unassumed::Real {
for &s in ¶ms {
if let ExprNode::Symbol(sid) = *arena.node(s)
&& arena.symbol_assumptions(sid) == Assumptions::default()
{
let mut real = Assumptions::default();
real.known_true |= Props::REAL;
reals.set_symbol_assumptions(s, real);
}
}
}
if let Some(known) = reals.query(arena, c, Props::REAL) {
return Some(known);
}
if !params.is_empty() {
return None;
}
let z = crate::transforms::evalf::evalf_complex(arena, c, digits).ok()?;
if !crate::transforms::evalf::is_real_to_digits(&z, digits.saturating_sub(2)) {
return Some(false);
}
let im = arena.im(c);
let im = crate::transforms::eval::eval(arena, im);
if walk::has_unevaluated(arena, im) {
return None;
}
let w = crate::transforms::evalf::evalf_complex(arena, im, digits).ok()?;
(w.0.is_zero() && w.1.is_zero()).then_some(true)
}
pub(crate) fn symbol_declared_real(arena: &Arena, s: crate::base::node::SymbolId) -> bool {
let mut declared = arena.symbol_assumptions(s);
declared.normalize_declared();
declared.query(Props::REAL) == Some(true)
}