tiergraph 0.2.0__tar.gz → 0.2.2__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.
- {tiergraph-0.2.0 → tiergraph-0.2.2}/CHANGELOG.md +84 -1
- {tiergraph-0.2.0 → tiergraph-0.2.2}/CONTRIBUTING.md +4 -1
- {tiergraph-0.2.0 → tiergraph-0.2.2}/Makefile +20 -4
- {tiergraph-0.2.0 → tiergraph-0.2.2}/PKG-INFO +1 -1
- {tiergraph-0.2.0 → tiergraph-0.2.2}/RELEASING.md +9 -3
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/concepts.md +9 -5
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/folding.md +198 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/manifest.json +17 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/reference/api.md +323 -11
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/reference/cli.md +5 -5
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/check_reservations.py +0 -25
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/check_tracked_clean.py +1 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/__init__.py +16 -2
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/cli/__init__.py +1 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/fold.py +6 -4
- tiergraph-0.2.2/src/tiergraph/pathplan.py +863 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/semiring.py +120 -1
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/value.py +38 -1
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/schema_codec.py +42 -11
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_cli.py +21 -0
- tiergraph-0.2.2/tests/test_pathplan.py +953 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_publishability_guards.py +11 -5
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_reservation_register.py +48 -16
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_schema_codec_conformance.py +40 -9
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_semiring.py +48 -0
- tiergraph-0.2.2/tests/test_value_embedding.py +139 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/.github/workflows/ci.yml +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/.github/workflows/publish.yml +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/.gitignore +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/.pre-commit-config.yaml +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/LICENSE +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/README.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/SECURITY.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/corpus/accepted-documents.jsonl +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/denied-name-digests.txt +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/README.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/contributing-docs.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/format.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/getting-started.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/construction.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/profiles.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/recognize-and-act.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/selection-and-traversal.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/serialization.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/span-views.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/docs/guide/timing.md +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/examples/__init__.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/examples/caption_alignment.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/examples/critical_path.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/examples/json_document.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/examples/mix_paths.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/examples/mixing.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/examples/text_segmentation.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/pyproject.toml +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/schema/tiergraph.schema.json +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/schema/tiergraph.schema.sha256 +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/__init__.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/capture_corpus.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/check_changelog_claims.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/check_documented.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/check_format_growth.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/check_format_semantics.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/generate_docs.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/scripts/generate_schema.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/__main__.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/action.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/build.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/clock.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/core.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/grammar.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/inspect.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/machine.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/machine_codec.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/path.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/profile.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/py.typed +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/rewrite.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/root.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/schema.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/selection.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/spanview.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/textgrid.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/traversal.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph/wire.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph_dot/__init__.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/src/tiergraph_dot/py.typed +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/__init__.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/__init__.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/action.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/declared_schema_codec_divergences.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/fold.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/kernel.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/machine.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/recognition.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/schema.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/selection.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/traversal.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/conformance/wire.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/fixtures/textgrid/integer-long.TextGrid +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/fixtures/textgrid/reference-long.TextGrid +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/fixtures/textgrid/reference-short.TextGrid +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/semiring_laws.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_action.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_alignment_witness.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_alternation_witness.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_boundary_witness.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_build.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_canonical_properties.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_capture_corpus.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_changelog_claims.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_cli_envelope.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_clock.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_core.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_displacement.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_docs.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_dot.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_edit.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_examples.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_external_reference_witness.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_fold.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_fold_exactness.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_fold_witness.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_format_growth.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_format_semantics.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_gate_environment.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_grammar.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_inspect.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_machine.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_machine_codec.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_machine_decoders.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_mix_paths.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_mix_paths_render.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_ordered_containment.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_ordered_polyadic_traversal.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_package.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_path.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_path_alternation.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_polyadic_relations.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_polyadic_view_reachability.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_profile.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_refusal_order.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_rewrite.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_root.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_schema.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_selection.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_selection_semiring.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_semiring_law_discrimination.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_shipped_surface.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_spanview.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_text_domain.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_textgrid.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_traversal.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_value.py +0 -0
- {tiergraph-0.2.0 → tiergraph-0.2.2}/tests/test_wire.py +0 -0
|
@@ -7,6 +7,87 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.2] - 2026-09-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added `LOG_PROBABILITY`, the log-sum-exp semiring over finite IEEE-double log
|
|
15
|
+
weights with `-inf` as its zero: stable addition, log-product multiplication,
|
|
16
|
+
positive weights admitted, overflow refused, every required law except
|
|
17
|
+
addition commutativity declared approximate, and no star. `tiergraph semirings` lists it as
|
|
18
|
+
`log-probability`, and `tiergraph fold --semiring log-probability` runs it.
|
|
19
|
+
Its `normalize` method is the declared readout that turns log weights into
|
|
20
|
+
probabilities of a total; `ExpectationSemiring` still refuses this inexact
|
|
21
|
+
base (#186).
|
|
22
|
+
- Added `PathPlan`, which compiles a `FoldDeclaration` over one `OR` relation on
|
|
23
|
+
an acyclic graph once and evaluates it again under any vector of carrier
|
|
24
|
+
values in the plan's item order. `evaluate` reproduces what `run` returns for
|
|
25
|
+
the same values, with the same provenance and cost account: exactly under the
|
|
26
|
+
`ARCTIC` and `TROPICAL` carriers, and within the algebra's declared
|
|
27
|
+
approximation under `LOG_PROBABILITY`, where a gathered log-sum-exp sums its
|
|
28
|
+
exponentials in a different order than pairwise addition does. `marginals`
|
|
29
|
+
adds the outside pass and returns `PathMarginals`, whose
|
|
30
|
+
`posteriors(readout=...)` reads probabilities through the readout the caller
|
|
31
|
+
declares and the algebra publishes, and reports zero mass rather than
|
|
32
|
+
fabricating a distribution, as `PathPosteriors` with the readout named. Under
|
|
33
|
+
those three carriers the plan runs the algebra's operations in a fused
|
|
34
|
+
schedule when the declaration states no witness order, and under the extremum
|
|
35
|
+
carriers also under an `AlgebraOrder` — a witness order by an algebra's own
|
|
36
|
+
selective addition — with `CHOOSE_FIRST`, whose selection it fuses too; every
|
|
37
|
+
other declaration runs the general schedule. Ranked output, index axes,
|
|
38
|
+
several relations, `AND` transitions, and cycles are refused by name (#186).
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- The package root now exports every semiring constant the shell can name:
|
|
43
|
+
`ARCTIC`, `DECIMAL_ARCTIC`, `LOG_PROBABILITY` and `TROPICAL` join `BOOLEAN`,
|
|
44
|
+
`COUNTING`, `DECIMAL_TROPICAL` and `PATH` there. `PATH_WITNESSES`, which the
|
|
45
|
+
shell has no spelling for, stays on `tiergraph.semiring`, as every constant
|
|
46
|
+
still does (#186).
|
|
47
|
+
- `FoldDeclaration` now states where a readout above the algebra is declared,
|
|
48
|
+
and the `declared-readout` reservation is discharged: the reservation
|
|
49
|
+
register carries four entries, and `PathMarginals.posteriors` records the
|
|
50
|
+
readout it applies (#186).
|
|
51
|
+
- The gate's three hash-seed test passes run concurrently under `make
|
|
52
|
+
determinism`; `DETERMINISM_JOBS=1` runs them one at a time, and each seed
|
|
53
|
+
writes its own log under the virtualenv and prints only its summary line when
|
|
54
|
+
it passes; a failing seed prints its whole log.
|
|
55
|
+
The publishability test that plants a sentinel under the checkout's ignored
|
|
56
|
+
local agent directory names it per process, so concurrent passes over one
|
|
57
|
+
checkout no longer race on its cleanup (#187).
|
|
58
|
+
- The schema-codec conformance suite audits its generated probes once per
|
|
59
|
+
module and subtracts each test's policy from that audit, through the
|
|
60
|
+
harness's new `audit_drifts` and `subtract_declared`, whose composition
|
|
61
|
+
`undeclared_drifts` still is; a test holds the two answers equal. The three
|
|
62
|
+
tests that each ran the full audit took most of the suite's time (#187).
|
|
63
|
+
- `FORMAT_VERSION` stays `"0.2.0"`: nothing in this line touches the wire
|
|
64
|
+
format, and `make format-growth` reports no break.
|
|
65
|
+
|
|
66
|
+
### Documentation
|
|
67
|
+
|
|
68
|
+
- The release runbook's step 3 no longer says a stale local `dist/` build is
|
|
69
|
+
what the publish workflow would upload; the workflow builds from a fresh
|
|
70
|
+
checkout of the tag. It now separates the two local checks: the wheel package
|
|
71
|
+
listing reads `dist/*.whl`, so a stale archive is what it would read, while
|
|
72
|
+
the printed version imports from `src` and never consults `dist/` at all. The
|
|
73
|
+
`dist/` filename listing is the only step that would expose a stale build, as
|
|
74
|
+
an extra pair of archives (#185).
|
|
75
|
+
|
|
76
|
+
## [0.2.1] - 2026-09-13
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
|
|
80
|
+
- Added `embed_json_value` to embed a native JSON value in an existing graph
|
|
81
|
+
through an explicitly fresh namespace. It returns the extended graph, its
|
|
82
|
+
validated value profile, and the value root while preserving the source
|
|
83
|
+
graph. Namespace collisions refuse without partial changes; owner relations
|
|
84
|
+
remain caller-declared. The graph interchange format is unchanged (#183).
|
|
85
|
+
|
|
86
|
+
### Documentation
|
|
87
|
+
|
|
88
|
+
- Clarified that release-phase format-growth regression tests must consult
|
|
89
|
+
tags, so the release tag does not invalidate their expectations (#182).
|
|
90
|
+
|
|
10
91
|
## [0.2.0] - 2026-09-05
|
|
11
92
|
|
|
12
93
|
### Highlights
|
|
@@ -881,6 +962,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
881
962
|
- TG-PATH canonical addressing for structural and durable items and boundaries, profile-owned alternatives, kind checks, and typed refusals with offender details.
|
|
882
963
|
- Canonical selection, bounded bipartite walks, ordered polyadic traversal, and ordered containment queries that preserve declared incidence and child order where applicable.
|
|
883
964
|
|
|
884
|
-
[Unreleased]: https://github.com/lenzo-ka/tiergraph/compare/v0.2.
|
|
965
|
+
[Unreleased]: https://github.com/lenzo-ka/tiergraph/compare/v0.2.2...HEAD
|
|
966
|
+
[0.2.2]: https://github.com/lenzo-ka/tiergraph/compare/v0.2.1...v0.2.2
|
|
967
|
+
[0.2.1]: https://github.com/lenzo-ka/tiergraph/compare/v0.2.0...v0.2.1
|
|
885
968
|
[0.2.0]: https://github.com/lenzo-ka/tiergraph/compare/v0.1.0...v0.2.0
|
|
886
969
|
[0.1.0]: https://github.com/lenzo-ka/tiergraph/releases/tag/v0.1.0
|
|
@@ -52,7 +52,10 @@ version this section used to carry fell a step behind twice: a copied list is a
|
|
|
52
52
|
claim about the gate that nothing checks.
|
|
53
53
|
|
|
54
54
|
`make check` builds the virtualenv and then runs `make gate`, which is the same
|
|
55
|
-
steps against an environment that already exists.
|
|
55
|
+
steps against an environment that already exists. The `determinism` step runs
|
|
56
|
+
its three seeds concurrently, each writing a log under the virtualenv and
|
|
57
|
+
printing its summary line; on a machine that cannot hold three interpreters at
|
|
58
|
+
once, `make gate DETERMINISM_JOBS=1` runs them one at a time. Run `gate` where an index
|
|
56
59
|
cannot be reached, rather than copying its steps out by hand. Coverage is
|
|
57
60
|
measured for the `tiergraph` and `tiergraph_dot` packages and for the `scripts`
|
|
58
61
|
gates, and must remain at 100% branch coverage.
|
|
@@ -26,7 +26,7 @@ export PYTHONPATH := $(MAKEFILE_DIR)/src$(if $(PYTHONPATH),:$(PYTHONPATH))
|
|
|
26
26
|
# and runs nothing. A target left off this line is silent until something in the
|
|
27
27
|
# tree happens to share its name, which is why `format-semantics` and
|
|
28
28
|
# `corpus-capture` sat missing here without ever being noticed.
|
|
29
|
-
.PHONY: venv lint format-check types test determinism-seed determinism schema schema-check format-growth format-semantics corpus-capture docs docs-check tracked-clean documented reservations changelog-claims gate-fast gate check
|
|
29
|
+
.PHONY: venv lint format-check types test determinism-seed determinism determinism-seed-0 determinism-seed-12345 determinism-seed-999 schema schema-check format-growth format-semantics corpus-capture docs docs-check tracked-clean documented reservations changelog-claims gate-fast gate check
|
|
30
30
|
|
|
31
31
|
# Development happens in an isolated environment: a shared interpreter drags in
|
|
32
32
|
# packages this project does not depend on, and they surface as type errors in
|
|
@@ -56,10 +56,26 @@ determinism-seed:
|
|
|
56
56
|
@test -n "$(HASH_SEED)" || (echo "HASH_SEED is required" >&2; exit 2)
|
|
57
57
|
@PYTHONHASHSEED=$(HASH_SEED) $(VENV_PYTHON) -m pytest
|
|
58
58
|
|
|
59
|
+
# The three seeds are independent, so they run concurrently: measured serial,
|
|
60
|
+
# they were the larger half of the gate's wall time. Each seed writes its own
|
|
61
|
+
# log under the virtualenv (ignored, so it cannot ship) and prints only its
|
|
62
|
+
# summary line, so three interleaved dot streams do not have to be read. A
|
|
63
|
+
# failing seed prints its whole log. DETERMINISM_JOBS=1 runs them one at a
|
|
64
|
+
# time on a machine that cannot hold three interpreters at once.
|
|
65
|
+
DETERMINISM_JOBS ?= 3
|
|
66
|
+
DETERMINISM_SEEDS := 0 12345 999
|
|
67
|
+
|
|
59
68
|
determinism:
|
|
60
|
-
|
|
61
|
-
$(
|
|
62
|
-
|
|
69
|
+
@$(MAKE) --no-print-directory -j$(DETERMINISM_JOBS) \
|
|
70
|
+
$(addprefix determinism-seed-,$(DETERMINISM_SEEDS))
|
|
71
|
+
|
|
72
|
+
determinism-seed-0 determinism-seed-12345 determinism-seed-999:
|
|
73
|
+
@seed=$(@:determinism-seed-%=%); log=$(VENV)/determinism-$$seed.log; \
|
|
74
|
+
if $(MAKE) --no-print-directory determinism-seed HASH_SEED=$$seed >$$log 2>&1; then \
|
|
75
|
+
printf 'seed %s: %s\n' "$$seed" "$$(tail -n 1 $$log)"; \
|
|
76
|
+
else \
|
|
77
|
+
status=$$?; cat $$log; echo "seed $$seed failed" >&2; exit $$status; \
|
|
78
|
+
fi
|
|
63
79
|
|
|
64
80
|
tracked-clean:
|
|
65
81
|
@$(VENV_PYTHON) scripts/check_tracked_clean.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tiergraph
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Ordered tiers, declared relations, and an algebra over them
|
|
5
5
|
Project-URL: Homepage, https://github.com/lenzo-ka/tiergraph
|
|
6
6
|
Project-URL: Repository, https://github.com/lenzo-ka/tiergraph
|
|
@@ -82,7 +82,11 @@ job references it; the OIDC identity is scoped to it).
|
|
|
82
82
|
opened the release line, and this edit is what leaves something for that
|
|
83
83
|
commit.
|
|
84
84
|
|
|
85
|
-
3. **
|
|
85
|
+
3. **Regenerate version-bearing documentation, then verify locally.** Run
|
|
86
|
+
`make docs` after changing the package version: the generated API and CLI
|
|
87
|
+
references carry it. Commit those generated changes with the
|
|
88
|
+
release preparation so the gate checks the documentation that will ship.
|
|
89
|
+
Run these from the development virtualenv that
|
|
86
90
|
[CONTRIBUTING.md](CONTRIBUTING.md#set-up-a-development-environment) builds —
|
|
87
91
|
`make venv` creates `.venv` and installs the `build` frontend along with the
|
|
88
92
|
rest of the development dependencies. Three of these steps are **read**, not
|
|
@@ -113,8 +117,9 @@ job references it; the OIDC identity is scoped to it).
|
|
|
113
117
|
displaying it — so without this line the doc asks for a comparison it
|
|
114
118
|
gives no way to make. Expect exactly `tiergraph-X.Y.Z.tar.gz` and
|
|
115
119
|
`tiergraph-X.Y.Z-py3-none-any.whl`; a stale build left in `dist/` from an
|
|
116
|
-
earlier version shows up here as an extra pair
|
|
117
|
-
|
|
120
|
+
earlier version shows up here as an extra pair. The publish workflow never
|
|
121
|
+
sees it — it builds from a fresh checkout of the tag — but the local
|
|
122
|
+
checks below would read the wrong archive.
|
|
118
123
|
- **The wheel listing must show both packages.** The grep exits 0 when
|
|
119
124
|
either package is present, so the exit status decides nothing: read the
|
|
120
125
|
output and confirm entries under `tiergraph/` *and* under `tiergraph_dot/`.
|
|
@@ -255,6 +260,7 @@ ascending sort order.
|
|
|
255
260
|
still exists, before `rm -rf dist build` removes it. That listing is read, not
|
|
256
261
|
scored: the pattern matches either package, so *both* is a fact about the
|
|
257
262
|
output rather than about the exit status.
|
|
263
|
+
- **Tag-sensitive format-growth tests**: A regression test that asserts what `format-growth` reports is phase-dependent: the report changes the moment the line's first tag exists. Such a test must read the phase from the tags, as `test_the_committed_schema_reports_only_the_break_this_release_priced` does, or it fails on the release commit once tagged; the tag goes up with the release commit in step 4, and the CI run that must be green before step 5 checks out full history and tags, so it sees the tag and a test depending on the tag's absence fails there.
|
|
258
264
|
- **CI must be green first**: `ci.yml` runs on the push; only cut the release
|
|
259
265
|
once it passes.
|
|
260
266
|
- **Re-releases**: PyPI is immutable — you cannot overwrite `X.Y.Z`. If a build
|
|
@@ -121,11 +121,15 @@ or schema is present or recognized; required fields or types inside `value`;
|
|
|
121
121
|
numeric ranges; or canonical serialization. The producing and consuming
|
|
122
122
|
applications must perform those validations.
|
|
123
123
|
|
|
124
|
-
Separately, `json_value_graph` and `JsonValueProfile`
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
Separately, `json_value_graph` and `JsonValueProfile` represent a JSON value as
|
|
125
|
+
a checked, standalone graph. `embed_json_value(graph, value, namespace=...)`
|
|
126
|
+
adds that native structure to an existing graph and returns the extended graph,
|
|
127
|
+
validated profile, and root reference. Supply a `NamespaceDeclaration` with an
|
|
128
|
+
unused URI and prefix; collisions refuse rather than rename or overwrite.
|
|
129
|
+
Existing facts remain unchanged, including boundaries, seals, and layers.
|
|
130
|
+
The helper does not infer an owner: link the returned root through your own
|
|
131
|
+
declared relation. It is not an arbitrary graph merge or an automatic migration
|
|
132
|
+
of stringified-JSON attributes.
|
|
129
133
|
|
|
130
134
|
## Coordinates, and what an edit does to them
|
|
131
135
|
|
|
@@ -335,6 +335,204 @@ Use `TROPICAL` or `ARCTIC`, whose associativity check is approximate, for
|
|
|
335
335
|
`xsd:double` values. The refusal is a declaration-time guard, so a fold that
|
|
336
336
|
runs has already been checked for this mismatch.
|
|
337
337
|
|
|
338
|
+
## Preparing a path plan
|
|
339
|
+
|
|
340
|
+
A fold over one `OR` relation on an acyclic graph is a path graph: every
|
|
341
|
+
derivation is a root-to-sink path, and its value is the product of the local
|
|
342
|
+
values along it. When the graph stays fixed and only the values change — an
|
|
343
|
+
expectation step re-weighting the same lattice, a sweep over parameters —
|
|
344
|
+
`PathPlan` compiles the declaration's topology once and evaluates it under any
|
|
345
|
+
vector of carrier values given in the plan's item order. `PathPlan.evaluate`
|
|
346
|
+
returns what `FoldDeclaration.run` returns, provenance and cost account
|
|
347
|
+
included, and `PathPlan.marginals` adds the outside pass: for every item, the
|
|
348
|
+
sum over the derivations that pass through it.
|
|
349
|
+
|
|
350
|
+
The example is a small lattice whose states and arcs are items of one tier,
|
|
351
|
+
joined by a `next` relation, with the arcs after the states. Under
|
|
352
|
+
`LOG_PROBABILITY` the values are log weights and `-INF` is the zero. A sink
|
|
353
|
+
accepts with its own value, so the final state carries `0.0` and a dead end
|
|
354
|
+
would carry `-INF`.
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
import math
|
|
358
|
+
|
|
359
|
+
from tiergraph import (
|
|
360
|
+
AttributeDeclaration,
|
|
361
|
+
AttributeDomain,
|
|
362
|
+
AttributeValuation,
|
|
363
|
+
AttributeValue,
|
|
364
|
+
BipartiteRelationDeclaration,
|
|
365
|
+
ChildCombination,
|
|
366
|
+
FoldDeclaration,
|
|
367
|
+
FoldTransition,
|
|
368
|
+
Graph,
|
|
369
|
+
Item,
|
|
370
|
+
ItemRef,
|
|
371
|
+
NamespaceDeclaration,
|
|
372
|
+
QualifiedName,
|
|
373
|
+
RelationInstance,
|
|
374
|
+
SimpleRelationDeclaration,
|
|
375
|
+
Tier,
|
|
376
|
+
TierDeclaration,
|
|
377
|
+
TiePolicy,
|
|
378
|
+
XsdType,
|
|
379
|
+
)
|
|
380
|
+
from tiergraph.pathplan import AlgebraOrder, PathPlan
|
|
381
|
+
from tiergraph.semiring import ARCTIC, LOG_PROBABILITY
|
|
382
|
+
|
|
383
|
+
ns = "https://example.com/plan"
|
|
384
|
+
nodes = QualifiedName(ns, "nodes")
|
|
385
|
+
node = QualifiedName(ns, "node")
|
|
386
|
+
follows = QualifiedName(ns, "next")
|
|
387
|
+
weight = QualifiedName(ns, "weight")
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def item(label: str, log_weight: float) -> Item:
|
|
391
|
+
lexical = "-INF" if log_weight == -math.inf else repr(log_weight)
|
|
392
|
+
return Item(label, (AttributeValue(weight, XsdType.DOUBLE, lexical),))
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
labels = ("s", "m", "f", "merged", "first", "silent")
|
|
396
|
+
lattice_refs = {label: ItemRef(nodes, index) for index, label in enumerate(labels)}
|
|
397
|
+
graph = Graph(
|
|
398
|
+
(NamespaceDeclaration("lattice", ns),),
|
|
399
|
+
(
|
|
400
|
+
Tier(
|
|
401
|
+
TierDeclaration(nodes, "States and arcs"),
|
|
402
|
+
(
|
|
403
|
+
item("s", 0.0),
|
|
404
|
+
item("m", 0.0),
|
|
405
|
+
item("f", 0.0),
|
|
406
|
+
item("merged", math.log(0.4)),
|
|
407
|
+
item("first", math.log(0.3)),
|
|
408
|
+
item("silent", math.log(0.5)),
|
|
409
|
+
),
|
|
410
|
+
),
|
|
411
|
+
),
|
|
412
|
+
(
|
|
413
|
+
SimpleRelationDeclaration(QualifiedName(ns, "membership"), nodes, node),
|
|
414
|
+
BipartiteRelationDeclaration(follows, node, node, acyclic=True),
|
|
415
|
+
),
|
|
416
|
+
tuple(
|
|
417
|
+
RelationInstance(follows, lattice_refs[left], lattice_refs[right])
|
|
418
|
+
for left, right in (
|
|
419
|
+
("s", "merged"),
|
|
420
|
+
("merged", "f"),
|
|
421
|
+
("s", "first"),
|
|
422
|
+
("first", "m"),
|
|
423
|
+
("m", "silent"),
|
|
424
|
+
("silent", "f"),
|
|
425
|
+
)
|
|
426
|
+
),
|
|
427
|
+
(AttributeDeclaration(weight, AttributeDomain.ITEM, XsdType.DOUBLE),),
|
|
428
|
+
)
|
|
429
|
+
valuation = AttributeValuation("weight", weight, (nodes,))
|
|
430
|
+
transitions = (FoldTransition(follows, ChildCombination.OR),)
|
|
431
|
+
|
|
432
|
+
plan = PathPlan.prepare(
|
|
433
|
+
FoldDeclaration(
|
|
434
|
+
"lattice",
|
|
435
|
+
graph,
|
|
436
|
+
valuation,
|
|
437
|
+
LOG_PROBABILITY,
|
|
438
|
+
lambda value, _label: value,
|
|
439
|
+
transitions,
|
|
440
|
+
roots=(lattice_refs["s"],),
|
|
441
|
+
)
|
|
442
|
+
)
|
|
443
|
+
marginals = plan.marginals()
|
|
444
|
+
print("log mass:", round(marginals.total, 6))
|
|
445
|
+
posteriors = marginals.posteriors(readout="normalize")
|
|
446
|
+
print("readout:", posteriors.readout)
|
|
447
|
+
probabilities = posteriors.values
|
|
448
|
+
assert probabilities is not None # zero mass is reported, never fabricated
|
|
449
|
+
for label, probability in zip(plan.labels, probabilities):
|
|
450
|
+
print(f"{label}: {probability:.4f}")
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
```text
|
|
454
|
+
log mass: -0.597837
|
|
455
|
+
readout: normalize
|
|
456
|
+
s: 1.0000
|
|
457
|
+
m: 0.2727
|
|
458
|
+
f: 1.0000
|
|
459
|
+
merged: 0.7273
|
|
460
|
+
first: 0.2727
|
|
461
|
+
silent: 0.2727
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
The mass is `0.4 + 0.3 × 0.5 = 0.55`, and each posterior is the share of that
|
|
465
|
+
mass passing through the item. Normalizing is a division above the algebra,
|
|
466
|
+
so the caller declares the readout by name and the carrier must publish it —
|
|
467
|
+
`normalize` is the one `LOG_PROBABILITY` publishes — and `PathPosteriors`
|
|
468
|
+
records the readout it applied. A zero total is reported as `zero_mass` with
|
|
469
|
+
no values rather than as a fabricated distribution. Aggregating
|
|
470
|
+
posteriors by anything other than item — by the output an arc emits, say — is
|
|
471
|
+
the caller's readout in turn; two arcs producing the same output each carry
|
|
472
|
+
their own share here.
|
|
473
|
+
|
|
474
|
+
New values reuse the compiled topology. `plan.values` holds what the
|
|
475
|
+
declaration lifted, `plan.index` locates an item's position, and a vector of
|
|
476
|
+
another length is refused:
|
|
477
|
+
|
|
478
|
+
```python
|
|
479
|
+
reweighted = list(plan.values)
|
|
480
|
+
reweighted[plan.index(lattice_refs["merged"])] = math.log(0.1)
|
|
481
|
+
print("re-weighted log mass:", round(plan.marginals(reweighted).total, 6))
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
```text
|
|
485
|
+
re-weighted log mass: -1.386294
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
A best path runs the same plan under a selective carrier. `AlgebraOrder` is a
|
|
489
|
+
witness order by the algebra's own addition, so the fold and the plan agree on
|
|
490
|
+
what wins; with `CHOOSE_FIRST` a tie goes to the alternative earliest in the
|
|
491
|
+
graph's canonical order, deterministically, and `ALL` keeps every tied path up
|
|
492
|
+
to `output_cap`.
|
|
493
|
+
|
|
494
|
+
```python
|
|
495
|
+
best = PathPlan.prepare(
|
|
496
|
+
FoldDeclaration(
|
|
497
|
+
"best",
|
|
498
|
+
graph,
|
|
499
|
+
valuation,
|
|
500
|
+
ARCTIC,
|
|
501
|
+
lambda value, _label: value,
|
|
502
|
+
transitions,
|
|
503
|
+
roots=(lattice_refs["s"],),
|
|
504
|
+
witness_order=AlgebraOrder(ARCTIC),
|
|
505
|
+
tie_policy=TiePolicy.CHOOSE_FIRST,
|
|
506
|
+
)
|
|
507
|
+
)
|
|
508
|
+
result = best.evaluate()
|
|
509
|
+
print("best:", round(result.value, 6), result.provenance)
|
|
510
|
+
print("carrier ops:", result.cost.carrier_work)
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
```text
|
|
514
|
+
best: -0.916291 (('s', 'merged', 'f'),)
|
|
515
|
+
carrier ops: 8
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
Under `LOG_PROBABILITY`, `ARCTIC`, and `TROPICAL` the plan runs a fused
|
|
519
|
+
schedule that gathers each item's alternatives at once with the algebra's
|
|
520
|
+
operations inlined, and an `AlgebraOrder` with `CHOOSE_FIRST` fuses the
|
|
521
|
+
selection too. The cost account is the general schedule's. A gathered
|
|
522
|
+
log-sum-exp sums its exponentials in a different order than pairwise
|
|
523
|
+
addition, so under the log carrier the plan agrees with `run` within the
|
|
524
|
+
algebra's declared approximation — at the rounding scale of the operands,
|
|
525
|
+
which a total near cancellation can show in its result — and under the
|
|
526
|
+
extremum carriers exactly. Every other declaration runs the general schedule
|
|
527
|
+
through the algebra's methods and agrees with `run` exactly. A result
|
|
528
|
+
that would leave the finite double carrier is refused as overflow rather than
|
|
529
|
+
read as mass created or destroyed, and a value vector outside the carrier —
|
|
530
|
+
`NaN`, a Boolean, the excluded infinity — is refused before anything runs.
|
|
531
|
+
|
|
532
|
+
A plan refuses what a path cannot carry, each by name: ranked output, an index
|
|
533
|
+
product, more than one dependency relation, an `AND` transition, and a cycle,
|
|
534
|
+
which is reported by its closing edge.
|
|
535
|
+
|
|
338
536
|
## From the command line
|
|
339
537
|
|
|
340
538
|
`tiergraph semirings` lists the algebras the `tiergraph fold` shell can name,
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"GraphEditor"
|
|
39
39
|
],
|
|
40
40
|
"fold": [
|
|
41
|
+
"AlgebraOrder",
|
|
41
42
|
"AttributeValuation",
|
|
42
43
|
"ChildCombination",
|
|
43
44
|
"ExactnessRefusal",
|
|
@@ -48,6 +49,9 @@
|
|
|
48
49
|
"FoldHomomorphism",
|
|
49
50
|
"FoldResult",
|
|
50
51
|
"FoldTransition",
|
|
52
|
+
"PathMarginals",
|
|
53
|
+
"PathPlan",
|
|
54
|
+
"PathPosteriors",
|
|
51
55
|
"TiePolicy"
|
|
52
56
|
],
|
|
53
57
|
"grammar": [
|
|
@@ -147,6 +151,7 @@
|
|
|
147
151
|
"RoleBinding",
|
|
148
152
|
"RoleValue",
|
|
149
153
|
"SpanViewProfile",
|
|
154
|
+
"embed_json_value",
|
|
150
155
|
"json_value_graph",
|
|
151
156
|
"span_view",
|
|
152
157
|
"to_html",
|
|
@@ -195,10 +200,14 @@
|
|
|
195
200
|
"selection_loads"
|
|
196
201
|
],
|
|
197
202
|
"semirings": [
|
|
203
|
+
"ARCTIC",
|
|
198
204
|
"BOOLEAN",
|
|
199
205
|
"COUNTING",
|
|
206
|
+
"DECIMAL_ARCTIC",
|
|
200
207
|
"DECIMAL_TROPICAL",
|
|
208
|
+
"LOG_PROBABILITY",
|
|
201
209
|
"PATH",
|
|
210
|
+
"TROPICAL",
|
|
202
211
|
"StarRefusal",
|
|
203
212
|
"StarSelector",
|
|
204
213
|
"ZeroClosedStar"
|
|
@@ -297,6 +306,12 @@
|
|
|
297
306
|
"text",
|
|
298
307
|
"python",
|
|
299
308
|
"text",
|
|
309
|
+
"python",
|
|
310
|
+
"text",
|
|
311
|
+
"python",
|
|
312
|
+
"text",
|
|
313
|
+
"python",
|
|
314
|
+
"text",
|
|
300
315
|
"console"
|
|
301
316
|
],
|
|
302
317
|
"docs/guide/profiles.md": [
|
|
@@ -378,6 +393,7 @@
|
|
|
378
393
|
"COUNTING",
|
|
379
394
|
"DECIMAL_ARCTIC",
|
|
380
395
|
"DECIMAL_TROPICAL",
|
|
396
|
+
"LOG_PROBABILITY",
|
|
381
397
|
"PATH",
|
|
382
398
|
"PATH_WITNESSES",
|
|
383
399
|
"TROPICAL",
|
|
@@ -389,6 +405,7 @@
|
|
|
389
405
|
"ExpectationSemiring",
|
|
390
406
|
"LawCheck",
|
|
391
407
|
"LexicographicSemiring",
|
|
408
|
+
"LogProbabilitySemiring",
|
|
392
409
|
"Path",
|
|
393
410
|
"PathSemiring",
|
|
394
411
|
"PathValue",
|