Search by

danielpetrica / dochia-cycle-model

danielpetrica

A small, calibrated, on-device statistical model for menstrual-cycle forecasting (PHP reference).

Package info

github.com/danielpetrica/dochia-cycle-model

Language:Python

pkg:composer/danielpetrica/dochia-cycle-model

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-11-04 16:25 UTC

This package is auto-updated.

Last update: 2026-11-04 16:38:06 UTC


README

CI License: MIT Hugging Face Packagist Version DOI

Dochia — a small, calibrated, on-device cycle-forecasting model. Nine arcs represent the nine coats of the Dochia myth.

A small, auditable, on-device statistical model for menstrual-cycle forecasting: a calibrated next-onset distribution, a daily onset hazard, a corrected ovulation-variance identity, and explicit abstention. Reference implementations in PHP, Python, R, Julia and JavaScript; no neural network, no server, no network calls.

Not a medical device. Not contraception. Not a diagnosis. Forecasts are estimates with uncertainty and must not be used for medical decisions.

Repository: danielpetrica/dochia-cycle-model

Why this exists

Most cycle apps show a single date with false precision. This model shows:

  • a range and a probability, not just a day;
  • daily probabilities ("chance today", "chance within 3 days") and a late-period signal;
  • abstention when the history is too variable or incomplete;
  • a corrected ovulation/fertile-window distribution (the common SD(cycle)² + SD(luteal)² error is fixed by subtracting the luteal variance: SD(O)² = SD(CL)² − SD(luteal)²).

It is deliberately tiny: ~50–200 effective parameters, <10 KB of parameters, milliseconds of pure-PHP inference. It exists to make uncertainty honest, not to promise a date.

What it is not

  • Not an LLM or an "AI" model.
  • Not a medical device, contraceptive, fertility diagnostic, or clinical tool.
  • Not validated on the general population. Validation is on a selected charted cohort plus synthetic stress tests; see docs/VALIDATION.md.
  • It does not predict ovulation or phases from wearables. Phase inference (BBT/LH/mucus) is future work.

Quick start (PHP)

git clone https://github.com/danielpetrica/dochia-cycle-model.git
cd dochia-cycle-model

Requirements: PHP >= 8.2, no extensions or Composer dependencies required (Composer optional).

<?php
require 'src/Erf.php';
require 'src/LognormalMixture.php';
require 'src/CalibratedPredictive.php';
require 'src/ModelParams.php';
require 'src/ModelParamsFactory.php';
require 'src/MicroModel.php';

use Dochia\MicroModel;
use Dochia\ModelParamsFactory;

$model = new MicroModel(ModelParamsFactory::literature());
$forecast = $model->forecast([29, 28, 30, 27, 31, 29], currentDay: 12);

echo $forecast['quantiles']['0.5'];   // median cycle length (days)
echo $forecast['hazard']['p_within_3']; // P(onset within 3 days | not yet)
echo $forecast['ovulation']['sd_day'];  // corrected ovulation-day SD

Or install via Packagist:

composer require danielpetrica/dochia-cycle-model

For local development in this repository:

composer dump-autoload

CLI demo:

php bin/forecast.php 29 28 30 27 31 29
php bin/forecast.php --json 29 28 30 27 31 29

Cross-language implementations

The same equations are implemented and parity-tested in five languages:

Language File Runtime
PHP src/ PHP 8.2+
Python python/dochia.py Python 3.11+
R r/dochia.R R 4.x (base)
Julia julia/dochia.jl Julia 1.10+ (stdlib)
JavaScript javascript/dochia.mjs Node 22+

All five agree on the shared 12-case forecast fixture and the synthetic walk-forward accuracy fixture (319 assertions each; MAE 3.8474 d, cov80 83.26%, cov95 93.21%, abstain 34.39% on that synthetic evaluation set). Tolerances and commands: docs/PARITY.md.

python3 python/parity_test.py
php tests/php/parity_test.php
Rscript r/parity_test.R
julia julia/parity_test.jl
node javascript/parity_test.mjs

Quick start (Python reference)

The Python implementation mirrors the PHP reference and is used to generate the golden and parity fixtures. It needs only the standard library.

cd python
python3 - <<'PY'
import dochia as mm
params = mm.ModelParams.from_json('../params/dochia-v1.json')
f = mm.forecast([29, 28, 30, 27, 31, 29], current_day=12, params=params)
print(f['quantiles']['0.5'], f['hazard']['p_within_3'])
PY

How accurate is it?

On a held-out real validation split (283 women / 858 forecasts from the public Creighton cycle-length corpus; even-ID women only), the ship-safe dochia-v1 model:

Metric Result
Average miss of the central guess 2.67 days
Half of guesses within 1.48 days
Guess within 1 / 2 / 3 / 7 days 35% / 62% / 75% / 94%
Nominal 80% interval actually contained the date 82.0%
Nominal 95% interval actually contained the date 94.4%

That is not an accuracy improvement over a standard normal hierarchical model (2.69-day average miss, 76.9%/90.3% coverage); the improvement is that the stated uncertainty is now honest. On deliberately hard synthetic cohorts (PCOS-like, postpartum) the model abstains frequently rather than pretending. Full methods, tables and caveats: docs/VALIDATION.md.

Repository layout

src/                  PHP reference (namespace Dochia)
python/               Python reference, simulation, fixture/params generators
r/                    base-R reference + parity test
julia/                Julia reference + parity test
javascript/           JavaScript (Node) reference + parity test
params/               dochia-v1.json (ship-safe published priors only)
tests/php/            standalone PHP test runner, golden vectors, parity test
tests/fixtures/       golden + cross-language parity/evaluation fixtures
testing/              synthetic test-data generators + 16 tests (stdlib only)
docs/                 model card, validation, parity, test-data, integration
huggingface/          ready-to-push Hugging Face model/dataset cards
research/             optional reproduction scripts for the external validation
bin/forecast.php      PHP CLI
examples/             sample input

No real cycle data is bundled. The research validation scripts fetch the public Creighton corpus directly from its source under its own licence (CC BY-NC 3.0); do not redistribute that data.

Test it

PHP (no PHPUnit required):

php tests/php/run_tests.php
php tests/php/parity_test.php

Python + synthetic data:

python3 python/parity_test.py
cd testing/
python3 build_suites.py
python3 evaluate_suites.py
python3 test_generators.py -v

R / Julia / JavaScript parity:

Rscript r/parity_test.R
julia julia/parity_test.jl
node javascript/parity_test.mjs

Documentation

  • Model card — intended use, factors, metrics, ethical considerations.
  • Validation — data, methods, results, limits.
  • Cross-language parity — five implementations, shared fixtures, tolerances, commands.
  • Test data — synthetic regimes generated from published summary statistics, leakage rules, custom real data.
  • Integration — adding the model to a local-first app.
  • NOTICE — third-party references and data licensing.

Licence

Code: MIT (see LICENSE). Documentation, model card and synthetic test data: CC BY 4.0. No real cycle data is included or redistributed.

Citation

If you use this model or test-data methodology, cite:

Petrica, D. (2026). Dochia: a calibrated on-device statistical model for menstrual-cycle forecasting (v0.1.1). Zenodo. https://doi.org/10.5281/zenodo.23956336

Machine-readable citation: CITATION.cff. Please also cite the primary sources listed in docs/VALIDATION.md and NOTICE.

Contributing

Issues and pull requests are welcome. Please read CONTRIBUTING.md; in particular: no medical/contraceptive claims, no real data without permission, tests before "fixed".

Disclaimer

This is research/educational software. It is not a medical device and must not be used for contraception, diagnosis, or treatment decisions. If a period is late and pregnancy is possible, test; for persistent irregularity or concerning symptoms, consult a qualified clinician.