Reverse lookup

solar_dates_by_bazi and reverse_chart - the functions and types for recovering candidate birth dates from BaZi pillars or chart features.

Recover candidate birth dates from four BaZi pillars or from chart features. Both entry points are "pruned enumeration + full re-charting", so results have zero divergence from forward charting. Concepts, how pillars follow the Config boundaries, and the multi-solution / truncation semantics are on the reverse lookup guide.

use x_iztro::*;

let cands = solar_dates_by_bazi(
    (HeavenlyStem::Geng, EarthlyBranch::Chen),
    (HeavenlyStem::Jia, EarthlyBranch::Shen),
    (HeavenlyStem::Bing, EarthlyBranch::Wu),
    (HeavenlyStem::Geng, EarthlyBranch::Yin),
    (1900, 2100),
    &Config::default(),
)?;

Everything is defined in x_iztro::astro::reverse and re-exported at the crate root.

Types

BirthCandidate

One candidate birth moment, ready to hand to by_solar.

FieldTypeMeaning
solar_dateStringsolar date, YYYY-M-D
time_indexu8hour index 0–12 (0 = early Zi hour, 12 = late Zi hour)

StarPosition

A star and the branch of the palace it sits in: the atomic condition of a feature lookup.

FieldTypeMeaning
starStarKeythe star (natal chart stars only; horoscope-scope flow stars are rejected)
branchEarthlyBranchthe branch of its palace

ReverseCriteria

The condition set of a feature lookup. Implements Default; the idiomatic construction gives the conditions and closes with ..Default::default(). Every condition is optional, but at least one must be given.

FieldTypeDefaultMeaning
soul_branchOption<EarthlyBranch>Nonesoul palace branch
body_branchOption<EarthlyBranch>Nonebody palace branch
five_elements_classOption<FiveElementsClass>Nonefive elements class
starsVec<StarPosition>emptystar placements, all of which must hold
mutagens[Option<StarKey>; 4]all Nonewhich star carries each birth-year mutagen [Lu, Quan, Ke, Ji]
year_range(i64, i64)(1900, 2100)inclusive solar year range, within 1583–9999
fix_leapbooltrueleap month correction, same meaning as the charting parameter
limitusize0candidate cap; 0 takes DEFAULT_REVERSE_LIMIT

ReverseResult

FieldTypeMeaning
candidatesVec<BirthCandidate>the birth candidates satisfying every condition
truncatedboolwhether the search stopped early at the candidate cap; later solutions were never searched

DEFAULT_REVERSE_LIMIT

pub const DEFAULT_REVERSE_LIMIT: usize = 512;

The candidate cap used when ReverseCriteria::limit is 0.


solar_dates_by_bazi

Recover solar birth dates from four BaZi pillars.

pub fn solar_dates_by_bazi(
    yearly: (HeavenlyStem, EarthlyBranch),
    monthly: (HeavenlyStem, EarthlyBranch),
    daily: (HeavenlyStem, EarthlyBranch),
    hourly: (HeavenlyStem, EarthlyBranch),
    year_range: (i64, i64),
    config: &Config,
) -> Result<Vec<BirthCandidate>, IztroError>

The pillars are interpreted under the boundary readings of config (year_divide for the year pillar, horoscope_divide for the month pillar, day_divide for the late Zi hour) — the same semantics as the raw_dates.chinese_date a charted astrolabe reports, so reversing any chart's pillars always includes that chart's birth moment. A set of pillars recurs roughly every 60 years within the range; an hour branch of Zi may yield two candidates on adjacent days because of the early/late Zi hour split.

Example

let a = by_solar("2000-8-16", 2, Gender::Female, true, Language::EnUS, Config::default())?;
let p = a.raw_dates.chinese_date;

let cands = solar_dates_by_bazi(p.yearly, p.monthly, p.daily, p.hourly, (1900, 2100), &Config::default())?;
for c in &cands {
    println!("{} {}", c.solar_date, c.time_index);
}

Output

1940-8-31 2
2000-8-16 2
2060-8-1 2

Errors A pillar with mismatched stem/branch polarity (such as 甲丑 Jia-Chou — a yang stem on a yin branch), or a year range that is reversed or outside 1583–9999, returns IztroError::InvalidArgument.


reverse_chart

Recover candidate birth dates from chart features.

pub fn reverse_chart(
    criteria: &ReverseCriteria,
    config: &Config,
) -> Result<ReverseResult, IztroError>

Judgement runs entirely under config: the mutagen table, the school and every boundary follow it, so charting a candidate with the same config is guaranteed to satisfy every condition. Chart layout does not depend on gender (gender only affects the direction the decadal horoscope advances), so the criteria carry no gender.

Example

let r = reverse_chart(
    &ReverseCriteria {
        soul_branch: Some(EarthlyBranch::Wu),
        five_elements_class: Some(FiveElementsClass::Wood3rd),
        stars: vec![StarPosition { star: StarKey::ZiweiMaj, branch: EarthlyBranch::Wu }],
        mutagens: [Some(StarKey::TaiyangMaj), None, None, None],
        year_range: (1998, 2002),
        ..Default::default()
    },
    &Config::default(),
)?;
println!("{} {}", r.candidates.len(), r.truncated);

Output

39 false

Errors Empty criteria, a horoscope-scope flow star in stars, or an invalid year range returns IztroError::InvalidArgument.

truncated means truncation, not sampling

Reaching limit stops the search; later solutions never appear in the result. On truncated = true, narrow year_range or add conditions and query again.

On this page