665 static relg inst{auto_probe_tag{}};
699 if (request.
up < 0 || request.
up > 2)
701 throw std::invalid_argument(
"family_request.up must be 0, 1 or 2");
703 if (request.
down < 0 || request.
down > 2)
705 throw std::invalid_argument(
"family_request.down must be 0, 1 or 2");
707 if (request.
names && !_from.
name->has_resources())
709 throw std::runtime_error(
"relationship-generator: names were requested and name-generator has no data loaded");
711 const core::rng call{call_seed};
712 const double ref_day =
static_cast<double>(days_(request.
reference_date));
713 check_known_(request.
anchor);
715 const anchor_info
anchor = draw_anchor_(request, call.split(
"anchor").seed(), ref_day);
716 const country_model& cm = lookup_(
anchor.country);
719 f._signature = {.seed = call_seed, .data =
data_hash()};
726 const auto& spec = request.
anchor;
727 const life anchor_life{.
birth =
anchor.birth_day, .lifespan = never_dies_, .s =
anchor.s};
728 std::vector<raw_member> raw;
729 push_(raw, relation::anchor, anchor_life,
"anchor");
730 raw[0].fixed = spec.name;
734 double together_until =
anchor.birth_day;
737 const known_parents known{spec.father ? &*spec.father :
nullptr, spec.mother ? &*spec.mother :
nullptr};
738 const bool known_siblings = spec.siblings.has_value();
740 auto lin = draw_lineage_(cm,
anchor.country, call.split(
"parents"),
anchor.birth_day, ref_day,
744 for (
const auto& s : lin.siblings) together_until = std::max(together_until, s.birth);
745 lin.siblings.clear();
751 std::string_view label;
755 std::vector<half_rec> halves;
756 const auto father_slot = raw.size();
757 const auto mother_slot = raw.size() + 1;
758 if (request.
siblings && known_siblings)
760 for (std::size_t i = 0; i < spec.siblings->size(); ++i)
762 const auto& ks = spec.siblings->at(i);
763 const auto l = life_of_(ks.person, ref_day,
static_cast<int>(i));
766 lin.siblings.push_back(l);
770 const bool via_father = ks.through == sex::male;
771 halves.push_back({l, via_father ? father_slot : mother_slot, via_father ?
"father" :
"mother",
778 std::ranges::stable_sort(lin.siblings, [](
const life& x,
const life& y) { return x.birth < y.birth; });
779 for (
const auto& s : lin.siblings) together_until = std::max(together_until, s.birth);
780 const auto father = push_(raw, relation::father, lin.father,
"father");
781 const auto mother = push_(raw, relation::mother, lin.mother,
"mother");
782 if (spec.father) raw[
father].fixed = spec.father->name;
783 if (spec.mother) raw[
mother].fixed = spec.mother->name;
784 raw[
father].name_child = 0;
785 raw[
mother].name_child = 0;
786 raw[0].parents = {
static_cast<std::int64_t
>(
father),
static_cast<std::int64_t
>(
mother)};
787 for (
const auto& s : lin.siblings)
789 const auto id = push_(raw, relation::sibling, s,
"sibling." + std::to_string(s.index));
790 raw[id].parents = raw[0].parents;
791 if (known_siblings) raw[id].fixed = spec.siblings->at(
static_cast<std::size_t
>(s.index)).person.name;
797 const auto half = call.split(
"half-siblings");
802 std::string_view label;
804 } sides[] = {{
father,
"father",
true}, {
mother,
"mother",
false}};
805 for (
const auto& side : sides)
807 for (
const auto& k : draw_half_siblings_(cm,
anchor.country, raw.at(side.parent).life, side.father,
808 side.father ? std::vector<double>{} : lin.mother_births,
809 ref_day, half.split(side.label)))
811 halves.push_back({k, side.parent, side.label, none_, side.father});
817 std::ranges::stable_sort(halves, [](
const half_rec& x,
const half_rec& y) {
return x.l.birth < y.l.birth; });
818 std::int64_t next_other = unlisted_ + 1000;
819 std::array<std::int64_t, 2> current{none_, none_};
820 std::array<double, 2> last{0.0, 0.0};
821 for (
auto& h : halves)
823 const std::size_t side = h.father ? 0 : 1;
824 if (current[side] == none_ || h.l.birth - last[side] > half_cluster_years_ * year_days_)
826 current[side] = next_other++;
828 last[side] = h.l.birth;
829 h.other = current[side];
830 const auto id = push_(raw, relation::half_sibling, h.l,
831 "half." + std::string{h.label} +
"." + std::to_string(h.l.index));
832 raw[id].parents = h.father
833 ? std::array<std::int64_t, 2>{
static_cast<std::int64_t
>(h.parent), h.other}
834 : std::array<std::int64_t, 2>{h.other,
static_cast<std::int64_t
>(h.parent)};
835 if (known_siblings) raw[id].fixed = spec.siblings->at(
static_cast<std::size_t
>(h.l.index)).
person.
name;
840 const auto grand = call.split(
"grandparents");
844 std::string_view label;
847 const std::optional<known_person>* given;
848 } sides[] = {{
father,
"father", relation::paternal_grandfather, relation::paternal_grandmother, &spec.father},
849 {
mother,
"mother", relation::maternal_grandfather, relation::maternal_grandmother, &spec.mother}};
850 for (
const auto& side : sides)
852 known_parents above{
nullptr,
nullptr};
853 if (side.given->has_value())
855 for (
const auto& gp : (*side.given)->parents)
857 (gp.bio_sex == sex::male ? above.father : above.mother) = &gp;
860 const auto g = draw_lineage_(cm,
anchor.country, grand.split(side.label),
861 raw.at(side.parent).life.birth, ref_day,
false, above);
862 const auto gf = push_(raw, side.grandfather, g.father,
"gp." + std::string{side.label} +
".m");
863 const auto gm = push_(raw, side.grandmother, g.mother,
"gp." + std::string{side.label} +
".f");
864 if (above.father !=
nullptr) raw[gf].fixed = above.father->name;
865 if (above.mother !=
nullptr) raw[gm].fixed = above.mother->name;
866 raw[gf].name_child =
static_cast<std::int64_t
>(side.parent);
867 raw[gm].name_child =
static_cast<std::int64_t
>(side.parent);
868 raw[side.parent].parents = {
static_cast<std::int64_t
>(gf),
static_cast<std::int64_t
>(gm)};
873 std::vector<union_rec>
unions;
876 for (std::size_t j = 0; j < spec.unions->size(); ++j)
878 unions.push_back(union_of_(spec.unions->at(j), j,
anchor.s, ref_day));
883 unions = draw_unions_(cm,
anchor.country, anchor_life, ref_day, call.split(
"unions"));
886 std::vector<std::int64_t> partner_slot;
887 std::vector<std::size_t> partner_ids;
888 for (std::size_t j = 0; j <
unions.size(); ++j)
892 const auto id = push_(raw, relation::partner,
unions[j].
partner,
"partner." + std::to_string(j));
893 raw[id].fixed =
unions[j].partner_name;
894 partner_ids.push_back(
id);
895 partner_slot.push_back(
static_cast<std::int64_t
>(
id));
899 partner_ids.push_back(no_member_);
900 partner_slot.push_back(unlisted_ + 10 +
static_cast<std::int64_t
>(j));
907 const auto step = call.split(
"stepchildren");
908 std::vector<std::pair<std::size_t, life>> stepkids;
909 for (std::size_t j = 0; j <
unions.size(); ++j)
911 if (!
unions[j].has_partner)
continue;
914 for (std::size_t i = 0; i < spec.unions->at(j).stepchildren.size(); ++i)
916 stepkids.emplace_back(j, life_of_(spec.unions->at(j).stepchildren[i], ref_day,
static_cast<int>(i)));
920 for (
const auto& k : draw_stepchildren_(cm,
anchor.country,
unions[j], ref_day, step.split(
static_cast<std::uint64_t
>(j))))
922 stepkids.emplace_back(j, k);
925 std::ranges::stable_sort(stepkids, [](
const auto& x,
const auto& y) {
return x.second.birth < y.second.birth; });
926 for (
const auto& [j, k] : stepkids)
928 const auto partner = partner_ids.at(j);
929 const auto token = unlisted_ + 500 +
static_cast<std::int64_t
>(j);
930 const auto id = push_(raw, relation::stepchild, k,
"step." + std::to_string(j) +
"." + std::to_string(k.index));
931 raw[id].parents = raw.at(
partner).life.s == sex::male
932 ? std::array<std::int64_t, 2>{
static_cast<std::int64_t
>(
partner), token}
933 : std::array<std::int64_t, 2>{token,
static_cast<std::int64_t
>(
partner)};
934 if (spec.unions) raw[id].fixed = spec.unions->at(j).stepchildren.at(
static_cast<std::size_t
>(k.index)).name;
938 if (request.
down >= 1)
940 auto kids = spec.unions ? known_children_(*spec.unions, ref_day)
941 : draw_union_children_(cm,
anchor.country, anchor_life,
unions, ref_day,
942 call.split(
"children"));
943 std::ranges::stable_sort(kids, [](
const child_rec& x,
const child_rec& y) {
return x.life.birth < y.life.birth; });
944 const std::size_t first_child = raw.size();
945 for (
const auto& k : kids)
947 const auto& u =
unions.at(
static_cast<std::size_t
>(k.union_index));
948 const std::int64_t
other = partner_slot.at(
static_cast<std::size_t
>(k.union_index));
950 const bool anchor_first = u.same_sex ||
anchor.s == sex::male;
951 const auto id = push_(raw, relation::child, k.life,
952 "child." + std::to_string(k.union_index) +
"." + std::to_string(k.life.index));
953 raw[id].parents = anchor_first ? std::array<std::int64_t, 2>{0,
other} : std::array<std::int64_t, 2>{
other, 0};
954 raw[id].genetic = k.genetic;
955 raw[id].fixed = k.fixed;
957 if (request.
down >= 2)
959 const auto grand = call.split(
"grandchildren");
960 std::vector<std::size_t> parents_of_grandchildren;
961 for (std::size_t c = first_child; c < raw.size(); ++c) parents_of_grandchildren.push_back(c);
962 std::vector<std::pair<std::size_t, life>> grandchildren;
963 for (
const auto c : parents_of_grandchildren)
965 const auto kids2 = draw_grandchildren_(cm,
anchor.country, raw.at(c).life, ref_day, grand.split(raw.at(c).key));
966 for (
const auto& k : kids2) grandchildren.emplace_back(c, k);
968 std::ranges::stable_sort(grandchildren, [](
const auto& x,
const auto& y) {
return x.second.birth < y.second.birth; });
969 for (
const auto& [c, k] : grandchildren)
971 const auto token = unlisted_ + 100 +
static_cast<std::int64_t
>(c);
972 const auto id = push_(raw, relation::grandchild, k,
"grand." + raw.at(c).key +
"." + std::to_string(k.index));
973 raw[id].parents = raw.at(c).life.s == sex::male
974 ? std::array<std::int64_t, 2>{
static_cast<std::int64_t
>(c), token}
975 : std::array<std::int64_t, 2>{token,
static_cast<std::int64_t
>(c)};
982 std::vector<step_rec> steps;
983 std::vector<std::size_t> step_ids;
984 std::vector<std::size_t> step_parents;
987 const auto sp = call.split(
"stepparents");
991 std::string_view label;
992 } sides[] = {{1,
"father"}, {2,
"mother"}};
993 for (
const auto& side : sides)
995 const auto rec = draw_stepparent_(cm,
anchor.country, raw.at(side.parent).life,
anchor.birth_day,
996 together_until, ref_day, sp.split(side.label));
998 const auto id = push_(raw, rec->partner.s == sex::male ? relation::stepfather : relation::stepmother,
999 rec->partner,
"stepparent." + std::string{side.label});
1000 raw[id].name_child =
static_cast<std::int64_t
>(side.parent);
1001 steps.push_back(*rec);
1002 step_ids.push_back(
id);
1003 step_parents.push_back(side.parent);
1012 if (request.
siblings && !steps.empty())
1014 const auto& p = _model.params;
1015 const auto sib = call.split(
"stepsiblings");
1016 std::vector<std::pair<std::size_t, life>> joint;
1017 std::vector<std::pair<std::size_t, life>> stepsibs;
1018 for (std::size_t k = 0; k < steps.size(); ++k)
1020 const auto parent = step_parents[k];
1021 const auto sp = step_ids[k];
1022 const auto rk = sib.split(raw.at(sp).key);
1023 const union_rec u{.partner = steps[k].partner, .start = steps[k].start};
1024 for (
const auto& c : draw_stepchildren_(cm,
anchor.country, u, ref_day, rk)) stepsibs.emplace_back(k, c);
1025 if (steps[k].
partner.s == raw.at(parent).life.s)
continue;
1027 const int tied = tie_half_siblings_(raw, parent, sp, steps[k], p);
1028 const double mean = (tfr_at_(cm.fertility, 1970.0 + (steps[k].start / year_days_)) + p.union_fertility_offset) *
1029 p.union_fertility * p.later_union_factor;
1030 auto count_rng = rk.split(
"count");
1031 const int n = std::min(family_size_(count_rng, mean),
static_cast<int>(p.max_children));
1032 const bool via_father = raw.at(parent).life.s == sex::male;
1033 const auto mother_id =
static_cast<std::int64_t
>(via_father ? sp : parent);
1034 std::vector<double> births;
1035 for (
const auto& m : raw)
1037 if (m.parents[1] == mother_id) births.push_back(m.life.birth);
1039 for (
const auto& [j, c] : stepsibs)
1041 if (j == k && via_father) births.push_back(c.birth);
1043 const life&
mother = via_father ? steps[k].partner : raw.at(parent).life;
1044 const life&
father = via_father ? raw.at(parent).life : steps[k].partner;
1045 for (
const auto& c : place_union_births_(cm,
anchor.country,
mother,
father, steps[k].start,
1046 steps[k].end, tied, n, births, rk.split(
"joint")))
1048 joint.emplace_back(k, c.life);
1051 std::ranges::stable_sort(joint, [](
const auto& x,
const auto& y) {
return x.second.birth < y.second.birth; });
1052 std::ranges::stable_sort(stepsibs, [](
const auto& x,
const auto& y) {
return x.second.birth < y.second.birth; });
1053 for (
const auto& [k, c] : joint)
1055 const auto parent =
static_cast<std::int64_t
>(step_parents[k]);
1056 const auto sp =
static_cast<std::int64_t
>(step_ids[k]);
1057 const auto id = push_(raw, relation::half_sibling, c,
1058 "joint." + raw.at(step_ids[k]).key +
"." + std::to_string(c.index));
1059 raw[id].parents = raw.at(step_parents[k]).life.s == sex::male ? std::array<std::int64_t, 2>{parent, sp}
1060 : std::array<std::int64_t, 2>{sp, parent};
1062 for (
const auto& [k, c] : stepsibs)
1064 const auto sp = step_ids[k];
1065 const auto token = unlisted_ + 600 +
static_cast<std::int64_t
>(k);
1066 const auto id = push_(raw, relation::stepsibling, c,
"stepsib." + raw.at(sp).key +
"." + std::to_string(c.index));
1067 raw[id].parents = raw.at(sp).life.s == sex::male
1068 ? std::array<std::int64_t, 2>{
static_cast<std::int64_t
>(sp), token}
1069 : std::array<std::int64_t, 2>{token,
static_cast<std::int64_t
>(sp)};
1075 for (std::size_t i = 0; i < raw.size(); ++i)
1077 for (
const auto p : raw[i].parents)
1079 if (p >= 0 && p < unlisted_)
1081 f.
edges.push_back({.kind = edge_kind::parent_of, .from =
static_cast<std::size_t
>(p), .to = i,
1082 .full =
true, .genetic = raw[i].genetic});
1086 std::vector<bool> twin(raw.size(),
false);
1087 for (std::size_t i = 0; i < raw.size(); ++i)
1089 for (std::size_t k = i + 1; k < raw.size(); ++k)
1091 const auto& a = raw[i].parents;
1092 const auto& b = raw[k].parents;
1093 const auto shares = [&](std::int64_t x) {
return x != none_ && (x == b[0] || x == b[1]); };
1094 if (!shares(a[0]) && !shares(a[1]))
continue;
1095 const bool full = (a[0] == b[0] && a[1] == b[1]) || (a[0] == b[1] && a[1] == b[0]);
1096 if (full && std::floor(raw[i].life.birth) == std::floor(raw[k].life.birth)) twin[i] = twin[k] =
true;
1097 const bool older = raw[i].life.birth <= raw[k].life.birth;
1098 f.
edges.push_back({.kind = edge_kind::sibling_of, .from = older ? i : k, .to = older ? k : i,
1102 for (std::size_t j = 0; j < partner_ids.size(); ++j)
1104 if (partner_ids[j] == no_member_)
continue;
1105 const auto& u =
unions[j];
1106 edge e{.
kind = edge_kind::partner_of, .from = 0, .to = partner_ids[j]};
1107 e.start =
static_cast<int>(from_days_(u.start).year());
1108 if (u.ended != union_end::ongoing) e.end =
static_cast<int>(from_days_(u.end).year());
1110 f.
edges.push_back(e);
1112 for (std::size_t k = 0; k < steps.size(); ++k)
1114 edge e{.
kind = edge_kind::partner_of, .from = step_parents[k], .to = step_ids[k]};
1115 e.start =
static_cast<int>(from_days_(steps[k].start).year());
1116 if (steps[k].ended != union_end::ongoing) e.end =
static_cast<int>(from_days_(steps[k].end).year());
1117 e.ended = steps[k].ended;
1118 f.
edges.push_back(e);
1119 f.
edges.push_back({.kind = edge_kind::step_parent_of, .from = step_ids[k], .to = 0});
1122 for (std::size_t i = 0; i < raw.size(); ++i)
1124 f.
members.push_back(to_person_(raw[i], i, ref_day));
1125 f.
members.back().twin = twin[i];
1128 if (request.
home) f.
home = draw_household_(cm, f, call.split(
"household"));
1156 std::uint64_t call_seed)
const
1158 if (member >= base.
members.size())
throw std::invalid_argument(
"expand: the member is not in the family");
1160 request.
anchor = anchor_of_(base, member);
1172 return expand(base, member, request, draw_seed_());
1187 const core::batch_options& options)
1208 const core::batch_options& options,
1209 std::uint64_t batch_seed)
const
1211 return core::run_batch(options, batch_seed, [&](std::uint64_t item_seed)
1228 template <
typename Sink>
1230 std::uint64_t batch_seed, Sink&& sink)
const
1232 core::for_each_batch(options, batch_seed,
1233 [&](std::uint64_t item_seed) {
return get_family(request, item_seed); },
1234 std::forward<Sink>(sink));
1243 template <
typename Sink>
1247 for_each_family(request, options, draw_seed_(), std::forward<Sink>(sink));
1254 [[nodiscard]]
bool has_data()
const {
return has_own_data_() && _from.
birth->has_data(); }
1265 std::vector<std::string> out;
1266 out.reserve(_model.countries.size());
1267 for (
const auto& [code, _] : _model.countries) out.push_back(code);
1268 std::ranges::sort(out);
1282 void load(
const std::filesystem::path& dir)
1285 if (!std::filesystem::is_directory(dir, ec))
return;
1286 for (
const auto t : required_tables_)
1288 if (!std::filesystem::is_regular_file(dir / file_name_(t), ec))
return;
1290 apply_(read_directory_(dir), core::layer_mode::replace,
true);
1303 [[nodiscard]]
bool load(dataset tier)
1305 const std::string tier_dir{core::tier_name(tier)};
1306 const auto marker = tier_dir +
"/" + std::string{file_name_(family_table::fertility)};
1307 const auto root = core::find_resources(library_name_, marker);
1309 for (
const auto t : all_tables_)
1311 docs.at(index_(t)) = core::load_resource(tier_dir +
"/" + std::string{file_name_(t)},
1312 embedded_files_(), root);
1314 for (
const auto t : required_tables_)
1316 if (!docs.at(index_(t)))
return false;
1318 apply_(std::move(docs), core::layer_mode::replace,
true);
1333 void extend(
const std::filesystem::path& path, core::layer_mode mode = core::layer_mode::override)
1336 if (std::filesystem::is_directory(path, ec))
1338 apply_(read_directory_(path), mode,
false);
1341 for (
const auto t : all_tables_)
1343 if (path.filename() == file_name_(t))
1345 (void)
extend(t, core::tsv_document::load(path), mode);
1349 throw std::invalid_argument(
"extend: expected one of the family tables (regions.tsv, fertility.tsv, "
1350 "unions.tsv, households.tsv, defaults.tsv, parameters.tsv), got " +
1351 path.filename().string());
1367 core::layer_mode mode = core::layer_mode::override)
1370 docs.at(index_(which)).emplace(std::move(doc));
1371 apply_(std::move(docs), mode,
false);
1372 return _tables.at(index_(which)).layers().back();
1384 core::layer_mode mode = core::layer_mode::override)
1386 return extend(which, core::tsv_document::parse(text, std::move(source)), mode);
1394 return _tables.at(index_(which)).layers();
1403 std::uint64_t own = 0;
1405 for (
const auto& t : _tables)
1407 any = any || !t.layers().empty();
1408 own = core::hash_combine(own, t.data_hash());
1411 return core::hash_combine(core::hash_combine(own, _from.
birth->data_hash()), _from.
name->data_hash());
1419 static constexpr std::string_view library_name_ =
"relationship-generator";
1420 static constexpr std::size_t table_count_ = 6;
1421 static constexpr std::array<table, table_count_> all_tables_{table::regions, table::fertility,
1422 table::unions, table::households,
1423 table::defaults, table::parameters};
1424 static constexpr std::array<table, 5> required_tables_{table::regions, table::fertility, table::unions,
1425 table::defaults, table::parameters};
1426 static constexpr std::array<std::string_view, 8> age_columns_{
1427 "pasfr_10_14",
"pasfr_15_19",
"pasfr_20_24",
"pasfr_25_29",
1428 "pasfr_30_34",
"pasfr_35_39",
"pasfr_40_44",
"pasfr_45_49"};
1429 static constexpr std::array<int, 15> tfr_years_{1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985,
1430 1990, 1995, 2000, 2005, 2010, 2015, 2020};
1431 static constexpr double year_days_ = 365.2425;
1432 static constexpr double euler_gamma_ = 0.57721566490153286;
1434 using documents = std::array<std::optional<core::tsv_document>, table_count_>;
1435 using tables = std::array<core::layered_table, table_count_>;
1436 using cells = std::unordered_map<std::string, double>;
1438 static constexpr std::size_t index_(table t) {
return static_cast<std::size_t
>(t); }
1440 static constexpr std::string_view file_name_(table t)
1444 case table::regions:
return "regions.tsv";
1445 case table::fertility:
return "fertility.tsv";
1446 case table::unions:
return "unions.tsv";
1447 case table::households:
return "households.tsv";
1448 case table::defaults:
return "defaults.tsv";
1449 case table::parameters:
return "parameters.tsv";
1455 static std::vector<std::string> numeric_columns_(table t)
1457 std::vector<std::string> cols;
1460 cols.emplace_back(
"tfr");
1461 cols.emplace_back(
"mac");
1462 for (
const auto c : age_columns_) cols.emplace_back(c);
1463 for (
const int y : tfr_years_) cols.push_back(
"tfr_" + std::to_string(y));
1467 for (
const char* c : {
"smam_m",
"smam_f",
"never_m_45_49",
"never_f_45_49",
"divorced_m_45_49",
1468 "divorced_f_45_49"})
1470 cols.emplace_back(c);
1475 for (
const char* c : {
"size",
"one_person",
"single_parent",
"multi_generation"}) cols.emplace_back(c);
1479 case table::fertility:
fertility();
break;
1480 case table::unions:
unions();
break;
1482 case table::defaults:
1487 case table::regions:
1488 case table::parameters:
break;
1493 static core::table_schema schema_(table t)
1497 case table::regions:
return {.key = {
"cca2"}, .required = {
"subregion"}, .optional = {}};
1498 case table::fertility:
1500 core::table_schema s{.key = {
"cca2"}, .required = {
"tfr",
"mac"}, .optional = {}};
1501 for (
const auto c : age_columns_) s.required.emplace_back(c);
1502 for (
const int y : tfr_years_) s.optional.push_back(
"tfr_" + std::to_string(y));
1507 core::table_schema s{.key = {
"cca2"}, .required = {}, .optional = {
"year"}};
1508 for (
auto& c : numeric_columns_(t)) s.optional.push_back(std::move(c));
1511 case table::households:
1513 core::table_schema s{.key = {
"cca2"}, .required = {}, .optional = {
"year",
"source"}};
1514 for (
auto& c : numeric_columns_(t)) s.optional.push_back(std::move(c));
1517 case table::defaults:
1519 core::table_schema s{.key = {
"subregion"}, .required = {}, .optional = {
"countries"}};
1520 for (
auto& c : numeric_columns_(t)) s.optional.push_back(std::move(c));
1523 case table::parameters:
return {.key = {
"key"}, .required = {
"value"}, .optional = {
"note"}};
1528 static tables make_tables_()
1530 return {core::layered_table{schema_(table::regions)}, core::layered_table{schema_(table::fertility)},
1531 core::layered_table{schema_(table::unions)}, core::layered_table{schema_(table::households)},
1532 core::layered_table{schema_(table::defaults)}, core::layered_table{schema_(table::parameters)}};
1540 double min_mother_age{12.0};
1541 double max_mother_age{49.9};
1542 double min_father_age{15.0};
1543 double max_father_age{80.0};
1544 double father_gap_sd{3.5};
1545 double max_gap_mean{8.0};
1546 double conception_lead{0.75};
1547 double birth_spacing{0.75};
1548 double gompertz_beta{0.09};
1549 double adult_intercept{26.0};
1550 double adult_slope{0.7};
1551 double child_q15_scale{0.012};
1552 double child_q15_decay{11.0};
1553 double dispersion_intercept{0.2};
1554 double dispersion_slope{0.27};
1555 double dispersion_min{0.3};
1556 double max_siblings{14.0};
1557 double male_birth_share{0.512};
1558 double min_union_age{16.0};
1559 double union_age_sd{4.5};
1560 double max_unions{3.0};
1561 double same_sex_share{0.03};
1562 double remarry_share{0.45};
1563 double divorce_duration_mean{9.0};
1564 double remarry_gap_mean{3.0};
1565 double union_fertility{1.0};
1566 double union_fertility_offset{0.2};
1567 double union_early_max{3.0};
1568 double later_union_factor{0.6};
1569 double adoption_factor{0.15};
1570 double half_sibling_factor{0.6};
1571 double half_sibling_extra{0.5};
1572 double married_name_share{0.8};
1573 double max_children{12.0};
1574 double twin_share{0.012};
1575 double stepchild_factor{0.6};
1576 double stepparent_factor{1.0};
1577 double stepparent_start_mean{6.0};
1578 double mother_custody_share{0.8};
1579 double household_minor_age{18.0};
1580 double young_adult_home_age{30.0};
1581 double young_adult_home_share{0.5};
1582 double one_person_scale{3.0};
1587 std::string_view key;
1591 static constexpr std::array<param_def, 43> param_table_{{
1592 {
"min_mother_age", ¶meters::min_mother_age},
1593 {
"max_mother_age", ¶meters::max_mother_age},
1594 {
"min_father_age", ¶meters::min_father_age},
1595 {
"max_father_age", ¶meters::max_father_age},
1596 {
"father_gap_sd", ¶meters::father_gap_sd},
1597 {
"max_gap_mean", ¶meters::max_gap_mean},
1598 {
"conception_lead", ¶meters::conception_lead},
1599 {
"birth_spacing", ¶meters::birth_spacing},
1600 {
"gompertz_beta", ¶meters::gompertz_beta},
1601 {
"adult_intercept", ¶meters::adult_intercept},
1602 {
"adult_slope", ¶meters::adult_slope},
1603 {
"child_q15_scale", ¶meters::child_q15_scale},
1604 {
"child_q15_decay", ¶meters::child_q15_decay},
1605 {
"dispersion_intercept", ¶meters::dispersion_intercept},
1606 {
"dispersion_slope", ¶meters::dispersion_slope},
1607 {
"dispersion_min", ¶meters::dispersion_min},
1608 {
"max_siblings", ¶meters::max_siblings},
1609 {
"male_birth_share", ¶meters::male_birth_share},
1610 {
"min_union_age", ¶meters::min_union_age},
1611 {
"union_age_sd", ¶meters::union_age_sd},
1612 {
"max_unions", ¶meters::max_unions},
1613 {
"same_sex_share", ¶meters::same_sex_share},
1614 {
"remarry_share", ¶meters::remarry_share},
1615 {
"divorce_duration_mean", ¶meters::divorce_duration_mean},
1616 {
"remarry_gap_mean", ¶meters::remarry_gap_mean},
1617 {
"union_fertility", ¶meters::union_fertility},
1618 {
"union_fertility_offset", ¶meters::union_fertility_offset},
1619 {
"union_early_max", ¶meters::union_early_max},
1620 {
"later_union_factor", ¶meters::later_union_factor},
1621 {
"adoption_factor", ¶meters::adoption_factor},
1622 {
"half_sibling_factor", ¶meters::half_sibling_factor},
1623 {
"half_sibling_extra", ¶meters::half_sibling_extra},
1624 {
"married_name_share", ¶meters::married_name_share},
1625 {
"max_children", ¶meters::max_children},
1626 {
"twin_share", ¶meters::twin_share},
1627 {
"stepchild_factor", ¶meters::stepchild_factor},
1628 {
"stepparent_factor", ¶meters::stepparent_factor},
1629 {
"stepparent_start_mean", ¶meters::stepparent_start_mean},
1630 {
"mother_custody_share", ¶meters::mother_custody_share},
1631 {
"household_minor_age", ¶meters::household_minor_age},
1632 {
"young_adult_home_age", ¶meters::young_adult_home_age},
1633 {
"young_adult_home_share", ¶meters::young_adult_home_share},
1634 {
"one_person_scale", ¶meters::one_person_scale},
1637 struct fertility_row
1640 std::vector<std::pair<int, double>> history;
1641 std::optional<core::discrete> by_age;
1649 double never_m{0.0};
1650 double never_f{0.0};
1651 double divorced_m{0.0};
1652 double divorced_f{0.0};
1656 struct household_row
1665 struct country_model
1675 std::unordered_map<std::string, country_model> countries;
1676 country_model
world;
1680 static void check_number_(
const core::tsv_row& row, std::string_view column)
1682 if (row.has(column))
1684 const double v = row.get<
double>(column);
1685 if (!std::isfinite(v))
throw row.error(column,
"must be a finite number");
1689 static void validate_(table t,
const core::tsv_row& row)
1693 case table::regions:
1694 if (row.get<std::string>(
"subregion").empty())
throw row.error(
"subregion",
"must not be empty");
1696 case table::parameters:
1698 const auto key = row.get<std::string>(
"key");
1699 if (std::ranges::none_of(param_table_, [&](
const param_def& d) {
return d.key == key; }))
1701 throw row.error(
"key",
"unknown parameter '" + key +
"'");
1703 const double v = row.get<
double>(
"value");
1704 if (!std::isfinite(v) || v < 0.0)
throw row.error(
"value",
"must be a non-negative number");
1707 case table::fertility:
1709 const double tfr = row.get<
double>(
"tfr");
1710 if (!(tfr > 0.0))
throw row.error(
"tfr",
"must be positive");
1712 for (
const auto c : age_columns_)
1714 const double v = row.get<
double>(c);
1715 if (!(v >= 0.0))
throw row.error(c,
"must not be negative");
1718 if (!(sum > 0.0))
throw row.error(
"pasfr_10_14",
"the age distribution must not be all zero");
1722 case table::households:
1723 case table::defaults:
break;
1725 const auto schema = schema_(t);
1726 for (
const auto& c : numeric_columns_(t))
1728 if (std::ranges::find(schema.optional, c) != schema.optional.end() ||
1729 std::ranges::find(schema.required, c) != schema.required.end())
1731 check_number_(row, c);
1736 static cells read_cells_(
const core::tsv_row& row, table t)
1739 const auto& schema_cols = schema_(t);
1740 for (
const auto& c : numeric_columns_(t))
1742 const bool known = std::ranges::find(schema_cols.optional, c) != schema_cols.optional.end() ||
1743 std::ranges::find(schema_cols.required, c) != schema_cols.required.end();
1744 if (known && row.has(c)) out[c] = row.get<
double>(c);
1749 static std::unordered_map<std::string, cells> read_table_(
const core::layered_table& tbl, table t)
1751 std::unordered_map<std::string, cells> out;
1752 const std::string key = t == table::defaults ?
"subregion" :
"cca2";
1753 for (
const auto& row : tbl.rows()) out[row.get<std::string>(key)] = read_cells_(row, t);
1764 [[nodiscard]]
double value(
const std::string& column)
const
1768 if (c ==
nullptr)
continue;
1769 const auto it = c->find(column);
1770 if (it != c->end())
return it->second;
1772 throw std::runtime_error(
"relationship-generator: no value for '" + column +
1773 "' in the country, its subregion or the world row of defaults.tsv");
1777 static fertility_row make_fertility_(
const lookup_cells& l, data_source source)
1781 r.tfr = l.value(
"tfr");
1782 std::vector<double> weights;
1783 for (
const auto c : age_columns_) weights.push_back(l.value(std::string{c}));
1784 r.by_age.emplace(weights);
1785 for (
const int y : tfr_years_)
1789 r.history.emplace_back(y, l.value(
"tfr_" + std::to_string(y)));
1791 catch (
const std::runtime_error&)
1796 r.history.emplace_back(2023, r.tfr);
1800 static union_row make_union_(
const lookup_cells& l, data_source source)
1802 return {.smam_m = l.value(
"smam_m"),
1803 .smam_f = l.value(
"smam_f"),
1804 .never_m = l.value(
"never_m_45_49"),
1805 .never_f = l.value(
"never_f_45_49"),
1806 .divorced_m = l.value(
"divorced_m_45_49"),
1807 .divorced_f = l.value(
"divorced_f_45_49"),
1811 static household_row make_household_(
const lookup_cells& l, data_source source)
1813 return {.size = l.value(
"size"),
1814 .one_person = l.value(
"one_person"),
1815 .single_parent = l.value(
"single_parent"),
1816 .multi_generation = l.value(
"multi_generation"),
1820 static model build_model_(
const tables& tbls)
1823 for (
const auto& row : tbls[index_(table::
parameters)].rows())
1825 const auto key = row.get<std::string>(
"key");
1826 const double v = row.get<
double>(
"value");
1827 for (
const auto& d : param_table_)
1829 if (d.key == key) m.params.*d.member = v;
1832 if (m.params.gompertz_beta <= 0.0 || m.params.dispersion_min <= 0.0 || m.params.child_q15_decay <= 0.0 || m.params.birth_spacing <= 0.0 ||
1833 m.params.min_mother_age >= m.params.max_mother_age || m.params.male_birth_share > 1.0 ||
1834 m.params.twin_share < 0.0 || m.params.twin_share > 0.5 || m.params.stepchild_factor < 0.0 ||
1835 m.params.stepparent_factor < 0.0 || m.params.stepparent_start_mean <= 0.0 ||
1836 m.params.mother_custody_share < 0.0 || m.params.mother_custody_share > 1.0 ||
1837 m.params.household_minor_age < 1.0 || m.params.young_adult_home_share < 0.0 ||
1838 m.params.young_adult_home_share > 1.0 || m.params.one_person_scale < 0.0)
1840 throw std::runtime_error(
"relationship-generator: parameters.tsv has an impossible value");
1843 std::unordered_map<std::string, std::string> region;
1844 for (
const auto& row : tbls[index_(table::
regions)].rows())
1846 region[row.get<std::string>(
"cca2")] = row.get<std::string>(
"subregion");
1848 const auto defaults = read_table_(tbls[index_(table::defaults)], table::defaults);
1849 const auto fert = read_table_(tbls[index_(table::fertility)], table::fertility);
1850 const auto uni = read_table_(tbls[index_(table::unions)], table::unions);
1851 const auto hh = read_table_(tbls[index_(table::households)], table::households);
1853 if (world ==
defaults.end())
return m;
1855 const auto resolve = [&](
const std::string& code,
const std::unordered_map<std::string, cells>& own,
1856 table t) -> std::pair<lookup_cells, data_source>
1858 const auto sub = region.find(code);
1859 const auto sub_cells = sub == region.end() ?
defaults.end() :
defaults.find(sub->second);
1860 const auto mine = own.find(code);
1861 lookup_cells l{.country = mine == own.end() ? nullptr : &mine->second,
1862 .subregion = sub_cells ==
defaults.end() ? nullptr : &sub_cells->second,
1863 .world = &
world->second};
1866 if (l.country !=
nullptr) src = data_source::country;
1867 else if (l.subregion !=
nullptr) src = data_source::subregion;
1871 std::vector<std::string> codes;
1872 for (
const auto& [code, _] : region) codes.push_back(code);
1873 for (
const auto& [code, _] : fert) codes.push_back(code);
1874 for (
const auto& [code, _] : uni) codes.push_back(code);
1875 for (
const auto& [code, _] : hh) codes.push_back(code);
1876 std::ranges::sort(codes);
1877 codes.erase(std::ranges::unique(codes).begin(), codes.end());
1879 for (
const auto& code : codes)
1881 const auto [fl, fs] = resolve(code, fert, table::fertility);
1882 const auto [ul, us] = resolve(code, uni, table::unions);
1883 const auto [hl, hs] = resolve(code, hh, table::households);
1884 m.countries.emplace(code, country_model{.fertility = make_fertility_(fl, fs), .unions = make_union_(ul, us),
1885 .households = make_household_(hl, hs)});
1887 const lookup_cells only_world{.country =
nullptr, .subregion =
nullptr, .world = &
world->second};
1888 m.world = {.fertility = make_fertility_(only_world, data_source::world),
1889 .unions = make_union_(only_world, data_source::world),
1890 .households = make_household_(only_world, data_source::world)};
1895 static documents read_directory_(
const std::filesystem::path& dir)
1898 for (
const auto t : all_tables_)
1900 const auto file = dir / file_name_(t);
1902 if (std::filesystem::is_regular_file(file, ec))
1904 docs.at(index_(t)) = core::tsv_document::load(file);
1910 void apply_(documents docs, core::layer_mode mode,
bool reset)
1912 tables next = _tables;
1913 for (
const auto t : all_tables_)
1915 auto& doc = docs.at(index_(t));
1916 auto& tbl = next.at(index_(t));
1919 if (reset) tbl.clear();
1922 (void)tbl.extend(std::move(*doc), mode, [t](
const core::tsv_row& row) { validate_(t, row); });
1924 auto built = build_model_(next);
1925 _tables = std::move(next);
1926 _model = std::move(built);
1932 tables _tables{make_tables_()};
1934 core::rng _engine{core::rng::from_entropy()};
1936 struct auto_probe_tag {};
1938 explicit relg(auto_probe_tag )
1940 if (!
load(dataset::lite)) (void)
load(dataset::full);
1943 static std::span<const core::embedded_file> embedded_files_()
1945#ifdef DASMIG_RELATIONSHIP_EMBED
1946 return embedded::relgen::files;
1952 std::uint64_t draw_seed_() {
return _engine(); }
1954 [[nodiscard]]
bool has_own_data_()
const {
return _model.ready; }
1956 void require_data_()
const
1958 if (!
has_data())
throw std::runtime_error(
"relationship-generator: this generator or birth-generator has no data loaded");
1961 [[nodiscard]]
const country_model& lookup_(
const std::string& code)
const
1963 const auto it = _model.countries.find(code);
1964 return it == _model.countries.end() ? _model.world : it->second;
1970 [[nodiscard]]
static known_person known_of_(
const family& f, std::size_t
id,
bool above)
1972 const auto& m = f.members.at(
id);
1974 k.bio_sex = m.bio_sex;
1977 if (!m.name.empty()) k.name = person_name{m.given, m.patronymic, m.family};
1980 for (
const auto& e : f.edges)
1982 if (e.kind == edge_kind::parent_of && e.to ==
id) k.parents.push_back(known_of_(f, e.from,
false));
1988 [[nodiscard]]
static std::vector<std::size_t> parents_in_(
const family& f, std::size_t
id)
1990 std::vector<std::size_t> out;
1991 for (
const auto& e : f.edges)
1993 if (e.kind == edge_kind::parent_of && e.to ==
id) out.push_back(e.from);
1998 [[nodiscard]]
static std::chrono::year_month_day mid_year_(
int year)
2000 return {std::chrono::year{year}, std::chrono::July, std::chrono::day{1}};
2003 [[nodiscard]]
static std::chrono::year_month_day year_before_(
const std::chrono::year_month_day& d)
2005 return std::chrono::year_month_day{std::chrono::sys_days{d} - std::chrono::days{365}};
2010 [[nodiscard]]
static anchor_spec anchor_of_(
const family& f, std::size_t
id)
2012 const auto& m = f.members.at(
id);
2014 a.country_code = f.country_code;
2015 a.bio_sex = m.bio_sex;
2017 if (!m.name.empty()) a.name = person_name{m.given, m.patronymic, m.family};
2019 const auto parents = parents_in_(f,
id);
2020 if (!parents.empty())
2023 if (parents.size() == 1)
2025 (f.members.at(parents[0]).bio_sex == sex::male ? a.father : a.mother) = known_of_(f, parents[0],
true);
2029 a.father = known_of_(f, parents[0],
true);
2030 a.mother = known_of_(f, parents[1],
true);
2032 std::vector<known_sibling> sibs;
2033 for (
const auto& e : f.edges)
2035 if (e.kind != edge_kind::sibling_of || (e.from !=
id && e.to !=
id))
continue;
2036 const auto other = e.from ==
id ? e.to : e.from;
2038 ks.person = known_of_(f, other,
false);
2042 const auto theirs = parents_in_(f, other);
2043 for (
const auto p : parents)
2045 if (std::ranges::find(theirs, p) != theirs.end()) ks.through = f.members.at(p).bio_sex;
2048 sibs.push_back(std::move(ks));
2050 a.siblings = std::move(sibs);
2055 std::vector<known_union>
unions;
2056 const auto add_child = [&](known_union& u, std::size_t
child)
2058 known_child c{known_of_(f, child,
false),
true};
2059 for (
const auto& e : f.edges)
2061 if (e.kind == edge_kind::parent_of && e.to == child && e.from ==
id) c.genetic = e.genetic;
2063 u.children.push_back(std::move(c));
2065 std::vector<std::pair<std::optional<std::size_t>, std::size_t>> kids;
2066 for (
const auto& e : f.edges)
2068 if (e.kind != edge_kind::parent_of || e.from !=
id)
continue;
2069 std::optional<std::size_t>
other;
2070 for (
const auto p : parents_in_(f, e.to))
2072 if (p !=
id)
other = p;
2074 kids.emplace_back(other, e.to);
2078 for (
const auto& e : f.edges)
2080 if (e.kind != edge_kind::partner_of || e.from != 0)
continue;
2082 u.partner = known_of_(f, e.to,
false);
2083 u.start = mid_year_(*e.start);
2084 if (e.ended != union_end::ongoing)
2086 u.end = (e.ended == union_end::death && u.partner->death) ? *u.partner->death : mid_year_(*e.end);
2088 for (
const auto& [other, child] : kids)
2090 if (other && *other == e.to) add_child(u, child);
2093 for (
const auto& pe : f.edges)
2095 if (pe.kind != edge_kind::parent_of || pe.from != e.to)
continue;
2096 if (f.members.at(pe.to).role == relation::stepchild) u.stepchildren.push_back(known_of_(f, pe.to,
false));
2098 unions.push_back(std::move(u));
2101 for (
const auto& [other, child] : kids)
2103 if (!other) add_child(loose, child);
2105 if (!loose.children.empty())
2107 loose.start = year_before_(loose.children.front().person.birth);
2108 unions.push_back(std::move(loose));
2113 std::vector<std::optional<std::size_t>> seen;
2114 for (
const auto& [other, child] : kids)
2116 if (std::ranges::find(seen, other) != seen.end())
continue;
2117 seen.push_back(other);
2119 if (other) u.partner = known_of_(f, *other,
false);
2120 for (
const auto& [o2, c2] : kids)
2122 if (o2 == other) add_child(u, c2);
2124 u.start = year_before_(u.children.front().person.birth);
2125 if (u.partner && u.partner->death) u.end = u.partner->death;
2126 unions.push_back(std::move(u));
2129 if (!
unions.empty()) a.unions = std::move(unions);
2135 static constexpr double never_dies_ = 1000.0;
2136 static constexpr double max_age_ = 122.0;
2137 static constexpr double child_age_ = 15.0;
2138 static constexpr std::int64_t none_ = -1;
2139 static constexpr std::size_t no_member_ =
static_cast<std::size_t
>(-1);
2141 static constexpr double half_cluster_years_ = 4.0;
2144 static constexpr std::int64_t unlisted_ = 100000;
2151 double lifespan{0.0};
2161 std::array<std::int64_t, 2> parents{none_, none_};
2162 std::int64_t name_child{none_};
2164 std::optional<person_name> fixed{};
2171 double birth_day{0.0};
2178 std::vector<life> siblings;
2179 std::vector<double> mother_births;
2183 struct known_parents
2185 const known_person*
father;
2186 const known_person*
mother;
2195 bool same_sex{
false};
2196 bool has_partner{
true};
2197 std::optional<person_name> partner_name{};
2205 std::optional<person_name> fixed{};
2208 static std::int64_t days_(
const std::chrono::year_month_day& d)
2210 return std::chrono::sys_days{d}.time_since_epoch().count();
2213 static std::chrono::year_month_day from_days_(
double day)
2215 return std::chrono::year_month_day{
2216 std::chrono::sys_days{std::chrono::days{
static_cast<std::int64_t
>(std::floor(day))}}};
2219 static double clamp_(
double v,
double lo,
double hi) {
return std::min(std::max(v, lo), hi); }
2222 static double back_(
double day,
double years) {
return day - core::math::fenced(years * year_days_); }
2223 static double forward_(
double day,
double years) {
return day + core::math::fenced(years * year_days_); }
2226 static int calendar_age_(
const std::chrono::year_month_day& birth,
const std::chrono::year_month_day& at)
2228 int age =
static_cast<int>(at.year()) -
static_cast<int>(birth.year());
2229 if (at.month() < birth.month() || (at.month() == birth.month() && at.day() < birth.day())) --age;
2230 return std::max(age, 0);
2233 static std::size_t push_(std::vector<raw_member>& raw, relation role,
const life& l, std::string key)
2235 raw.push_back({.role = role, .life = l, .key = std::move(key)});
2236 return raw.size() - 1;
2239 static person to_person_(
const raw_member& m, std::size_t
id,
double ref_day)
2244 p.bio_sex = m.life.s;
2245 p.birth = from_days_(m.life.birth);
2246 const double death_day = forward_(m.life.birth, m.life.lifespan);
2247 p.alive = death_day > ref_day;
2250 p.age =
static_cast<std::uint8_t
>(std::min(calendar_age_(p.birth, from_days_(ref_day)), 255));
2254 p.death = from_days_(death_day);
2255 p.age =
static_cast<std::uint8_t
>(std::min(calendar_age_(p.birth, *p.death), 255));
2261 static void check_name_(
const std::optional<person_name>& n)
2263 if (n && n->given.empty())
throw std::invalid_argument(
"a known person's name needs a given name");
2266 static void check_person_(
const known_person& k)
2268 check_name_(k.name);
2269 for (
const auto& parent : k.parents) check_person_(parent);
2272 static void check_known_(
const anchor_spec& a)
2274 check_name_(a.name);
2275 if (a.father) check_person_(*a.father);
2276 if (a.mother) check_person_(*a.mother);
2277 for (
const auto& s : a.siblings.value_or(std::vector<known_sibling>{})) check_person_(s.person);
2278 for (
const auto& u : a.
unions.value_or(std::vector<known_union>{}))
2280 if (u.partner) check_person_(*u.partner);
2281 for (
const auto& c : u.children) check_person_(c.person);
2287 [[nodiscard]]
static life life_of_(
const known_person& k,
double ref_day,
int index)
2289 if (!k.birth.ok())
throw std::invalid_argument(
"a known person's birth is not a date");
2290 const double birth =
static_cast<double>(days_(k.birth));
2291 double lifespan = never_dies_;
2294 if (!k.death->ok())
throw std::invalid_argument(
"a known person's death is not a date");
2295 const double d =
static_cast<double>(days_(*k.death));
2296 if (d < birth)
throw std::invalid_argument(
"a known person died before being born");
2298 if (d < ref_day) lifespan = ((d - birth) / year_days_) + 1e-6;
2300 return {.birth = birth, .lifespan = lifespan, .s = k.bio_sex, .index = index};
2304 [[nodiscard]]
static union_rec union_of_(
const known_union& k, std::size_t j, sex anchor_sex,
double ref_day)
2306 if (!k.start.ok())
throw std::invalid_argument(
"a known union's start is not a date");
2310 u.partner = life_of_(*k.partner, ref_day,
static_cast<int>(j));
2311 u.partner_name = k.partner->name;
2312 u.same_sex = k.partner->bio_sex == anchor_sex;
2316 u.partner = {.birth = 0.0, .lifespan = never_dies_, .s = anchor_sex == sex::male ? sex::female : sex::male,
2317 .index =
static_cast<int>(j)};
2318 u.has_partner =
false;
2320 u.start =
static_cast<double>(days_(k.start));
2324 if (!k.end->ok())
throw std::invalid_argument(
"a known union's end is not a date");
2325 const double e =
static_cast<double>(days_(*k.end));
2326 if (e < u.start)
throw std::invalid_argument(
"a known union ends before it begins");
2330 const bool partner_died =
2331 k.partner && k.partner->death &&
static_cast<double>(days_(*k.partner->death)) <= e;
2332 u.ended = partner_died ? union_end::death : union_end::divorce;
2339 [[nodiscard]]
static std::vector<child_rec> known_children_(
const std::vector<known_union>& unions,
double ref_day)
2341 std::vector<child_rec> out;
2342 for (std::size_t j = 0; j <
unions.size(); ++j)
2344 for (std::size_t i = 0; i <
unions[j].children.size(); ++i)
2346 const auto& c =
unions[j].children[i];
2347 out.push_back({.life = life_of_(c.person, ref_day,
static_cast<int>(i)),
2348 .union_index =
static_cast<int>(j),
2349 .genetic = c.genetic,
2350 .fixed = c.person.name});
2356 [[nodiscard]] anchor_info draw_anchor_(
const family_request& request, std::uint64_t seed,
double ref_day)
const
2358 const auto& spec = request.anchor;
2359 if (spec.birth && !spec.birth->ok())
throw std::invalid_argument(
"family_request.anchor.birth is not a date");
2360 if (spec.age && (*spec.age < 0 || *spec.age >
static_cast<int>(max_age_)))
2362 throw std::invalid_argument(
"family_request.anchor.age must be 0 to 122");
2364 std::optional<std::string>
country;
2365 if (spec.country_code)
2367 std::string code = *spec.country_code;
2368 for (
char& c : code) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
2369 const auto known = _from.
birth->countries();
2370 if (std::find(known.begin(), known.end(), code) == known.end())
2372 throw std::invalid_argument(
"relationship-generator: unknown country code: " + *spec.country_code);
2377 if (spec.birth && country && spec.bio_sex)
2379 if (calendar_age_(*spec.birth, from_days_(ref_day)) >
static_cast<int>(max_age_))
2381 throw std::invalid_argument(
"the anchor would be older than 122 at the reference date");
2384 a.s = *spec.bio_sex;
2385 a.birth_day =
static_cast<double>(days_(*spec.birth));
2391 br.bio_sex = spec.bio_sex;
2392 br.weighted = request.weighted;
2393 br.reference_date = request.reference_date;
2396 br.year = year_t{
static_cast<std::uint16_t
>(
static_cast<int>(spec.birth->year()))};
2400 const auto age =
static_cast<std::uint8_t
>(*spec.age);
2401 br.ages = age_range{.min = age, .max = age};
2403 const auto b = _from.
birth->get_birth(br, seed);
2404 a.country = b.country_code;
2406 a.birth_day =
static_cast<double>(days_(
2407 spec.birth ? *spec.birth
2408 : std::chrono::year_month_day{std::chrono::year{b.year},
2409 std::chrono::month{b.month}, std::chrono::day{b.day}}));
2411 if (a.birth_day > ref_day)
throw std::invalid_argument(
"the anchor is born after the reference date");
2427 [[nodiscard]] life draw_life_(core::rng r,
const std::string& country, sex s,
double birth_day,
2428 double alive_until)
const
2430 const auto& p = _model.params;
2431 const double e0 = _from.
birth->life_expectancy(country, s);
2432 const double q15 = std::min(0.9, p.child_q15_scale * core::math::exp((80.0 - e0) / p.child_q15_decay));
2433 const double beta = p.gompertz_beta;
2434 const double adult_mean = p.adult_intercept + core::math::fenced(p.adult_slope * e0);
2435 const double mode = adult_mean + (euler_gamma_ / beta);
2436 const double c = core::math::exp(-(beta * mode));
2437 const double child_roll = core::uniform01(r);
2438 const double within = core::uniform01(r);
2439 const double u = 1.0 - core::uniform01(r);
2440 if (alive_until < child_age_ && child_roll < q15 * ((child_age_ - alive_until) / child_age_))
2442 return {.birth = birth_day,
2443 .lifespan = alive_until + core::math::fenced(((child_age_ - alive_until) * within) * within),
2446 const double from = std::max(alive_until, child_age_);
2447 const double grown = core::math::exp(beta * from) - (core::math::log(u) / c);
2448 const double lifespan = core::math::log(grown) / beta;
2449 return {.birth = birth_day, .lifespan = clamp_(lifespan, from, max_age_), .s = s};
2454 [[nodiscard]]
double draw_mother_age_(
const fertility_row& f, core::rng& r)
const
2456 const auto& p = _model.params;
2457 double a = p.min_mother_age;
2458 for (
int i = 0; i < 12; ++i)
2460 const double group = 10.0 + (5.0 *
static_cast<double>((*f.by_age)(r)));
2461 a = group + core::math::fenced(5.0 * core::uniform01(r));
2462 if (a >= p.min_mother_age && a <= p.max_mother_age)
return a;
2464 return clamp_(a, p.min_mother_age, p.max_mother_age);
2468 [[nodiscard]]
static double tfr_at_(
const fertility_row& f,
double year)
2470 const auto& h = f.history;
2471 if (year <=
static_cast<double>(h.front().first))
return h.front().second;
2472 for (std::size_t i = 1; i < h.size(); ++i)
2474 if (year <=
static_cast<double>(h[i].first))
2476 const double y0 =
static_cast<double>(h[i - 1].first);
2477 const double t = (year - y0) / (
static_cast<double>(h[i].first) - y0);
2478 return h[i - 1].second + core::math::fenced(t * (h[i].second - h[i - 1].second));
2481 return h.back().second;
2486 [[nodiscard]]
static double gamma_(core::rng& r,
double shape,
double scale)
2490 const double u = 1.0 - core::uniform01(r);
2491 return gamma_(r, shape + 1.0, scale) * core::math::exp(core::math::log(u) / shape);
2493 const double d = shape - (1.0 / 3.0);
2494 const double c = 1.0 / std::sqrt(9.0 * d);
2497 const double x = core::normal(r, 0.0, 1.0);
2498 const double t = 1.0 + core::math::fenced(c * x);
2499 if (t <= 0.0)
continue;
2500 const double v = t * t * t;
2501 const double u = core::uniform01(r);
2502 if (u <= 0.0)
continue;
2503 const double bound = core::math::fenced(0.5 * x * x) + d - core::math::fenced(d * v) +
2504 core::math::fenced(d * core::math::log(v));
2505 if (core::math::log(u) < bound)
return d * v * scale;
2510 [[nodiscard]]
static int poisson_(core::rng& r,
double lambda)
2512 const double limit = core::math::exp(-std::min(lambda, 40.0));
2518 p *= core::uniform01(r);
2519 }
while (p > limit && k < 200);
2523 [[nodiscard]]
static double exponential_(core::rng& r,
double mean)
2525 return -(mean * core::math::log(1.0 - core::uniform01(r)));
2529 [[nodiscard]]
double dispersion_(
double mean)
const
2531 const auto& p = _model.params;
2532 return std::max(p.dispersion_min, p.dispersion_intercept + (p.dispersion_slope * mean));
2543 [[nodiscard]]
int family_size_(core::rng& r,
double mean)
const
2545 if (mean <= 0.0)
return 0;
2546 const double d = dispersion_(mean);
2549 const int n = std::max(1,
static_cast<int>(std::lround(mean / (1.0 - d))));
2550 const double prob = std::min(1.0, mean /
static_cast<double>(n));
2552 for (
int i = 0; i < n; ++i) size += core::bernoulli(r, prob) ? 1 : 0;
2555 if (d <= 1.05)
return poisson_(r, mean);
2556 const double k = mean / (d - 1.0);
2557 return poisson_(r, gamma_(r, k, mean / k));
2569 [[nodiscard]]
int sibling_count_(core::rng& r,
double mean)
const
2571 const double d = dispersion_(mean);
2574 const int n = std::max(1,
static_cast<int>(std::lround(mean / (1.0 - d))));
2575 const double prob = std::min(1.0, mean /
static_cast<double>(n));
2577 for (
int i = 1; i < n; ++i) siblings += core::bernoulli(r, prob) ? 1 : 0;
2580 if (d <= 1.05)
return poisson_(r, mean);
2581 const double k = mean / (d - 1.0);
2582 return poisson_(r, gamma_(r, k + 1.0, mean / k));
2588 [[nodiscard]] lineage draw_lineage_(
const country_model& cm,
const std::string& country,
const core::rng& r,
2589 double child_birth,
double ref_day,
bool with_siblings,
2590 const known_parents& known)
const
2592 const auto& p = _model.params;
2594 auto age_rng = r.split(
"mother-age");
2595 double mother_age = draw_mother_age_(cm.fertility, age_rng);
2596 auto gap_rng = r.split(
"father-gap");
2597 const double mean_gap = clamp_(cm.unions.smam_m - cm.unions.smam_f, 0.0, p.max_gap_mean);
2598 double father_age = clamp_(mother_age + core::normal(gap_rng, mean_gap, p.father_gap_sd),
2599 p.min_father_age, p.max_father_age);
2600 const double drawn_gap = father_age - mother_age;
2601 std::optional<life> known_mother;
2602 std::optional<life> known_father;
2603 if (known.mother !=
nullptr)
2605 known_mother = life_of_(*known.mother, ref_day, 0);
2606 mother_age = (child_birth - known_mother->birth) / year_days_;
2608 if (known.father !=
nullptr)
2610 known_father = life_of_(*known.father, ref_day, 0);
2611 father_age = (child_birth - known_father->birth) / year_days_;
2613 if (known_mother && !known_father) father_age = clamp_(mother_age + drawn_gap, p.min_father_age, p.max_father_age);
2614 if (known_father && !known_mother) mother_age = clamp_(father_age - drawn_gap, p.min_mother_age, p.max_mother_age);
2615 if ((known_mother && mother_age <= 0.0) || (known_father && father_age <= 0.0))
2617 throw std::invalid_argument(
"a known parent is not born before the child");
2619 out.mother = known_mother ? *known_mother
2620 : draw_life_(r.split(
"mother-life"), country, sex::female,
2621 back_(child_birth, mother_age), mother_age);
2622 out.father = known_father ? *known_father
2623 : draw_life_(r.split(
"father-life"), country, sex::male,
2624 back_(child_birth, father_age),
2625 std::max(0.0, father_age - p.conception_lead));
2626 out.mother_births.push_back(child_birth);
2627 if (!with_siblings)
return out;
2629 auto count_rng = r.split(
"sibling-count");
2630 const double mean = tfr_at_(cm.fertility, 1970.0 + (child_birth / year_days_));
2631 const int wanted = std::min(sibling_count_(count_rng, mean),
static_cast<int>(p.max_siblings));
2636 std::vector<double> mother_ages{mother_age};
2637 const auto siblings = r.split(
"siblings");
2638 for (
int i = 0; i < wanted; ++i)
2640 auto ri = siblings.split(
static_cast<std::uint64_t
>(i));
2641 for (
int attempt = 0; attempt < 12; ++attempt)
2643 const double a = draw_mother_age_(cm.fertility, ri);
2644 const double birth = forward_(child_birth, a - mother_age);
2645 const double fa = father_age + (a - mother_age);
2646 if (a >= out.mother.lifespan || birth > ref_day || fa < p.min_father_age || fa > p.max_father_age ||
2647 fa - p.conception_lead >= out.father.lifespan)
2651 if (std::ranges::any_of(mother_ages, [&](
double e) {
return std::abs(a - e) < p.birth_spacing; }))
2655 mother_ages.push_back(a);
2656 out.mother_births.push_back(birth);
2657 const sex s = core::bernoulli(ri, p.male_birth_share) ? sex::male : sex::female;
2658 auto l = draw_life_(ri.split(
"life"), country, s, birth, 0.0);
2660 out.siblings.push_back(l);
2661 if (
const auto t = twin_of_(ri, country, l)) out.siblings.push_back(*t);
2667 auto twin_rng = r.split(
"anchor-twin");
2668 if (p.max_siblings >= 1.0 && core::bernoulli(twin_rng, 2.0 * p.twin_share))
2670 const sex s = core::bernoulli(twin_rng, p.male_birth_share) ? sex::male : sex::female;
2671 auto l = draw_life_(twin_rng.split(
"life"), country, s, child_birth, 0.0);
2673 out.siblings.push_back(l);
2679 [[nodiscard]] std::optional<life> twin_of_(core::rng& r,
const std::string& country,
const life& l)
const
2681 const auto& p = _model.params;
2682 if (!core::bernoulli(r, p.twin_share))
return std::nullopt;
2683 const sex s = core::bernoulli(r, p.male_birth_share) ? sex::male : sex::female;
2684 auto t = draw_life_(r.split(
"twin"), country, s, l.birth, 0.0);
2685 t.index = 1000 + l.index;
2694 [[nodiscard]] std::vector<life> draw_offspring_(
const country_model& cm,
const std::string& country,
2695 const life& parent,
int count,
2696 std::vector<double> mother_births,
double ref_day,
2697 const core::rng& r)
const
2699 const auto& p = _model.params;
2700 std::vector<life> out;
2701 const bool female = parent.s == sex::female;
2702 const double mean_gap = clamp_(cm.unions.smam_m - cm.unions.smam_f, 0.0, p.max_gap_mean);
2703 for (
int i = 0; i < count; ++i)
2705 auto ri = r.split(
static_cast<std::uint64_t
>(i));
2706 for (
int attempt = 0; attempt < 12; ++attempt)
2708 const double am = draw_mother_age_(cm.fertility, ri);
2709 const double pa = female ? am
2710 : clamp_(am + core::normal(ri, mean_gap, p.father_gap_sd), p.min_father_age,
2712 const double birth = forward_(parent.birth, pa);
2713 if (birth > ref_day || (female ? pa >= parent.lifespan : pa - p.conception_lead >= parent.lifespan))
2717 if (female && std::ranges::any_of(mother_births, [&](
double e)
2718 {
return std::abs(birth - e) < p.birth_spacing * year_days_; }))
2722 if (female) mother_births.push_back(birth);
2723 const sex s = core::bernoulli(ri, p.male_birth_share) ? sex::male : sex::female;
2724 auto l = draw_life_(ri.split(
"life"), country, s, birth, 0.0);
2727 if (
const auto t = twin_of_(ri, country, l)) out.push_back(*t);
2738 [[nodiscard]] std::vector<life> draw_half_siblings_(
const country_model& cm,
const std::string& country,
2739 const life& parent,
bool father,
2740 std::vector<double> mother_births,
double ref_day,
2741 const core::rng& r)
const
2743 const auto& p = _model.params;
2744 const double never =
father ? cm.unions.never_m : cm.unions.never_f;
2745 const double divorced =
father ? cm.unions.divorced_m : cm.unions.divorced_f;
2746 const double chance = clamp_(p.half_sibling_factor * divorced / std::max(100.0 - never, 10.0), 0.0, 0.9);
2747 auto roll = r.split(
"roll");
2748 if (!core::bernoulli(roll, chance))
return {};
2749 const int count = std::min(1 + poisson_(roll, p.half_sibling_extra),
static_cast<int>(p.max_siblings));
2750 return draw_offspring_(cm, country, parent, count, std::move(mother_births), ref_day, r.split(
"births"));
2754 [[nodiscard]] std::vector<life> draw_grandchildren_(
const country_model& cm,
const std::string& country,
2755 const life& child,
double ref_day,
const core::rng& r)
const
2757 const auto& p = _model.params;
2758 auto count_rng = r.split(
"count");
2759 const double mean = tfr_at_(cm.fertility, 1970.0 + (
child.birth / year_days_) + 28.0);
2760 const int count = std::min(family_size_(count_rng, mean),
static_cast<int>(p.max_children));
2761 return draw_offspring_(cm, country, child, count, {}, ref_day, r.split(
"births"));
2768 [[nodiscard]] std::vector<life> draw_stepchildren_(
const country_model& cm,
const std::string& country,
2769 const union_rec& u,
double ref_day,
const core::rng& r)
const
2771 const auto& p = _model.params;
2772 const bool male = u.partner.s == sex::male;
2773 const double never = male ? cm.unions.never_m : cm.unions.never_f;
2774 const double divorced = male ? cm.unions.divorced_m : cm.unions.divorced_f;
2775 const double chance = clamp_(p.stepchild_factor * divorced / std::max(100.0 - never, 10.0), 0.0, 0.9);
2776 auto roll = r.split(
"roll");
2777 if (!core::bernoulli(roll, chance))
return {};
2778 const int count = std::min(1 + poisson_(roll, p.half_sibling_extra),
static_cast<int>(p.max_children));
2779 return draw_offspring_(cm, country, u.partner, count, {}, std::min(u.start - 0.75 * year_days_, ref_day),
2800 [[nodiscard]] std::optional<step_rec> draw_stepparent_(
const country_model& cm,
const std::string& country,
2801 const life& parent,
double child_birth,
double together_until,
2802 double ref_day,
const core::rng& r)
const
2804 const auto& p = _model.params;
2805 const bool male = parent.s == sex::male;
2806 const double never = male ? cm.unions.never_m : cm.unions.never_f;
2807 const double divorced = male ? cm.unions.divorced_m : cm.unions.divorced_f;
2808 const double p_divorce = clamp_(divorced / std::max(100.0 - never, 10.0), 0.0, 0.7);
2809 const double chance = clamp_(p.stepparent_factor * p_divorce * p.remarry_share, 0.0, 0.9);
2810 auto roll = r.split(
"roll");
2811 if (!core::bernoulli(roll, chance))
return std::nullopt;
2812 const double start = forward_(together_until, 1.0 + exponential_(roll, p.stepparent_start_mean));
2813 const double parent_death = forward_(parent.birth, parent.lifespan);
2814 const double parent_age = (start - parent.birth) / year_days_;
2815 if (start >= std::min(parent_death, ref_day) || parent_age < p.min_union_age ||
2816 start >= forward_(child_birth, p.household_minor_age))
2818 return std::nullopt;
2823 auto sex_rng = r.split(
"sex");
2824 const bool same_sex = core::bernoulli(sex_rng, p.same_sex_share);
2825 const sex ps = same_sex ? parent.s : (male ? sex::female : sex::male);
2826 const double mean_gap = clamp_(cm.unions.smam_m - cm.unions.smam_f, 0.0, p.max_gap_mean);
2827 auto gap_rng = r.split(
"gap");
2828 const double signed_gap = same_sex ? 0.0 : (male ? -mean_gap : mean_gap);
2829 const double partner_age = std::max(p.min_union_age, parent_age + core::normal(gap_rng, signed_gap, p.father_gap_sd));
2830 out.partner = draw_life_(r.split(
"life"), country, ps, back_(start, partner_age), partner_age);
2831 const double partner_death = forward_(out.partner.birth, out.partner.lifespan);
2833 auto end_rng = r.split(
"end");
2834 const bool separates = core::bernoulli(end_rng, p_divorce);
2835 const double separation = forward_(start, 0.5 + exponential_(end_rng, p.divorce_duration_mean));
2836 const double first_death = std::min(partner_death, parent_death);
2837 if (separates && separation < std::min(first_death, ref_day))
2839 out.end = separation;
2840 out.ended = union_end::divorce;
2842 else if (first_death <= ref_day)
2844 out.end = first_death;
2845 out.ended = union_end::death;
2858 static int tie_half_siblings_(std::vector<raw_member>& raw, std::size_t parent, std::size_t stepparent,
2859 const step_rec& u,
const parameters& p)
2861 const life sp = raw.at(stepparent).life;
2862 const bool via_father = raw.at(parent).life.s == sex::male;
2863 const std::size_t own = via_father ? 0 : 1;
2864 const auto parent_id =
static_cast<std::int64_t
>(parent);
2865 const double death = forward_(sp.birth, sp.lifespan);
2866 std::vector<double> births;
2869 if (m.role != relation::half_sibling || m.parents.at(own) != parent_id)
continue;
2870 const double b = m.life.birth;
2871 if (b < u.start || b > u.end)
continue;
2872 const double age = (b - sp.birth) / year_days_;
2875 if (age < p.min_mother_age || age > p.max_mother_age || b > death)
continue;
2876 if (std::ranges::any_of(births, [&](
double e)
2877 {
return e != b && std::abs(b - e) < p.birth_spacing * year_days_; }))
2882 else if (age < p.min_father_age || age > p.max_father_age || age - p.conception_lead >= sp.lifespan)
2886 m.parents.at(1 - own) =
static_cast<std::int64_t
>(stepparent);
2887 if (std::ranges::find(births, b) == births.end()) births.push_back(b);
2889 return static_cast<int>(births.size());
2908 [[nodiscard]] household draw_household_(
const country_model& cm,
const family& f,
const core::rng& r)
const
2910 const auto& p = _model.params;
2911 const auto& row = cm.households;
2912 const auto& me = f.members.front();
2913 auto roll = r.split(
"roll");
2915 const auto pct = [](
double v) {
return clamp_(v / 100.0, 0.0, 0.9); };
2916 const auto minor = [&](std::size_t id)
2917 {
return f.members[id].alive &&
static_cast<double>(f.members[id].age) < p.household_minor_age; };
2918 const auto has_edge = [&](
edge_kind kind, std::size_t from, std::size_t to)
2920 return std::ranges::any_of(f.edges, [&](
const edge& e) { return e.kind == kind && e.from == from && e.to == to; });
2922 const auto ongoing = [&](std::size_t a, std::size_t b)
2924 return std::ranges::any_of(f.edges, [&](
const edge& e)
2925 { return e.kind == edge_kind::partner_of && e.from == a && e.to == b &&
2926 e.ended == union_end::ongoing; });
2928 const auto add = [&](std::size_t id)
2930 if (std::ranges::find(out.members,
id) == out.members.end()) out.members.push_back(
id);
2932 const auto role_ids = [&](std::initializer_list<relation> roles,
bool alive_only)
2934 std::vector<std::size_t> ids;
2935 for (
const auto& m : f.members)
2937 if (std::ranges::find(roles, m.role) != roles.end() && (!alive_only || m.alive)) ids.push_back(m.id);
2942 const auto add_siblings = [&](
const std::vector<std::size_t>& parents)
2944 for (
const auto id : role_ids({relation::sibling, relation::half_sibling},
true))
2946 if (minor(
id) && std::ranges::any_of(parents, [&](std::size_t q) {
return has_edge(edge_kind::parent_of, q,
id); }))
2951 const auto pick = [&](
const std::vector<std::size_t>& candidates) -> std::optional<std::size_t>
2953 if (candidates.empty())
return std::nullopt;
2954 return candidates[
static_cast<std::size_t
>(core::bounded(roll, candidates.size()))];
2957 if (
static_cast<double>(me.age) < p.household_minor_age)
2959 const auto live = role_ids({relation::father, relation::mother},
true);
2962 out.type = household_type::other;
2966 std::vector<std::size_t> stepped;
2967 std::optional<std::size_t> step_of_chosen;
2968 for (
const auto q : live)
2970 for (
const auto s : role_ids({relation::stepfather, relation::stepmother},
true))
2972 if (
ongoing(q, s)) stepped.push_back(q);
2975 const auto is_mother = [&](std::size_t q) {
return f.members[q].role == relation::mother; };
2976 const auto keep_one = [&](
const std::vector<std::size_t>& both)
2978 const bool mother_first = core::bernoulli(roll, p.mother_custody_share);
2979 for (
const auto q : both)
2981 if (is_mother(q) == mother_first)
return q;
2983 return both.front();
2985 std::vector<std::size_t> chosen;
2986 if (!stepped.empty())
2988 const auto q = stepped.size() == 2 ? keep_one(stepped) : stepped.front();
2989 chosen.push_back(q);
2990 for (
const auto s : role_ids({relation::stepfather, relation::stepmother},
true))
2992 if (
ongoing(q, s)) step_of_chosen = s;
2995 else if (live.size() == 2 && core::bernoulli(roll, pct(row.single_parent)))
2997 chosen.push_back(keep_one(live));
3003 for (
const auto q : chosen) add(q);
3004 if (step_of_chosen) add(*step_of_chosen);
3005 const std::size_t adults = out.members.size() - 1;
3006 add_siblings(chosen);
3010 auto kept = r.split(
"stepsiblings");
3011 const double share = f.members[*step_of_chosen].bio_sex == sex::female ? p.mother_custody_share
3012 : 1.0 - p.mother_custody_share;
3013 std::vector<std::size_t> theirs;
3014 for (
const auto id : role_ids({relation::stepsibling},
true))
3016 if (minor(
id) && has_edge(edge_kind::parent_of, *step_of_chosen,
id)) theirs.push_back(
id);
3018 if (!theirs.empty() && core::bernoulli(kept, share))
3020 for (
const auto id : theirs) add(id);
3023 out.type = adults >= 2 ? household_type::nuclear : household_type::single_parent;
3024 if (core::bernoulli(roll, pct(row.multi_generation)))
3026 std::vector<std::size_t> grand;
3027 for (
const auto g : role_ids({relation::paternal_grandfather, relation::paternal_grandmother,
3028 relation::maternal_grandfather, relation::maternal_grandmother},
3031 if (std::ranges::any_of(chosen, [&](std::size_t q) {
return has_edge(edge_kind::parent_of, g, q); }))
3034 if (
const auto g = pick(grand))
3037 out.type = household_type::multi_generation;
3044 std::optional<std::size_t>
partner;
3045 for (
const auto id : role_ids({relation::partner},
true))
3047 if (
ongoing(0,
id)) partner =
id;
3049 std::map<std::int64_t, bool> keeps;
3051 for (
const auto id : role_ids({relation::child, relation::stepchild},
true))
3053 if (!minor(
id))
continue;
3054 std::optional<std::size_t>
other;
3055 for (
const auto& e : f.edges)
3057 if (e.kind == edge_kind::parent_of && e.to ==
id && e.from != 0)
other = e.from;
3059 const bool step = f.members[id].role == relation::stepchild;
3061 if (partner && other && *other == *partner)
3067 const std::int64_t key =
other ?
static_cast<std::int64_t
>(*other) : -1;
3068 auto it = keeps.find(key);
3069 if (it == keeps.end())
3071 auto kr = roll.split(
"custody").split(
static_cast<std::uint64_t
>(key + 1));
3072 const double share = me.bio_sex == sex::female ? p.mother_custody_share : 1.0 - p.mother_custody_share;
3073 it = keeps.emplace(key, core::bernoulli(kr, share)).first;
3083 if (partner) add(*partner);
3085 if (partner || kids)
3087 out.type = !kids ? household_type::couple : (
partner ? household_type::nuclear : household_type::single_parent);
3088 if (core::bernoulli(roll, pct(row.multi_generation)))
3090 if (
const auto g = pick(role_ids({relation::father, relation::mother},
true)))
3093 out.type = household_type::multi_generation;
3099 const auto parents = role_ids({relation::father, relation::mother},
true);
3100 if (!parents.empty() &&
static_cast<double>(me.age) < p.young_adult_home_age &&
3101 core::bernoulli(roll, p.young_adult_home_share))
3103 for (
const auto q : parents) add(q);
3104 add_siblings(parents);
3105 out.type = household_type::with_parents;
3108 out.type = core::bernoulli(roll, pct(row.one_person * p.one_person_scale)) ? household_type::one_person
3109 : household_type::other;
3120 [[nodiscard]] std::vector<union_rec> draw_unions_(
const country_model& cm,
const std::string& country,
3121 const life& a,
double ref_day,
const core::rng& r)
const
3123 const auto& p = _model.params;
3124 std::vector<union_rec> out;
3125 const bool male = a.s == sex::male;
3126 const double never = male ? cm.unions.never_m : cm.unions.never_f;
3127 const double divorced = male ? cm.unions.divorced_m : cm.unions.divorced_f;
3128 auto ever = r.split(
"ever");
3129 if (core::bernoulli(ever, clamp_(never / 100.0, 0.0, 1.0)))
return out;
3130 const double p_divorce = clamp_(divorced / std::max(100.0 - never, 10.0), 0.0, 0.7);
3131 const double mean_gap = clamp_(cm.unions.smam_m - cm.unions.smam_f, 0.0, p.max_gap_mean);
3132 const double smam = male ? cm.unions.smam_m : cm.unions.smam_f;
3133 auto age_rng = r.split(
"start-age");
3136 const double earlier = clamp_(0.5 * (smam - 21.0), 0.0, p.union_early_max);
3137 double start = forward_(a.birth, clamp_(core::normal(age_rng, smam - earlier, p.union_age_sd),
3138 p.min_union_age, 60.0));
3139 for (
int j = 0; j < static_cast<int>(p.max_unions) && start <= ref_day; ++j)
3141 const auto uj = r.split(
"union").split(
static_cast<std::uint64_t
>(j));
3144 auto sex_rng = uj.split(
"sex");
3145 u.same_sex = core::bernoulli(sex_rng, p.same_sex_share);
3146 const sex ps = u.same_sex ? a.s : (male ? sex::female : sex::male);
3147 auto gap_rng = uj.split(
"gap");
3148 const double signed_gap = u.same_sex ? 0.0 : (male ? -mean_gap : mean_gap);
3149 const double my_age = (start - a.birth) / year_days_;
3150 const double partner_age =
3151 std::max(p.min_union_age, my_age + core::normal(gap_rng, signed_gap, p.father_gap_sd));
3152 u.partner = draw_life_(uj.split(
"life"), country, ps, back_(start, partner_age), partner_age);
3153 const double partner_death = forward_(u.partner.birth, u.partner.lifespan);
3155 auto end_rng = uj.split(
"end");
3156 const bool separates = core::bernoulli(end_rng, p_divorce);
3157 const double separation = forward_(start, 0.5 + exponential_(end_rng, p.divorce_duration_mean));
3158 if (separates && separation < std::min(partner_death, ref_day))
3161 u.ended = union_end::divorce;
3163 else if (partner_death <= ref_day)
3165 u.end = partner_death;
3166 u.ended = union_end::death;
3169 if (u.ended == union_end::ongoing)
break;
3170 auto again = uj.split(
"remarry");
3171 if (!core::bernoulli(again, p.remarry_share))
break;
3172 start = forward_(u.end, 0.5 + exponential_(again, p.remarry_gap_mean));
3185 [[nodiscard]] std::vector<child_rec> draw_union_children_(
const country_model& cm,
const std::string& country,
3186 const life& a,
const std::vector<union_rec>& unions,
3187 double ref_day,
const core::rng& r)
const
3189 const auto& p = _model.params;
3190 std::vector<child_rec> out;
3191 std::vector<double> anchor_births;
3192 for (std::size_t j = 0; j <
unions.size(); ++j)
3194 const auto& u =
unions[j];
3195 const auto uj = r.split(
"union").split(
static_cast<std::uint64_t
>(j));
3196 const double window_end = std::min(u.end, ref_day);
3197 double mean = (tfr_at_(cm.fertility, 1970.0 + (u.start / year_days_)) + p.union_fertility_offset) *
3199 if (j > 0) mean *= p.later_union_factor;
3200 auto count_rng = uj.split(
"count");
3203 const int n = std::min(family_size_(count_rng, mean * p.adoption_factor),
static_cast<int>(p.max_children));
3204 const double lo = back_(u.start, 2.0);
3205 for (
int i = 0; i < n && window_end > lo; ++i)
3207 auto ci = uj.split(
"adopted").split(
static_cast<std::uint64_t
>(i));
3208 const double birth = lo + core::math::fenced(core::uniform01(ci) * (window_end - lo));
3209 const sex s = core::bernoulli(ci, p.male_birth_share) ? sex::male : sex::female;
3210 auto l = draw_life_(ci.split(
"life"), country, s, birth, 0.0);
3212 out.push_back({.life = l, .union_index =
static_cast<int>(j), .genetic =
false});
3216 const life&
mother = a.s == sex::female ? a : u.partner;
3217 const life&
father = a.s == sex::male ? a : u.partner;
3218 std::vector<double> local_births;
3219 std::vector<double>& births = a.s == sex::female ? anchor_births : local_births;
3220 const int n = std::min(family_size_(count_rng, mean),
static_cast<int>(p.max_children));
3221 for (
auto& c : place_union_births_(cm,
country,
mother,
father, u.start, window_end, 0, n, births, uj))
3223 c.union_index =
static_cast<int>(j);
3234 [[nodiscard]] std::vector<child_rec> place_union_births_(
const country_model& cm,
const std::string& country,
3235 const life& mother,
const life& father,
double from,
3236 double to,
int first,
int last,
3237 std::vector<double>& births,
const core::rng& r)
const
3239 const auto& p = _model.params;
3240 std::vector<child_rec> out;
3241 for (
int i = first; i < last; ++i)
3243 auto ci = r.split(
"child").split(
static_cast<std::uint64_t
>(i));
3244 for (
int attempt = 0; attempt < 24; ++attempt)
3246 const double am = draw_mother_age_(cm.fertility, ci);
3247 const double birth = forward_(
mother.birth, am);
3248 if (birth < from || birth > to || am >=
mother.lifespan)
continue;
3249 const double fa = (birth -
father.birth) / year_days_;
3250 if (fa < p.min_father_age || fa > p.max_father_age || fa - p.conception_lead >=
father.lifespan)
3254 if (std::ranges::any_of(births, [&](
double e)
3255 {
return std::abs(birth - e) < p.birth_spacing * year_days_; }))
3259 births.push_back(birth);
3260 const sex s = core::bernoulli(ci, p.male_birth_share) ? sex::male : sex::female;
3261 auto l = draw_life_(ci.split(
"life"), country, s, birth, 0.0);
3263 out.push_back({.life = l, .genetic =
true});
3264 if (
const auto t = twin_of_(ci, country, l)) out.push_back({.life = *t, .genetic =
true});
3280 void assign_names_(std::vector<person>& people,
const std::vector<raw_member>& raw,
const core::rng& rng,
3281 const std::string& country,
const std::optional<culture>& asked)
const
3283 culture c = culture::any;
3291 std::ranges::transform(lower, lower.begin(),
3292 [](
char ch) { return static_cast<char>(ch >=
'A' && ch <=
'Z' ? ch -
'A' +
'a' : ch); });
3293 c = ng::to_culture(core::from_utf8(lower));
3295 if (c != culture::any)
3301 assign_names_unchecked_(people, raw, rng, c);
3304 catch (
const std::invalid_argument&)
3306 for (
auto& p : people) p.given = p.patronymic = p.family = p.name = {};
3309 for (std::size_t i = 0; i < raw.size(); ++i)
3311 if (!raw[i].fixed)
continue;
3312 const auto& n = *raw[i].fixed;
3313 people[i].given = n.given;
3314 people[i].patronymic = n.patronymic;
3315 people[i].family = n.family;
3316 people[i].name = n.given;
3317 for (
const auto* part : {&n.patronymic, &n.family})
3319 if (!part->empty()) people[i].name +=
" " + *part;
3325 [[nodiscard]]
static std::vector<std::wstring> surnames_of_(
const std::string& family,
const naming_convention& cv)
3327 std::vector<std::wstring> out;
3328 if (family.empty() || !cv.family_name)
return out;
3329 std::vector<std::string> words;
3331 for (
const char ch : family)
3335 if (!word.empty()) words.push_back(std::move(word));
3343 if (!word.empty()) words.push_back(std::move(word));
3344 if (cv.surnames == 2 && words.size() == 2)
3346 for (
const auto& w : words) out.push_back(core::from_utf8(w));
3350 out.push_back(core::from_utf8(family));
3355 void assign_names_unchecked_(std::vector<person>& people,
const std::vector<raw_member>& raw,
const core::rng& rng,
3358 const auto gender_of = [](sex s) {
return s == sex::male ? gender::m : gender::f; };
3359 const auto seed_of = [&](
const std::string& key) {
return rng.split(key).seed(); };
3360 const ng& names = *_from.
name;
3361 const auto cv = names.convention(c);
3362 const auto full = [&](sex s,
const std::string& key)
3363 {
return names.get_full_name({.gender = gender_of(s), .culture = c}, seed_of(key)); };
3364 std::vector<std::optional<name>> nm(raw.size());
3365 std::unordered_map<std::int64_t, name> made_up;
3366 const auto slot = [&](std::int64_t token, sex s) ->
const name&
3368 if (token >= 0 && token < unlisted_)
return *nm.at(
static_cast<std::size_t
>(token));
3369 auto it = made_up.find(token);
3370 if (it == made_up.end()) it = made_up.emplace(token, full(s,
"other." + std::to_string(token))).first;
3376 const auto first_slot = [&](std::int64_t token) ->
const name&
3378 if (token >= 0 && token < unlisted_ && raw.at(
static_cast<std::size_t
>(token)).life.s == sex::female)
3380 const auto key = -token - 2;
3381 auto it = made_up.find(key);
3382 if (it == made_up.end())
3385 .emplace(key, names.get_parent_name(*nm.at(
static_cast<std::size_t
>(token)), gender::m,
3386 seed_of(
"stand-in." + raw.at(
static_cast<std::size_t
>(token)).key)))
3391 return slot(token, sex::male);
3394 for (std::size_t i = 0; i < raw.size(); ++i)
3396 if (!raw[i].fixed)
continue;
3397 const auto& n = *raw[i].fixed;
3398 if (n.given.empty())
throw std::invalid_argument(
"a name needs a given name");
3399 nm[i] = names.compose_name({.gender = gender_of(raw[i].life.s),
3400 .given = core::from_utf8(n.given),
3401 .patronymic = core::from_utf8(n.patronymic),
3402 .family = surnames_of_(n.family, cv)},
3403 c, seed_of(raw[i].key));
3409 const auto f = raw[0].parents[0];
3410 const auto m = raw[0].parents[1];
3411 const bool parents = f >= 0 && f < unlisted_ && m >= 0 && m < unlisted_;
3412 if (parents && (nm[
static_cast<std::size_t
>(f)] || nm[
static_cast<std::size_t
>(m)]))
3414 const auto fi =
static_cast<std::size_t
>(f);
3415 const auto mi =
static_cast<std::size_t
>(m);
3416 if (!nm[fi]) nm[fi] = full(raw[fi].life.s, raw[fi].key);
3417 if (!nm[mi]) nm[mi] = full(raw[mi].life.s, raw[mi].key);
3418 nm[0] = names.get_child_name(*nm[fi], *nm[mi], {.gender = gender_of(raw[0].life.s)}, seed_of(raw[0].key));
3422 nm[0] = full(raw[0].life.s, raw[0].key);
3428 const auto is_child = [](
relation r)
3430 return r == relation::sibling || r == relation::half_sibling || r == relation::child ||
3431 r == relation::grandchild || r == relation::stepchild || r == relation::stepsibling;
3433 std::vector<std::size_t> order;
3434 for (std::size_t i = 1; i < raw.size(); ++i)
3436 if (!is_child(raw[i].role)) order.push_back(i);
3438 for (std::size_t i = 1; i < raw.size(); ++i)
3440 if (is_child(raw[i].role)) order.push_back(i);
3442 for (
const auto i : order)
3444 if (nm[i])
continue;
3445 const auto& m = raw[i];
3448 case relation::anchor:
break;
3449 case relation::father:
3450 case relation::mother:
3451 case relation::paternal_grandfather:
3452 case relation::paternal_grandmother:
3453 case relation::maternal_grandfather:
3454 case relation::maternal_grandmother:
3455 nm[i] = names.get_parent_name(*nm.at(
static_cast<std::size_t
>(m.name_child)), gender_of(m.life.s),
3458 case relation::stepfather:
3459 case relation::stepmother:
3461 nm[i] = full(m.life.s, m.key);
3462 auto married = rng.split(m.key +
".married");
3463 const auto parent =
static_cast<std::size_t
>(m.name_child);
3464 if (raw[parent].life.s == sex::male && m.life.s == sex::female &&
3465 core::bernoulli(married, _model.params.married_name_share))
3467 nm[i] = names.get_married_name(*nm[i], *nm.at(parent));
3471 case relation::partner:
3473 nm[i] = full(m.life.s, m.key);
3474 auto married = rng.split(m.key +
".married");
3475 if (raw[0].life.s == sex::male && m.life.s == sex::female &&
3476 core::bernoulli(married, _model.params.married_name_share))
3478 nm[i] = names.get_married_name(*nm[i], *nm[0]);
3482 case relation::sibling:
3483 case relation::half_sibling:
3484 case relation::child:
3485 case relation::grandchild:
3486 case relation::stepchild:
3487 case relation::stepsibling:
3488 nm[i] = names.get_child_name(first_slot(m.parents[0]), slot(m.parents[1], sex::female),
3489 {.gender = gender_of(m.life.s)}, seed_of(m.key));
3493 for (std::size_t i = 0; i < raw.size(); ++i)
3495 const auto& n = *nm[i];
3496 people[i].given = core::to_utf8(n.given());
3497 people[i].patronymic = core::to_utf8(n.patronymic());
3498 people[i].family = core::to_utf8(n.family());
3499 people[i].name = core::to_utf8(
static_cast<std::wstring
>(n));