|
Relationship Generator 1.2.2
Believable families around a person: parents, siblings, partners and children, with ages and names for C++23
|
Where the data in resources/ comes from, how it is built, and what the model leaves out (rule 6 of the dasmig standard).
The tables below drive the whole family: the anchor, parents, grandparents, siblings and half-siblings, partners, stepchildren, children and grandchildren, and on request stepparents and stepsiblings. households.tsv sets who the anchor lives with, when a request asks for it (family_request::home).
| Tier | Countries in the tables | Notes |
|---|---|---|
lite | 193 independent states with fertility (192 in unions, 170 in households), 194 in regions | Vatican City has no data in any source |
full | 235 countries and territories with fertility (229 in unions, 188 in households), 249 in regions | The territories with UN estimates |
A country missing from a table, or with an empty cell, falls back to the defaults.tsv row of its UN subregion, and the result says so. The two tiers share one defaults.tsv built from all countries, so a fallback is the same in both.
All three sources are United Nations Population Division data made available under CC BY 3.0 IGO.
| File | Columns | Source |
|---|---|---|
regions.tsv | subregion | The UN subregion of each country: REST Countries v3.1. It says which row of defaults.tsv a country falls back to |
fertility.tsv | tfr | Total fertility rate, 2023: UN World Population Prospects 2024 (via the PPgp/wpp2024 R package data, tfr.txt) |
pasfr_10_14 … pasfr_45_49 | Percentage of fertility by five-year age group of the mother, 2023: WPP 2024 (percentASFR5.txt), renormalised to sum to exactly 100 | |
tfr_1950 … tfr_2020 | The same rate for each fifth year since 1950 (tfr.txt), to size the family of an older person | |
mac | Mean age at childbearing: computed from the pasfr columns, using the middle of each age group | |
unions.tsv | smam_m, smam_f | Singulate mean age at marriage by sex, latest series: UN World Marriage Data 2019 (SMAM) |
never_m_45_49, never_f_45_49 | 100 minus the percentage ever married at age 45 to 49, latest series (EVER_MARRIED) | |
divorced_m_45_49, divorced_f_45_49 | Percentage of all men or women aged 45 to 49 who are divorced or separated, latest series that reports divorce (MARITAL_STATUS_BY_AGE): Divorced plus Separated, or the joined category where a source has only that | |
year | Last year of the women's SMAM series | |
households.tsv | size | Average household size (number of members) |
one_person, single_parent, multi_generation | Percentage of households that are one-person, single parent with children, and multi-generation | |
year, source | Reference year and survey family (DHS, MICS, IPUMS, DYB, LFS or other) of the row used | |
| UN Database on Household Size and Composition 2026 (UN DESA/POP/2026/DC/NO.15): the survey with the most of these indicators filled in, then the latest | ||
defaults.tsv | every numeric column above | Median over the countries of a UN subregion (the REST Countries subregion), with World as the median over all countries; countries is how many countries it covers. Derived, not curated |
parameters.tsv | key, value, note | The model's constants, all curated (see the Generation Model); the file is layered like the others and an unknown key is an error |
| Country metadata | REST Countries v3.1: ISO codes, M49 numbers, subregion and independence |
scripts/prepare_demography.py downloads the sources (cached in scripts/.cache, which is not committed) and writes both tiers:
The report lists the values outside a plausible range (for example tfr outside 0.7 to 8, or a mean age at childbearing outside 22 to 34) and the independent states that fall back to a default. After changing the data, run make embed and update the known-answer tests (the data hash and results change).
get_family(request, seed) draws a family around an anchor. Each part comes from a stream split from the call seed by name, so asking for grandparents or for no siblings does not change the rest.
birth-generator for the country, with its age pyramid and population weights, and the date ages are counted at (1 July 2023 unless the request says otherwise).pasfr (the share of the country's births each group has), uniform inside the group, and inside the fertile years (12 to 49.9).smam_m - smam_f, between 0 and 8 years), with a standard deviation of 3.5 years and a floor of 15.m, the total fertility rate of the anchor's birth year (interpolated between the five-year figures). Seen from a child, a family is size-biased: a family of n children is n times as likely to be the anchor's, so the siblings are a size-biased family size minus one. How much families differ in size grows with fertility, as the variance over the mean d = 0.2 + 0.27 m (not below 0.3): below 0.9, a binomial family size; near 1, Poisson; above 1.05, a negative binomial (a Poisson whose mean is gamma-distributed). Each sibling is then placed by the mother's age at the birth and left out if no age fits in twelve tries: before she was 12 or after 49.9, after she died, after the father died (he must be alive nine months before a birth), after the reference date, or less than nine months from another of her births. A birth is male with probability 0.512.0.012 exp((80 - e0) / 11), where e0 is the country's life expectancy at birth for the sex (from birth-generator), and a child who dies does so early. Adulthood: from 15, a Gompertz curve (exp(-c (exp(beta x) - 1)), beta = 0.09) whose mean age at death is 26 + 0.7 e0, a line through the Coale-Demeny west model life tables (61 at e0 50, 82 at e0 80). Fitting the curve to e0 itself puts adult deaths far too early where child deaths are common: a 25-year-old Nigerian had a living father 37% of the time, against 62% now. The dead have a date of death before the reference date.parent_of edges.stepchild_factor (0.6); one child plus a Poisson number with mean 0.5, each born at least nine months before the union began. They are linked to the partner only (parent_of), and to the anchor's children by the partner as half-siblings. They are drawn for the anchor's partners only when partners and children are asked for.twin_share (0.012): another child of the same parents on the same day, with a sex and life of its own. The anchor has a twin with twice that probability (a person is twice as likely to be one of a pair as a delivery is to be a twin delivery). A member born the same day as a full sibling has twin set.stepparents = true). Each parent has a new partner while the anchor is a child with the chance stepparent_factor (1) times the parent's divorced share among the ever married times remarry_share (0.45), for example about 5% for Brazilian men and 9% for American. The union begins a year plus an exponential spell (mean stepparent_start_mean, 6 years) after the last child the parents had together (the anchor or a younger full sibling, drawn for this even when siblings are not asked for), while the parent is alive and at least 16 and the anchor is under 18. The partner is drawn like the anchor's own (the other sex unless same_sex_share, the usual marriage-age gap, a life that is alive at the start); the union ends by separation (the divorced share, after half a year plus an exponential spell with mean 9) or at the first death. Stepparents take the last member ids and are named like partners (a stepmother may take the father's family name). With siblings asked for, a union of a man and a woman has children: the parent's half-siblings already drawn who were born during the union (the stepmother between 12 and 49.9 and nine months from her other births, the stepfather 15 to 80 and alive at the conception) become the stepparent's, and more are placed like the anchor's union children (the fertility rate of the year the union began plus 0.2, times later_union_factor, 0.6) up to that number. About half of the American and German stepparents of people aged 40 have a child with the parent, as surveys of remarriages find. The stepparent's own children by an earlier union (stepsiblings) are drawn like a partner's stepchildren (stepchild_factor). These children take ids after the stepparents; a half-sibling who becomes a stepparent's child keeps its id and birth and is named after both parents.home = true), after everything else, from a stream of its own; see the usage guide. A child lives with a living parent: a parent with an ongoing stepparent lives with that partner (and the stepparent's own children under 18, by mother_custody_share for a stepmother or its complement for a stepfather), two living parents live together unless a draw with the single-parent share of households makes it one (the mother with mother_custody_share, 0.8), and a grandparent joins by the multi-generation share. An adult lives with an ongoing partner and the children under 18 of that union, or of the partner's, and keeps the children of an ended union by mother_custody_share; otherwise an adult under 30 lives with parents with chance young_adult_home_share (0.5), and others alone with the one-person share times one_person_scale (3, because a share of households is not a share of people) or with people the family does not hold.name-generator, by the culture of the anchor's country (or name_culture): the anchor is drawn or given, a parent is named after the child (get_parent_name), a sibling, child, stepchild, stepsibling or grandchild after both parents (get_child_name, with a made-up other parent where one is not a member), a partner is drawn and a wife may take the anchor's name (probability 0.8; get_married_name). Where a given anchor has parents with names and the anchor has none, the anchor is named after them. In a same-sex union of two women the first parent holds the father's place, so a man of her family stands in for the convention (a masculine surname, a patronymic). A country whose culture has no lists in the loaded tier of name-generator gets no names, but for the ones given.Known relatives and expansion. anchor_spec can hold the anchor's name, father, mother, siblings and unions as plain values. A relative that is given is used as it is (a parent's date of birth fixes the anchor's gap to the parent; the other parent and the siblings are drawn around it), and a list that is given (siblings, unions) is the whole list, so no one else is drawn for it. relg::expand(family, member, request, seed) builds this from a family: the member becomes the anchor and keeps the parents, grandparents, siblings, partners, stepchildren and children the family lists, so the two agree.
Every family keeps these rules, which the property tests check on tens of thousands of families: a mother is 12 to 50 at each birth and a father at least 15; no child is born after its mother's death or later than nine months after its father's; a mother's births are at least nine months apart; nobody is born after the reference date or dies after it; siblings are numbered oldest first.
The constants are in parameters.tsv. The ages, birth_spacing, conception_lead, the mortality lines and the dispersion line are curated (rule 6), and the file's note column says what each is.
pasfr) and life expectancy are today's: a 70-year-old's mother is given today's age at childbearing, and the parents' survival comes from today's life expectancy, which makes parents of older people in countries that were poor then live too long. Life expectancy by year is in WPP (e0B.txt) and could replace the second.one_person_scale, young_adult_home_share); the three-generation share is empty in many sources, and Western Europe and Australia and New Zealand, where no country has it, are curated at 5% and 6% (scripts/prepare_demography.py), so a person there is not given the world's third.partners = false or down = 0 has none to keep, and they are drawn again). A partner whom a family left out is not recreated, but the children of the union are kept. A union's dates are known to the year, so the start and end of a kept union are the middle of that year.year says which). SMAM is a stock-based estimate of the mean age at first marriage, not a count of weddings.World.parameters.tsv.