tinto 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. tinto-0.1.0/.github/README.md +115 -0
  2. tinto-0.1.0/.gitignore +137 -0
  3. tinto-0.1.0/AUTHORS.md +9 -0
  4. tinto-0.1.0/CONTRIBUTING.md +101 -0
  5. tinto-0.1.0/HISTORY.md +100 -0
  6. tinto-0.1.0/PKG-INFO +130 -0
  7. tinto-0.1.0/citation.cff +17 -0
  8. tinto-0.1.0/conftest.py +20 -0
  9. tinto-0.1.0/docs/_static/logo.svg +20 -0
  10. tinto-0.1.0/docs/companion/exact_stabilization_time.ipynb +1678 -0
  11. tinto-0.1.0/docs/companion/index.md +17 -0
  12. tinto-0.1.0/docs/conf.py +215 -0
  13. tinto-0.1.0/docs/index.md +18 -0
  14. tinto-0.1.0/docs/presentation/authors.md +2 -0
  15. tinto-0.1.0/docs/presentation/contributing.md +2 -0
  16. tinto-0.1.0/docs/presentation/history.md +2 -0
  17. tinto-0.1.0/docs/presentation/index.md +10 -0
  18. tinto-0.1.0/docs/presentation/installation.md +48 -0
  19. tinto-0.1.0/docs/presentation/readme.md +5 -0
  20. tinto-0.1.0/docs/reference/campaigns.md +15 -0
  21. tinto-0.1.0/docs/reference/configs.md +15 -0
  22. tinto-0.1.0/docs/reference/dynamics.md +23 -0
  23. tinto-0.1.0/docs/reference/estimate.md +8 -0
  24. tinto-0.1.0/docs/reference/exact.md +8 -0
  25. tinto-0.1.0/docs/reference/experiments.md +9 -0
  26. tinto-0.1.0/docs/reference/graphs.md +9 -0
  27. tinto-0.1.0/docs/reference/guards.md +9 -0
  28. tinto-0.1.0/docs/reference/index.md +13 -0
  29. tinto-0.1.0/docs/reference/io.md +9 -0
  30. tinto-0.1.0/docs/reference/oracle.md +8 -0
  31. tinto-0.1.0/docs/reference/runners.md +9 -0
  32. tinto-0.1.0/docs/reference/schedulers.md +9 -0
  33. tinto-0.1.0/docs/reference/solvers.md +9 -0
  34. tinto-0.1.0/docs/reference/starters.md +18 -0
  35. tinto-0.1.0/docs/reference/theory/bipartite.md +6 -0
  36. tinto-0.1.0/docs/reference/theory/cayley.md +6 -0
  37. tinto-0.1.0/docs/reference/theory/erdos_renyi.md +6 -0
  38. tinto-0.1.0/docs/reference/theory/general.md +6 -0
  39. tinto-0.1.0/docs/reference/theory/path_cycle.md +6 -0
  40. tinto-0.1.0/docs/reference/theory/star.md +6 -0
  41. tinto-0.1.0/docs/reference/theory.md +16 -0
  42. tinto-0.1.0/docs/tutorials/basics.ipynb +489 -0
  43. tinto-0.1.0/docs/tutorials/index.md +6 -0
  44. tinto-0.1.0/docs/tutorials/introduction.ipynb +2224 -0
  45. tinto-0.1.0/pyproject.toml +80 -0
  46. tinto-0.1.0/tests/__init__.py +1 -0
  47. tinto-0.1.0/tests/test_exact.py +80 -0
  48. tinto-0.1.0/tests/test_independence.py +57 -0
  49. tinto-0.1.0/tests/test_oracle.py +189 -0
  50. tinto-0.1.0/tests/test_theory.py +201 -0
  51. tinto-0.1.0/tests/test_tinto.py +470 -0
  52. tinto-0.1.0/tinto/__init__.py +12 -0
  53. tinto-0.1.0/tinto/configs.py +431 -0
  54. tinto-0.1.0/tinto/estimate.py +804 -0
  55. tinto-0.1.0/tinto/exact.py +311 -0
  56. tinto-0.1.0/tinto/experiments.py +1132 -0
  57. tinto-0.1.0/tinto/graphs.py +604 -0
  58. tinto-0.1.0/tinto/guards.py +276 -0
  59. tinto-0.1.0/tinto/io.py +52 -0
  60. tinto-0.1.0/tinto/oracle.py +295 -0
  61. tinto-0.1.0/tinto/runners.py +239 -0
  62. tinto-0.1.0/tinto/schedulers.py +516 -0
  63. tinto-0.1.0/tinto/solvers.py +414 -0
  64. tinto-0.1.0/tinto/starters.py +460 -0
  65. tinto-0.1.0/tinto/theory/__init__.py +28 -0
  66. tinto-0.1.0/tinto/theory/_egf.py +111 -0
  67. tinto-0.1.0/tinto/theory/bipartite.py +182 -0
  68. tinto-0.1.0/tinto/theory/cayley.py +319 -0
  69. tinto-0.1.0/tinto/theory/erdos_renyi.py +203 -0
  70. tinto-0.1.0/tinto/theory/general.py +374 -0
  71. tinto-0.1.0/tinto/theory/path_cycle.py +282 -0
  72. tinto-0.1.0/tinto/theory/star.py +88 -0
@@ -0,0 +1,115 @@
1
+ # <img src="../docs/_static/logo.svg" alt="Tinto logo" width="48" valign="middle" /> Tinto
2
+
3
+
4
+ [![PyPI Status](https://img.shields.io/pypi/v/tinto.svg)](https://pypi.python.org/pypi/tinto)
5
+ [![Build Status](https://github.com/balouf/tinto/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/balouf/tinto/actions?query=workflow%3Abuild)
6
+ [![Documentation Status](https://github.com/balouf/tinto/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/balouf/tinto/actions?query=workflow%3Adocs)
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![Code Coverage](https://codecov.io/gh/balouf/tinto/branch/main/graphs/badge.svg)](https://codecov.io/gh/balouf/tinto/tree/main)
9
+
10
+ How long does a self-stabilizing graph coloring take to settle? Tinto measures it with a Numba-compiled Monte Carlo over pluggable graphs, guards, schedulers and recoloring rules, down to the variance and skewness of the stabilization time. For the conflict-guard rule under the random central daemon, it also provides exact results.
11
+
12
+
13
+ - Free software: MIT
14
+ - Documentation: <https://balouf.github.io/tinto/>.
15
+ - Github: <https://github.com/balouf/tinto>
16
+
17
+
18
+ ## Features
19
+
20
+ - Numba-compiled dynamics: CSR graphs (line, ring, uniform labeled tree,
21
+ Erdős-Rényi `G(n, p)`, bipartite `G(n1, n2, p)`), pluggable guards,
22
+ four schedulers (shuffled, ordered, Bernoulli, independent) and five
23
+ colorers (lowest, next or uniform free color, plus two blind variants
24
+ that may leave clashes behind).
25
+ - Monte-Carlo driver aggregating mean, variance and third central moment
26
+ of both the number of steps and the number of activations before
27
+ stabilization, on a fixed graph or on a fresh random graph per replica.
28
+ - `Experiment` high-level API with cartesian-product sweeps, campaign
29
+ addition, light matplotlib plotting, CSV export, and fits of the
30
+ results (weighted least squares, test for a hidden term, recovery of
31
+ exact fractions).
32
+ - Exact stabilization time of the conflict-guard rule under the random
33
+ central daemon, from three independent sources: the peak oracle, which
34
+ samples it without running the dynamics (`tinto.oracle`), exact
35
+ enumeration on small graphs (`tinto.exact`) and closed forms
36
+ (`tinto.theory`).
37
+ - Companion notebooks that check the numerical statements of the papers.
38
+ - 100% branch-covered by doctest-based examples.
39
+
40
+ ## Quickstart
41
+
42
+ Install Tinto:
43
+
44
+ ```console
45
+ $ pip install tinto
46
+ ```
47
+
48
+ ### Low-level API
49
+
50
+ Drive one trajectory on a line graph:
51
+
52
+ ```pycon
53
+ >>> from tinto import graphs, configs, schedulers, solvers, runners
54
+ >>> from tinto.io import set_seed
55
+ >>> set_seed(0)
56
+ >>> Config = configs.make()
57
+ >>> c = Config(graphs.line(20))
58
+ >>> sched = schedulers.shuffled()(c)
59
+ >>> solver = solvers.make()
60
+ >>> steps, activations = runners.simple(c, sched, solver)
61
+ >>> steps > 0
62
+ True
63
+ >>> c.total
64
+ 0
65
+ ```
66
+
67
+ Or Monte-Carlo the moments of both metrics over many replicas:
68
+
69
+ ```pycon
70
+ >>> from tinto import starters
71
+ >>> set_seed(0)
72
+ >>> starter = starters.from_graph(Config)(graphs.line(20))
73
+ >>> res = runners.mc(starter, schedulers.shuffled(), solver, n_trials=20)
74
+ >>> mean, var, m3 = res["steps"]
75
+ >>> mean > 0
76
+ True
77
+ ```
78
+
79
+ ### High-level API
80
+
81
+ The `Experiment` class bundles a sweep + the Monte-Carlo runner + plot
82
+ and export helpers. Define an `Iterator` over one parameter, wrap it in
83
+ an `Experiment`, run:
84
+
85
+ ```pycon
86
+ >>> from tinto import Experiment, Iterator
87
+ >>> def build_starter(n):
88
+ ... return starters.from_graph(Config)(graphs.line(n))
89
+ >>> n_iter = Iterator("starter", [10, 20, 50], name="n", process=build_starter)
90
+ >>> exp = Experiment(
91
+ ... "line-sweep",
92
+ ... iterator=n_iter,
93
+ ... scheduler=schedulers.shuffled(),
94
+ ... solver=solver,
95
+ ... n_trials=50,
96
+ ... )
97
+ >>> _ = exp.run(progress=False)
98
+ >>> exp.results["line-sweep"]["axes"]
99
+ ('starter',)
100
+ ```
101
+
102
+ Compose cartesian products with `*` and combine multiple campaigns with
103
+ `+`:
104
+
105
+ ```pycon
106
+ >>> kind_iter = Iterator("starter", ["random", "mono"], name="kind")
107
+ >>> # plot or export via exp.plot(x="n", hue="kind") / exp.to_csv(...)
108
+ ```
109
+
110
+ ## Credits
111
+
112
+ This package was created with [Cookiecutter][CC] and the [Package Helper 3][PH3] project template.
113
+
114
+ [CC]: <https://github.com/audreyr/cookiecutter>
115
+ [PH3]: <https://balouf.github.io/package-helper-3/>
tinto-0.1.0/.gitignore ADDED
@@ -0,0 +1,137 @@
1
+ # build outputs
2
+ *.pdf
3
+
4
+ # python
5
+ __pycache__/
6
+ *.pyc
7
+ .ipynb_checkpoints/
8
+
9
+ # editors and OS
10
+ .DS_Store
11
+ Thumbs.db
12
+
13
+ # ---- Python package (from the tinto repository) ----
14
+ # Byte-compiled / optimized / DLL files
15
+ __pycache__/
16
+ *.py[cod]
17
+ *$py.class
18
+
19
+ # C extensions
20
+ *.so
21
+
22
+ # Distribution / packaging
23
+ .Python
24
+ env/
25
+ build/
26
+ develop-eggs/
27
+ dist/
28
+ downloads/
29
+ eggs/
30
+ .eggs/
31
+ lib/
32
+ lib64/
33
+ parts/
34
+ sdist/
35
+ var/
36
+ wheels/
37
+ *.egg-info/
38
+ .installed.cfg
39
+ *.egg
40
+
41
+ # PyInstaller
42
+ # Usually these files are written by a python script from a template
43
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
44
+ *.manifest
45
+ *.spec
46
+
47
+ # Installer logs
48
+ pip-log.txt
49
+ pip-delete-this-directory.txt
50
+
51
+ # Unit test / coverage reports
52
+ htmlcov/
53
+ .tox/
54
+ .coverage
55
+ .coverage.*
56
+ .cache
57
+ nosetests.xml
58
+ coverage.xml
59
+ *.cover
60
+ .hypothesis/
61
+ .pytest_cache/
62
+
63
+ # Translations
64
+ *.mo
65
+ *.pot
66
+
67
+ # Django stuff:
68
+ *.log
69
+ local_settings.py
70
+
71
+ # Flask stuff:
72
+ instance/
73
+ .webassets-cache
74
+
75
+ # Scrapy stuff:
76
+ .scrapy
77
+
78
+ # Sphinx documentation
79
+ docs/_build/
80
+
81
+ # PyBuilder
82
+ target/
83
+
84
+ # Jupyter Notebook
85
+ .ipynb_checkpoints
86
+
87
+ # pyenv
88
+ .python-version
89
+
90
+ # celery beat schedule file
91
+ celerybeat-schedule
92
+
93
+ # SageMath parsed files
94
+ *.sage.py
95
+
96
+ # dotenv
97
+ .env
98
+
99
+ # virtualenv
100
+ .venv
101
+ venv/
102
+ ENV/
103
+
104
+ # Spyder project settings
105
+ .spyderproject
106
+ .spyproject
107
+
108
+ # Rope project settings
109
+ .ropeproject
110
+
111
+ # mkdocs documentation
112
+ /site
113
+
114
+ # mypy
115
+ .mypy_cache/
116
+
117
+ # ruff
118
+ .ruff_cache/
119
+
120
+ # Coverage HTML output
121
+ cov/
122
+
123
+ # IDE settings
124
+ .vscode/
125
+
126
+ # PyCharm project settings
127
+ .idea
128
+ .claude
129
+
130
+ # Local experiments
131
+ sandbox/
132
+
133
+ # Notebook / doctest artifacts
134
+ schedulers.csv
135
+
136
+ # Work clones of tools/publish.py
137
+ .publish/
tinto-0.1.0/AUTHORS.md ADDED
@@ -0,0 +1,9 @@
1
+ # Credits
2
+
3
+ ## Development Lead
4
+
5
+ - Fabien Mathieu <fabien.mathieu@normalesup.org>
6
+
7
+ ## Contributors
8
+
9
+ None yet. Why not be the first?
@@ -0,0 +1,101 @@
1
+ # Contributing
2
+
3
+ Contributions are welcome, and they are greatly appreciated! Every little bit
4
+ helps, and credit will always be given.
5
+
6
+ You can contribute in many ways:
7
+
8
+ ## Types of Contributions
9
+
10
+ ### Report Bugs
11
+
12
+ Report bugs at https://github.com/balouf/tinto/issues.
13
+
14
+ If you are reporting a bug, please include:
15
+
16
+ - Your operating system name and version.
17
+ - Any details about your local setup that might be helpful in troubleshooting.
18
+ - Detailed steps to reproduce the bug.
19
+
20
+ ### Fix Bugs
21
+
22
+ Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
23
+ wanted" is open to whoever wants to implement it.
24
+
25
+ ### Implement Features
26
+
27
+ Look through the GitHub issues for features. Anything tagged with "enhancement"
28
+ and "help wanted" is open to whoever wants to implement it.
29
+
30
+ ### Write Documentation
31
+
32
+ Tinto could always use more documentation, whether as part of the
33
+ official Tinto docs, in docstrings, or even on the web in blog posts,
34
+ articles, and such.
35
+
36
+ ### Submit Feedback
37
+
38
+ The best way to send feedback is to file an issue at https://github.com/balouf/tinto/issues.
39
+
40
+ If you are proposing a feature:
41
+
42
+ - Explain in detail how it would work.
43
+ - Keep the scope as narrow as possible, to make it easier to implement.
44
+ - Remember that this is a volunteer-driven project, and that contributions
45
+ are welcome :)
46
+
47
+ ## Get Started!
48
+
49
+ Ready to contribute? Here's how to set up `tinto` for local development.
50
+
51
+ 1. Fork the `tinto` repo on GitHub.
52
+
53
+ 2. Clone your fork locally::
54
+ ```console
55
+ $ git clone git@github.com:your_name_here/tinto.git
56
+ ```
57
+
58
+ 3. Install your local copy into a virtualenv. Assuming you have uv installed, this is how you set up your fork for local development:
59
+ ```console
60
+ $ cd tinto/
61
+ $ uv sync --all-extras
62
+ ```
63
+
64
+ 4. Create a branch for local development::
65
+ ```console
66
+ $ git checkout -b name-of-your-bugfix-or-feature
67
+ ```
68
+ Now you can make your changes locally.
69
+
70
+ 5. When you're done making changes, check that your changes pass the
71
+ tests:
72
+ ```console
73
+ $ uv run pytest
74
+ ```
75
+
76
+ 6. Commit your changes and push your branch to GitHub::
77
+ ```bash
78
+ $ git add .
79
+ $ git commit -m "Your detailed description of your changes."
80
+ $ git push origin name-of-your-bugfix-or-feature
81
+ ```
82
+
83
+ 7. Submit a pull request through the GitHub website.
84
+
85
+ ## Pull Request Guidelines
86
+
87
+ Before you submit a pull request, check that it meets these guidelines:
88
+
89
+ 1. The pull request should include tests.
90
+ 2. If the pull request adds functionality, the docs should be updated. Put
91
+ your new functionality into a function with a docstring, and add the
92
+ feature to the list in `.github/README.md` or `HISTORY.md`.
93
+ 3. The pull request should work for Python for the versions supported by the package (ideally, the three latest minor CPython versions).
94
+ Make sure that the tests pass for all supported Python versions.
95
+
96
+ ## Tips
97
+
98
+ To run a subset of tests:
99
+ ```bash
100
+ $ uv run pytest tests.test_tinto
101
+ ```
tinto-0.1.0/HISTORY.md ADDED
@@ -0,0 +1,100 @@
1
+ # History
2
+
3
+ ## 0.1.0 (2026-11-11): First release
4
+
5
+ - First release on PyPI.
6
+
7
+ ### Coloring dynamics
8
+
9
+ - `graphs`: a Numba-compiled CSR graph, the `line` and `ring` builders,
10
+ and three random generators, each with its edge-list variant: uniform
11
+ labeled tree (`cayley`), Erdős-Rényi `G(n, p)` drawn by geometric
12
+ skipping in O(n + m) (`erdos_renyi`), and bipartite `G(n1, n2, p)`
13
+ (`bipartite`). Graphs are also built from an edge list
14
+ (`edges_to_graph`) or an adjacency matrix (`adja_to_graph`).
15
+ - `guards`: four enabling rules, from the default `color_clash` (a node
16
+ shares its color with a neighbor) to `color_clash_tie`, `color_min`
17
+ and `color_min_tie`.
18
+ - `configs.make`: the coloring configuration, which keeps the set of
19
+ enabled nodes in sync with the colors. Initial colorings may use fewer
20
+ colors than the palette (`Config.color_randomize(k_init)`); without an
21
+ explicit palette, it has `max(k_init, Delta + 1)` colors.
22
+ - `starters`: initial configurations, either on a fixed graph
23
+ (`from_graph`, uniform or random coloring) or on a fresh random graph
24
+ per draw (`from_cayley`, `from_erdos_renyi`, `from_bipartite`); every
25
+ starter takes a palette size `k` and a number of initial colors
26
+ `k_init`.
27
+ - `schedulers`: `shuffled`, `ordered`, `bernoulli` and `independent`.
28
+ - `solvers.make`, with five colorers: `colorer_lowest`, `colorer_next`
29
+ and `colorer_random` pick a free color (smallest, next, uniform);
30
+ `colorer_random_blind` and `colorer_next_blind` skip the neighborhood
31
+ scan and may leave clashes behind, modelling agents that detect a
32
+ conflict locally without seeing which colors are free.
33
+ - `runners`: `simple` runs one trajectory and returns its numbers of
34
+ steps and activations (recolorings); `mc` runs replicas in parallel
35
+ and returns the mean, variance and third central moment of both.
36
+ - The factories are memoized: two calls with the same arguments return
37
+ the same compiled object, so parameter sweeps compile each variant
38
+ once.
39
+ - `io.set_seed` seeds every random generator, Numba's included.
40
+
41
+ ### Experiments and estimation
42
+
43
+ - `tinto.Experiment`, `tinto.Iterator` and `tinto.ProductIterator`:
44
+ parameter sweeps (cartesian products with `*`, campaigns merged with
45
+ `+`), with `.run()`, `.plot()`, `.fit()`, `.fit_fractions()`,
46
+ `.report()`, `.residuals()`, `.to_dict()` and `.to_csv()`.
47
+ - `estimate`: weighted least squares on a linear basis (`wls`, `fit`),
48
+ a likelihood-ratio test for a hidden term (`test_extra_term`), and the
49
+ recovery of exact fractions from fitted coefficients (`simplest_in`,
50
+ `recover`, `fit_fractions`, `fractions_table`).
51
+
52
+ ### Exact stabilization time
53
+
54
+ Three independent sources for the stabilization time of the
55
+ conflict-guard rule under the random central daemon:
56
+
57
+ - `oracle`, the peak oracle: by the reduction lemma, `T = n - S` with `S`
58
+ the number of peaks of a uniform labeling, so `T` is sampled without
59
+ running the dynamics. `count_peaks`, and parallel samplers on a fixed
60
+ graph (`sample_graph`) or on a fresh random graph per trial
61
+ (`sample_erdos_renyi`, `sample_bipartite`, `sample_cayley`); the
62
+ samples depend on the seed only, not on the number of threads.
63
+ - `exact`: the exact law of the peak count on small graphs, by
64
+ enumeration of all labelings and colorings (`peaks_distribution`,
65
+ colorings up to a permutation of the colors, optional split on whether
66
+ two nodes share their color, optional fixed labeling), its factorial
67
+ moments, and the enumeration of all labeled trees and all graphs on
68
+ `n` nodes.
69
+ - `theory`: closed forms, one submodule per family:
70
+ - `general`: exact mean and variance on any graph (Theorems 1 and 3)
71
+ in rational arithmetic, the mean from a fixed initial coloring, and
72
+ a compiled floating-point monochrome variance for loops over
73
+ millions of graphs;
74
+ - `path_cycle`: generating functions in exact integers, exact laws and
75
+ closed forms;
76
+ - `erdos_renyi`: exact moments and fixed-`p` limit law;
77
+ - `bipartite`: monochrome law and limit mean;
78
+ - `cayley`: pair-degree laws, asymptotic variance slope and the
79
+ generating function of the law on the uniform labeled tree;
80
+ - `star`: law, mean and variance of the star, the graph of largest
81
+ variance.
82
+
83
+ `theory` imports nothing from the simulation side, nor from `exact`;
84
+ `tests/test_independence.py` enforces it.
85
+
86
+ ### Documentation
87
+
88
+ - Numpydoc docstrings with doctests on every public module, class and
89
+ function; 100% branch coverage under `NUMBA_DISABLE_JIT=1`.
90
+ - Sphinx reference pages for every module.
91
+ - Two tutorials: `introduction`, a tour of the modules with a
92
+ `verbose_run` helper that walks one step at a time through the
93
+ dynamics, and `basics`, a first set of experiments.
94
+ - Companion notebooks, starting with
95
+ `docs/companion/exact_stabilization_time.ipynb`: the numerical
96
+ statements of the exact stabilization-time report, each checked by
97
+ confronting closed forms, exact enumeration and Monte Carlo (sympy is
98
+ in the `dev` group for its symbolic sections). Notebooks that assert
99
+ checks are stored without outputs; the docs workflow executes them
100
+ before building, so a failing check fails the build.
tinto-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.5
2
+ Name: tinto
3
+ Version: 0.1.0
4
+ Summary: How long does a self-stabilizing graph coloring take to settle? Tinto measures it with a Numba-compiled Monte Carlo over pluggable graphs, guards, schedulers and recoloring rules, down to the variance and skewness of the stabilization time. For the conflict-guard rule under the random central daemon, it also provides exact results.
5
+ Project-URL: Repository, https://github.com/balouf/tinto
6
+ Project-URL: Documentation, https://balouf.github.io/tinto
7
+ Author-email: Fabien Mathieu <fabien.mathieu@normalesup.org>
8
+ Maintainer-email: Fabien Mathieu <fabien.mathieu@normalesup.org>
9
+ License-Expression: MIT
10
+ License-File: AUTHORS.md
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: numba>=0.65.0
13
+ Requires-Dist: scipy>=1.15.3
14
+ Description-Content-Type: text/markdown
15
+
16
+ # <img src="../docs/_static/logo.svg" alt="Tinto logo" width="48" valign="middle" /> Tinto
17
+
18
+
19
+ [![PyPI Status](https://img.shields.io/pypi/v/tinto.svg)](https://pypi.python.org/pypi/tinto)
20
+ [![Build Status](https://github.com/balouf/tinto/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/balouf/tinto/actions?query=workflow%3Abuild)
21
+ [![Documentation Status](https://github.com/balouf/tinto/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/balouf/tinto/actions?query=workflow%3Adocs)
22
+ [![License: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
23
+ [![Code Coverage](https://codecov.io/gh/balouf/tinto/branch/main/graphs/badge.svg)](https://codecov.io/gh/balouf/tinto/tree/main)
24
+
25
+ How long does a self-stabilizing graph coloring take to settle? Tinto measures it with a Numba-compiled Monte Carlo over pluggable graphs, guards, schedulers and recoloring rules, down to the variance and skewness of the stabilization time. For the conflict-guard rule under the random central daemon, it also provides exact results.
26
+
27
+
28
+ - Free software: MIT
29
+ - Documentation: <https://balouf.github.io/tinto/>.
30
+ - Github: <https://github.com/balouf/tinto>
31
+
32
+
33
+ ## Features
34
+
35
+ - Numba-compiled dynamics: CSR graphs (line, ring, uniform labeled tree,
36
+ Erdős-Rényi `G(n, p)`, bipartite `G(n1, n2, p)`), pluggable guards,
37
+ four schedulers (shuffled, ordered, Bernoulli, independent) and five
38
+ colorers (lowest, next or uniform free color, plus two blind variants
39
+ that may leave clashes behind).
40
+ - Monte-Carlo driver aggregating mean, variance and third central moment
41
+ of both the number of steps and the number of activations before
42
+ stabilization, on a fixed graph or on a fresh random graph per replica.
43
+ - `Experiment` high-level API with cartesian-product sweeps, campaign
44
+ addition, light matplotlib plotting, CSV export, and fits of the
45
+ results (weighted least squares, test for a hidden term, recovery of
46
+ exact fractions).
47
+ - Exact stabilization time of the conflict-guard rule under the random
48
+ central daemon, from three independent sources: the peak oracle, which
49
+ samples it without running the dynamics (`tinto.oracle`), exact
50
+ enumeration on small graphs (`tinto.exact`) and closed forms
51
+ (`tinto.theory`).
52
+ - Companion notebooks that check the numerical statements of the papers.
53
+ - 100% branch-covered by doctest-based examples.
54
+
55
+ ## Quickstart
56
+
57
+ Install Tinto:
58
+
59
+ ```console
60
+ $ pip install tinto
61
+ ```
62
+
63
+ ### Low-level API
64
+
65
+ Drive one trajectory on a line graph:
66
+
67
+ ```pycon
68
+ >>> from tinto import graphs, configs, schedulers, solvers, runners
69
+ >>> from tinto.io import set_seed
70
+ >>> set_seed(0)
71
+ >>> Config = configs.make()
72
+ >>> c = Config(graphs.line(20))
73
+ >>> sched = schedulers.shuffled()(c)
74
+ >>> solver = solvers.make()
75
+ >>> steps, activations = runners.simple(c, sched, solver)
76
+ >>> steps > 0
77
+ True
78
+ >>> c.total
79
+ 0
80
+ ```
81
+
82
+ Or Monte-Carlo the moments of both metrics over many replicas:
83
+
84
+ ```pycon
85
+ >>> from tinto import starters
86
+ >>> set_seed(0)
87
+ >>> starter = starters.from_graph(Config)(graphs.line(20))
88
+ >>> res = runners.mc(starter, schedulers.shuffled(), solver, n_trials=20)
89
+ >>> mean, var, m3 = res["steps"]
90
+ >>> mean > 0
91
+ True
92
+ ```
93
+
94
+ ### High-level API
95
+
96
+ The `Experiment` class bundles a sweep + the Monte-Carlo runner + plot
97
+ and export helpers. Define an `Iterator` over one parameter, wrap it in
98
+ an `Experiment`, run:
99
+
100
+ ```pycon
101
+ >>> from tinto import Experiment, Iterator
102
+ >>> def build_starter(n):
103
+ ... return starters.from_graph(Config)(graphs.line(n))
104
+ >>> n_iter = Iterator("starter", [10, 20, 50], name="n", process=build_starter)
105
+ >>> exp = Experiment(
106
+ ... "line-sweep",
107
+ ... iterator=n_iter,
108
+ ... scheduler=schedulers.shuffled(),
109
+ ... solver=solver,
110
+ ... n_trials=50,
111
+ ... )
112
+ >>> _ = exp.run(progress=False)
113
+ >>> exp.results["line-sweep"]["axes"]
114
+ ('starter',)
115
+ ```
116
+
117
+ Compose cartesian products with `*` and combine multiple campaigns with
118
+ `+`:
119
+
120
+ ```pycon
121
+ >>> kind_iter = Iterator("starter", ["random", "mono"], name="kind")
122
+ >>> # plot or export via exp.plot(x="n", hue="kind") / exp.to_csv(...)
123
+ ```
124
+
125
+ ## Credits
126
+
127
+ This package was created with [Cookiecutter][CC] and the [Package Helper 3][PH3] project template.
128
+
129
+ [CC]: <https://github.com/audreyr/cookiecutter>
130
+ [PH3]: <https://balouf.github.io/package-helper-3/>
@@ -0,0 +1,17 @@
1
+
2
+ cff-version: 1.2.0
3
+ title: Tinto
4
+ message: >-
5
+ If you use this software, please cite it using the
6
+ metadata from this file.
7
+ type: software
8
+ version: 0.1.0
9
+ date-released: "2026-11-11"
10
+ authors:
11
+ - family-names: Mathieu
12
+ given-names: Fabien
13
+ email: fabien.mathieu@normalesup.org
14
+ repository-code: "https://github.com/balouf/tinto/"
15
+ url: "https://balouf.github.io/tinto/"
16
+ abstract: "How long does a self-stabilizing graph coloring take to settle? Tinto measures it with a Numba-compiled Monte Carlo over pluggable graphs, guards, schedulers and recoloring rules, down to the variance and skewness of the stabilization time. For the conflict-guard rule under the random central daemon, it also provides exact results."
17
+ license: MIT
@@ -0,0 +1,20 @@
1
+ """Pytest configuration for the Tinto test suite."""
2
+
3
+ import os
4
+
5
+ # Disable numba JIT so that coverage can instrument the bodies of @jitclass /
6
+ # @njit functions. Must be set before numba is imported — conftest.py runs
7
+ # before any test or project module. CI mirrors this via the NUMBA_DISABLE_JIT
8
+ # env var in .github/workflows/build.yml.
9
+ os.environ.setdefault("NUMBA_DISABLE_JIT", "1")
10
+
11
+ # Headless matplotlib backend for .plot() doctests. Must be set before any
12
+ # matplotlib import; MPLBACKEND is the official env var for that.
13
+ os.environ.setdefault("MPLBACKEND", "Agg")
14
+
15
+ import numpy as np
16
+
17
+ # NumPy 2.0 changed scalar repr: np.int32(2) now prints as "np.int32(2)"
18
+ # instead of "2", which breaks doctests that were written against JIT output
19
+ # (plain Python ints). The legacy="1.25" flag restores the old repr.
20
+ np.set_printoptions(legacy="1.25")
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" role="img" aria-label="Tinto logo: 5-cycle with a valid 3-coloring">
3
+ <title>Tinto</title>
4
+ <!-- Pentagon (5-cycle) with a proper 3-coloring: R, G, B, R, G. -->
5
+ <!-- Vertex positions, regular pentagon centered at (50, 50), radius 35. -->
6
+ <g stroke="#2f3437" stroke-width="3" stroke-linecap="round">
7
+ <line x1="50" y1="15" x2="16.7" y2="39.2"/>
8
+ <line x1="16.7" y1="39.2" x2="29.4" y2="78.3"/>
9
+ <line x1="29.4" y1="78.3" x2="70.6" y2="78.3"/>
10
+ <line x1="70.6" y1="78.3" x2="83.3" y2="39.2"/>
11
+ <line x1="83.3" y1="39.2" x2="50" y2="15"/>
12
+ </g>
13
+ <g stroke="#2f3437" stroke-width="2.5">
14
+ <circle cx="50" cy="15" r="11" fill="#d62728"/>
15
+ <circle cx="16.7" cy="39.2" r="11" fill="#2ca02c"/>
16
+ <circle cx="29.4" cy="78.3" r="11" fill="#1f77b4"/>
17
+ <circle cx="70.6" cy="78.3" r="11" fill="#d62728"/>
18
+ <circle cx="83.3" cy="39.2" r="11" fill="#2ca02c"/>
19
+ </g>
20
+ </svg>