popfidelity
A language model that answers survey questions can match the average answer of a population and still erase the differences between the people in it. popfidelity measures how well a model's answers represent a human population, group by group. One Rust core gives a Python package, an R package and a command line the same numbers.
What it measures
The Population Fidelity Score (PFS; da Silva et al., 2026) compares the survey and the model on cells, the subpopulations a survey reports, and checks three conditions:
| Component | Question | Score |
|---|---|---|
| Accuracy | Is each cell's answer distribution close to the survey's? | one minus the mean normalised earth mover's distance |
| Adaptability | Do the model's cells differ from one another as much as the survey's do? | min(A, 1/A) of the ratio of median pairwise distances |
| Structure | Do the cells that differ in the survey also differ in the model? | Spearman correlation of the pairwise distances, clipped at zero |
PFS is their geometric mean, so a model fails as soon as one condition fails. It is reported for the pooled population and every demographic subgroup, for paired comparisons of a tuned and a base model, and across replicate runs and questions, with the paper's nine sensitivity specifications.
Beside PFS sits a registry of 126 measures from the literature on synthetic survey samples, each with the work it comes from and the work that applied it to language models; 66 ship in this release:
| Family | In 0.1 | Examples |
|---|---|---|
| Distances | 23 | nEMD, Wasserstein, total variation, Kullback-Leibler, Jensen-Shannon, Hellinger, Kolmogorov-Smirnov, energy distance, MMD |
| Alignment scores | 11 | OpinionQA representativeness, steerability and consistency; GlobalOpinionQA similarity; Meister; SimBench; SubPOP with its noise floor; WorldValuesBench curve |
| PFS and its parts | 10 | components, centre alignment, binding component, variants |
| Dispersion | 8 | SD ratio, normalised variance, gap inflation, entropy and collision ratios, support and modal collapse, stereotyping |
| Reliability | 7 | ICC, Krippendorff's alpha, Fleiss' kappa, Cronbach's alpha, Spearman-Brown, noise-to-signal |
| Structure, inference, artefacts | 7 | Mantel test, quality bands, cell bootstrap, permutation nulls, pooled t intervals, mismatch rate |
The measure catalogue lists all 126, including those planned for later releases, and 17 benchmarks.
Install
pip install popfidelity
remotes::install_github("neemiasbsilva/popfidelity", subdir = "r")
cargo add popfidelity
PyPI has wheels for Linux, macOS and Windows on Python 3.11 and newer, so pip needs
no Rust toolchain there. The R package compiles the Rust core, so it needs Cargo and
rustc 1.85 or newer, as does a Python install from source. The Python extras api
(OpenAI, Anthropic, Google clients), local (transformers) and parquet add
optional backends and formats.
Quickstart
Python:
import popfidelity as pf
from popfidelity.examples import toy
from popfidelity.io import read_cells
cells = toy()
scores = pf.score(cells["survey"], cells["M2"], pf.Variant(round_pairs=10))
print(scores["pfs"], scores["binding_component"])
questions = pf.read_questions("examples/ces/questions.yaml")
survey = read_cells("examples/ces/data/survey_cells.csv", questions)["ideo5"]
results = "examples/ces/results/ollama-qwen3-vl-2b/model_cells.csv"
model = read_cells(results, questions, mode="ntp")["ideo5"]
facets = pf.read_facets("examples/ces/facets.yaml").from_labels(survey.labels)
groups = pf.score_groups(survey, model, facets)
R:
library(popfidelity)
toy <- example_toy()
pfs_score(toy$survey, toy$M2)$pfs
questions <- read_questions("examples/ces/questions.yaml")
survey <- read_cells("examples/ces/data/survey_cells.csv", questions)$ideo5
results <- "examples/ces/results/ollama-qwen3-vl-2b/model_cells.csv"
model <- read_cells(results, questions, mode = "ntp")$ideo5
groups <- pfs_score_groups(survey, model, read_facets("examples/ces/facets.yaml"))
Command line:
popfidelity elicit --config examples/ces/elicit/ollama.yaml --limit 8
popfidelity aggregate records --config examples/ces/elicit/ollama.yaml --out model_cells.csv
popfidelity score --survey examples/ces/data/survey_cells.csv --model model_cells.csv \
--questions examples/ces/questions.yaml --facets examples/ces/facets.yaml --out scores
popfidelity report --groups scores/groups.csv
Asking models
popfidelity elicit interviews a model once per respondent and question, with
the respondent's demographics as prior turns, and stores resumable JSON-lines
records. It reads next-token probabilities over the answer options where the
endpoint returns them and samples full answers otherwise.
| Backend | Endpoints |
|---|---|
openai_compatible |
OpenAI, vLLM, llama.cpp, Hugging Face router and TGI, OpenRouter, Together, Fireworks, DeepSeek, Gemini's OpenAI endpoint, or any compatible URL |
ollama |
Ollama's native API with raw prompts |
anthropic, google |
Claude and Gemini, full answers |
transformers |
a local Hugging Face model, exact next-token probabilities |
Examples
| Example | Survey | Model answers |
|---|---|---|
| toy | the paper's toy cells | models M1 to M3 |
| ces | Cooperative Election Study 2024, 96 cells | qwen3-vl:2b on Ollama, and configurations for six other backends |
| twin2k | Twin-2K-500 wave 4, 24 cells | GPT-4.1-mini digital twins and a human retest ceiling |
| globalopinionqa | GlobalOpinionQA, 90 countries, fetched at run time | qwen3-vl:2b on Ollama, one country per interview |
| machine-bias | World Values Survey cells | the paper's archived and fine-tuned models |
On the CES, the local model is close to every cell on average but does not order the cells as the survey does, so structure binds and PFS stays at 0.30 or below. On Twin-2K-500, people answering the same items again reach PFS 0.95 and the digital twins 0.58 to 0.66.
Reproducibility
- Python and R give the same tables:
./run.sh parityruns both on shared inputs and compares 19 tables at 1e-12. - The library reproduces the paper:
./run.sh crosscheckrecomputes its 9,548 subgroup rows and 5,952 paired rows with differences of at most 4.4e-16. - Bootstrap and permutation draws are seeded one by one, so results do not depend on the number of threads.
- Every reference in
docs/references.bibis checked against Crossref and arXiv byscripts/check_references.py.
Development
uv sync --locked --group dev --extra api --extra parquet
./run.sh test # Rust and Python tests
./run.sh lint # rustfmt, clippy, ruff, mypy strict, style check
./run.sh r # R CMD check --as-cran
./run.sh parity # Python against R
See CONTRIBUTING.md for the conventions.
Citation
TODO - Demo Paper
@misc{dasilva2026population,
author = {da Silva, Neemias B. and Lukk, Martin and Sutani, Ali and Moturu, Abhishek and
Yang, Harris and Silver, Daniel and Ratto, Matt and Silva, Thiago H.},
title = {Population Fidelity: Evaluating Population Representativeness in {LLMs}},
year = {2026},
eprint = {2609.36253},
archivePrefix = {arXiv},
primaryClass = {cs.CL}
}
Please also cite the works behind the other measures you report; the registry names them. The software citation is in CITATION.cff.
Licence
Metadata
Release files for popfidelity 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| popfidelity-0.1.0.tar.gz | 99.8 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| popfidelity-0.1.0-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| popfidelity-0.1.0-cp311-abi3-manylinux_2_28_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ x86-64 | Details |
| popfidelity-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ ARM64 | Details |
| popfidelity-0.1.0-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
| popfidelity-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl | CPython 3.11 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 2.7 MB
Release files / popfidelity-0.1.0.tar.gz
| Download URL | popfidelity-0.1.0.tar.gz |
|---|---|
| Size | 99.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f2ecb55f0d205e63b36ee996c226d3adbb583e6f29ad7db773e7e58cef85da37
|
|
BLAKE2b-256 checksum How to use checksums |
b90f5a861cd444efb5f62b33e935ece7ba85ee24ed49760d0f1c7c27225c7a75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / popfidelity-0.1.0-cp311-abi3-win_amd64.whl
| Download URL | popfidelity-0.1.0-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 424.5 kB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
4f86f932317c399629b268d2c961c86575dd60eb5bff395d2f7e71d37d105372
|
|
BLAKE2b-256 checksum How to use checksums |
ec280de8cc4e7a7602f47890b79b4b6212d0502349ffd7d0905575cf08b59aa1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / popfidelity-0.1.0-cp311-abi3-manylinux_2_28_x86_64.whl
| Download URL | popfidelity-0.1.0-cp311-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 570.9 kB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
5b7e8f4b97d3e4205c89d5d9cf0a67bfe6cde2e4a79ca9254be79ab7ca71e18b
|
|
BLAKE2b-256 checksum How to use checksums |
70bdfa5e0ab47334db219a9b6742deb34bd7283ac0435e8d7ba017eefeaf0771
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / popfidelity-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl
| Download URL | popfidelity-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 567.8 kB |
| Tags | CPython 3.11 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
bfe2c08e1f80a749ab8d0c8974480c6edee09b6d3bb85d96489ff82d3887b847
|
|
BLAKE2b-256 checksum How to use checksums |
370059fc936754ecf4aae6af6f85d9be9008f745f5a229a79b884452461032af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / popfidelity-0.1.0-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | popfidelity-0.1.0-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 509.0 kB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
73bc125fc76fdf43efea334c50a4def0153c4749124e707223808b511093db67
|
|
BLAKE2b-256 checksum How to use checksums |
4e5ce1dabd695a22ee3b21bc8ec5e73e7ad21baf76dc8e49316ec54d9808a4aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / popfidelity-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl
| Download URL | popfidelity-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 520.2 kB |
| Tags | CPython 3.11 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
2346a9f31e7fde427ffa3b12f0b331225576f872cfa20b68439891aa73de0313
|
|
BLAKE2b-256 checksum How to use checksums |
8e860e24d20d86317768994cc77632c0061f2d2bbdef4ec47242d8f897fcfa56
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log