use crate::base::arena::Arena;
use crate::base::assumptions::{AssumptionCache, Props};
use crate::base::node::{ExprId, ExprNode};
use crate::base::truth::Truth;
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 !z.1.is_zero() {
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 search = crate::transforms::evalf::ZeroSearch::Cap;
let w = crate::transforms::evalf::evalf_verdict(arena, im, digits, search).ok()?;
match w.proven() {
Some(w) if w.0.is_zero() && w.1.is_zero() => Some(true),
Some(w) if w.1.is_zero() => Some(false),
Some(_) => None,
None => {
let facts = crate::transforms::eval::constant_facts(arena, c);
(Truth::from(facts.query(Props::REAL)).is_true()).then_some(true)
}
}
}
pub(crate) fn imaginary_part_sign(arena: &mut Arena, c: ExprId) -> crate::base::truth::SignSet {
use crate::base::truth::SignSet;
if !walk::free_symbols(arena, c).is_empty() || walk::has_unevaluated(arena, c) {
return SignSet::REAL;
}
let mut cache = AssumptionCache::new();
if Truth::from(cache.query(arena, c, Props::REAL)).is_true() {
return SignSet::ZERO;
}
let sign = |p: &astro_float::BigFloat| {
if crate::base::bigfloat::is_strictly_positive(p) {
SignSet::POSITIVE
} else {
SignSet::NEGATIVE
}
};
use crate::transforms::evalf::{self, Settled, ZeroSearch};
if let Ok((z, Settled::Certified)) = evalf::evalf_settled(arena, c, 16, ZeroSearch::Cap)
&& !z.1.is_zero()
{
return sign(&z.1);
}
let im = arena.im(c);
let im = crate::transforms::eval::eval(arena, im);
if arena.is_zero_structural(im) {
return SignSet::ZERO;
}
if walk::has_unevaluated(arena, im) {
return SignSet::REAL;
}
match evalf::evalf_verdict(arena, im, 16, ZeroSearch::Cap)
.ok()
.and_then(crate::base::truth::Verdict::proven)
{
Some(w) if w.0.is_zero() && w.1.is_zero() => SignSet::ZERO,
Some(w) if w.1.is_zero() => sign(&w.0),
_ => SignSet::REAL,
}
}
pub(crate) fn symbol_declared_real(arena: &Arena, s: crate::base::node::SymbolId) -> bool {
let mut declared = arena.symbol_assumptions(s);
declared.normalize_declared();
Truth::from(declared.query(Props::REAL)).is_true()
}