morphata 2.2.0__tar.gz → 2.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.
Files changed (122) hide show
  1. {morphata-2.2.0 → morphata-2.2.2}/.envrc +1 -1
  2. {morphata-2.2.0 → morphata-2.2.2}/.gitignore +5 -1
  3. {morphata-2.2.0 → morphata-2.2.2}/CHANGELOG.md +44 -0
  4. {morphata-2.2.0 → morphata-2.2.2}/PKG-INFO +2 -2
  5. {morphata-2.2.0 → morphata-2.2.2}/bench/test_equivalence_perf.py +1 -1
  6. {morphata-2.2.0 → morphata-2.2.2}/bench/test_hoa_exporter_perf.py +1 -1
  7. {morphata-2.2.0 → morphata-2.2.2}/bench/test_hoa_parser_perf.py +1 -1
  8. {morphata-2.2.0 → morphata-2.2.2}/bench/test_sere_nlm_perf.py +1 -1
  9. {morphata-2.2.0 → morphata-2.2.2}/bench/test_transforms_perf.py +1 -1
  10. {morphata-2.2.0 → morphata-2.2.2}/ci/make-release +16 -18
  11. {morphata-2.2.0 → morphata-2.2.2}/pixi.lock +907 -842
  12. {morphata-2.2.0 → morphata-2.2.2}/pixi.toml +2 -1
  13. {morphata-2.2.0 → morphata-2.2.2}/pyproject.toml +11 -3
  14. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/__init__.py +2 -0
  15. morphata-2.2.2/src/morphata/_version.py +24 -0
  16. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/acc_expr.py +1 -2
  17. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/acceptance.py +4 -6
  18. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/builder.py +4 -1
  19. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/__main__.py +1 -1
  20. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/parser.py +4 -5
  21. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/_common.py +17 -10
  22. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/ltl.py +1 -1
  23. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/psl.py +3 -4
  24. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/sere.py +25 -21
  25. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/_backend.py +3 -2
  26. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/matrix.py +20 -17
  27. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/polynomial.py +28 -16
  28. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/automaton.py +62 -26
  29. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/bdd.py +247 -292
  30. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/utils.py +21 -16
  31. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/utils.py +1 -1
  32. {morphata-2.2.0 → morphata-2.2.2}/tests/conftest.py +3 -4
  33. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/test_parser.py +1 -1
  34. {morphata-2.2.0 → morphata-2.2.2}/tests/logic/test_ltl.py +1 -2
  35. {morphata-2.2.0 → morphata-2.2.2}/tests/logic/test_psl.py +18 -16
  36. {morphata-2.2.0 → morphata-2.2.2}/tests/logic/test_sere.py +21 -17
  37. {morphata-2.2.0 → morphata-2.2.2}/tests/operators/test_matrix.py +2 -2
  38. {morphata-2.2.0 → morphata-2.2.2}/tests/operators/test_polynomial.py +1 -1
  39. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_bdd_helpers.py +3 -3
  40. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_compose.py +96 -1
  41. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_language_equivalence.py +52 -2
  42. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_ltlf2dfa_equivalence.py +2 -2
  43. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_symbolic_automaton.py +230 -5
  44. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_to_hoa.py +2 -2
  45. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_transforms.py +4 -4
  46. {morphata-2.2.0 → morphata-2.2.2}/tests/test_acceptance_validation.py +1 -1
  47. {morphata-2.2.0 → morphata-2.2.2}/tests/test_alphabet.py +2 -2
  48. {morphata-2.2.0 → morphata-2.2.2}/uv.lock +70 -93
  49. {morphata-2.2.0 → morphata-2.2.2}/.basedpyright/baseline.json +0 -0
  50. {morphata-2.2.0 → morphata-2.2.2}/.dockerignore +0 -0
  51. {morphata-2.2.0 → morphata-2.2.2}/.editorconfig +0 -0
  52. {morphata-2.2.0 → morphata-2.2.2}/.envrc.recommended +0 -0
  53. {morphata-2.2.0 → morphata-2.2.2}/.fdignore +0 -0
  54. {morphata-2.2.0 → morphata-2.2.2}/.gitattributes +0 -0
  55. {morphata-2.2.0 → morphata-2.2.2}/.mailmap +0 -0
  56. {morphata-2.2.0 → morphata-2.2.2}/.python-version +0 -0
  57. {morphata-2.2.0 → morphata-2.2.2}/.rstcheck.cfg +0 -0
  58. {morphata-2.2.0 → morphata-2.2.2}/AGENTS.md +0 -0
  59. {morphata-2.2.0 → morphata-2.2.2}/CLAUDE.md +0 -0
  60. {morphata-2.2.0 → morphata-2.2.2}/CONTRIBUTING.md +0 -0
  61. {morphata-2.2.0 → morphata-2.2.2}/LICENSE +0 -0
  62. {morphata-2.2.0 → morphata-2.2.2}/README.rst +0 -0
  63. {morphata-2.2.0 → morphata-2.2.2}/bench/README.md +0 -0
  64. {morphata-2.2.0 → morphata-2.2.2}/bench/__init__.py +0 -0
  65. {morphata-2.2.0 → morphata-2.2.2}/bench/conftest.py +0 -0
  66. {morphata-2.2.0 → morphata-2.2.2}/docs/Makefile +0 -0
  67. {morphata-2.2.0 → morphata-2.2.2}/docs/_static/navigation.html +0 -0
  68. {morphata-2.2.0 → morphata-2.2.2}/docs/api/modules.rst +0 -0
  69. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.acc_expr.rst +0 -0
  70. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.acceptance.rst +0 -0
  71. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.alphabet.rst +0 -0
  72. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.builder.rst +0 -0
  73. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.hoa.rst +0 -0
  74. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.logic.rst +0 -0
  75. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.operators.rst +0 -0
  76. {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.symbolic.rst +0 -0
  77. {morphata-2.2.0 → morphata-2.2.2}/docs/changelog.md +0 -0
  78. {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/acceptance.rst +0 -0
  79. {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/hoa.rst +0 -0
  80. {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/index.rst +0 -0
  81. {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/operators.rst +0 -0
  82. {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/symbolic.rst +0 -0
  83. {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/weights.rst +0 -0
  84. {morphata-2.2.0 → morphata-2.2.2}/docs/conf.py +0 -0
  85. {morphata-2.2.0 → morphata-2.2.2}/docs/index.rst +0 -0
  86. {morphata-2.2.0 → morphata-2.2.2}/docs/quick-start.rst +0 -0
  87. {morphata-2.2.0 → morphata-2.2.2}/justfile +0 -0
  88. {morphata-2.2.0 → morphata-2.2.2}/mypy.ini +0 -0
  89. {morphata-2.2.0 → morphata-2.2.2}/project.utf-8.add +0 -0
  90. {morphata-2.2.0 → morphata-2.2.2}/project.utf-8.add.spl +0 -0
  91. {morphata-2.2.0 → morphata-2.2.2}/pyrightconfig.json +0 -0
  92. {morphata-2.2.0 → morphata-2.2.2}/pytest.toml +0 -0
  93. {morphata-2.2.0 → morphata-2.2.2}/rules/no-derivative-multiarg.yml +0 -0
  94. {morphata-2.2.0 → morphata-2.2.2}/rules/no-typing-as-ty.yml +0 -0
  95. {morphata-2.2.0 → morphata-2.2.2}/sgconfig.yml +0 -0
  96. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/alphabet.py +0 -0
  97. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/__init__.py +0 -0
  98. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/hoa.lark +0 -0
  99. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/__init__.py +0 -0
  100. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/__init__.pyi +0 -0
  101. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/__init__.py +0 -0
  102. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/py.typed +0 -0
  103. {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/__init__.py +0 -0
  104. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut1.hoa +0 -0
  105. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut11.hoa +0 -0
  106. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut2.hoa +0 -0
  107. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut3.2.hoa +0 -0
  108. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut3.hoa +0 -0
  109. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut4.hoa +0 -0
  110. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut5.hoa +0 -0
  111. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut6.hoa +0 -0
  112. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut7.hoa +0 -0
  113. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut8.hoa +0 -0
  114. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/finite_aut.hoa +0 -0
  115. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/gen_buchi_3.hoa +0 -0
  116. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/gen_cobuchi_2.hoa +0 -0
  117. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/rabin_2pair.hoa +0 -0
  118. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/streett_2pair.hoa +0 -0
  119. {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/test_exporter.py +0 -0
  120. {morphata-2.2.0 → morphata-2.2.2}/tests/logic/__init__.py +0 -0
  121. {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_from_hoaf.py +0 -0
  122. {morphata-2.2.0 → morphata-2.2.2}/tests/test_builder.py +0 -0
@@ -23,4 +23,4 @@ export PIXI_ENV
23
23
  dotenv_if_exists
24
24
 
25
25
  watch_file pixi.lock
26
- eval "$(pixi shell-hook --as-is -e "$PIXI_ENV")"
26
+ eval "$(pixi shell-hook -e "$PIXI_ENV")"
@@ -1,7 +1,11 @@
1
+ # generated version file
2
+ src/morphata/_version.py
3
+
1
4
  # generated type stubs
2
5
  /typings/
3
6
  # pixi environments
4
- .pixi
7
+ .pixi/*
8
+ !.pixi/config.toml
5
9
 
6
10
  # Created by https://www.toptal.com/developers/gitignore/api/python
7
11
  # Edit at https://www.toptal.com/developers/gitignore?templates=python
@@ -1,5 +1,49 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.2.2 — 2026-08-23
4
+
5
+ ### Fixed
6
+
7
+ - Fixes a bug with complement and composition of nondeterministic automata
8
+
9
+ `__invert__` dualized each
10
+ (guard, successor)
11
+ pair on its own, leaving the implicit disjunction across a state's pairs undualized.
12
+ Read each state's relation back through `partition_by_state_residual` first,
13
+ so the disjunction sits inside one residual per disjoint guard class;
14
+ missing moves come back as a `false` residual, whose dual is the correct `true`.
15
+
16
+ `compose_automata` remapped only the reachable states,
17
+ so a fresh index could land on an unreachable state that kept its own index
18
+ and silently overwrite a transition row.
19
+ Remap every state and prune the unreachable rows afterwards.
20
+ `reindex_states` now rejects an assignment whose image collides with a state it does
21
+ not remap, so the same mistake raises instead of corrupting.
22
+
23
+ Together these made `is_language_equivalent` report False
24
+ for automata with identical languages.
25
+
26
+ ## 2.2.1 — 2026-08-20
27
+
28
+ This version bump is mostly a cleanup after the 2.2.0 rewrite,
29
+ but also swaps `dd` for `pollywog` as the wrapper around CUDD
30
+ for the symbolic automaton.
31
+ The main reason for the latter is that `dd` wasn't well-typed,
32
+ and because `dd` doesn't expose Algebraic Decision Diagrams,
33
+ which may be useful for a future symbolic weighted automaton.
34
+
35
+ ### Changed
36
+
37
+ - The BDD layer now uses `pollywog` instead of `dd`,
38
+ and the symbolic automaton code was adjusted to match.
39
+ Most of the visible work here is internal:
40
+ manager transfers and substitutions were tightened up,
41
+ and the tests moved along with the backend swap.
42
+ - Project versioning now comes from the VCS tag instead of being hard-coded in
43
+ `pyproject.toml`.
44
+ The release script now takes an explicit target version,
45
+ and `morphata.__version__` is exported from the generated version file.
46
+
3
47
  ## 2.2.0 — 2026-08-19
4
48
 
5
49
  This is a major release as it cleans up a lot of bad code,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morphata
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: Representation theory for automata, made practical.
5
5
  Project-URL: Documentation, https://docs.anandb.dev/morphata
6
6
  Project-URL: Repository, https://git.anandb.dev/morphata.git
@@ -14,11 +14,11 @@ Requires-Python: >=3.12
14
14
  Requires-Dist: algebraic-arrays>=1.3.0
15
15
  Requires-Dist: attrs>=25.4.0
16
16
  Requires-Dist: cattrs>=26.1.0
17
- Requires-Dist: dd>=0.6.0
18
17
  Requires-Dist: jaxtyping>=0.3
19
18
  Requires-Dist: lark>=1.3.1
20
19
  Requires-Dist: logic-asts>=1.8
21
20
  Requires-Dist: numpy
21
+ Requires-Dist: pollywog>=0.1.1
22
22
  Requires-Dist: typing-extensions>=4.14
23
23
  Provides-Extra: dot
24
24
  Requires-Dist: pydot>=4.0.1; extra == 'dot'
@@ -15,8 +15,8 @@ from __future__ import annotations
15
15
 
16
16
  from collections.abc import Set as AbstractSet
17
17
 
18
- import logic_asts.ltl as ltl
19
18
  import pytest
19
+ from logic_asts import ltl
20
20
  from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
21
21
 
22
22
  from morphata.alphabet import powerset_alphabet
@@ -25,8 +25,8 @@ from __future__ import annotations
25
25
 
26
26
  from collections.abc import Set as AbstractSet
27
27
 
28
- import logic_asts.ltl as ltl
29
28
  import pytest
29
+ from logic_asts import ltl
30
30
  from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
31
31
 
32
32
  from morphata.alphabet import powerset_alphabet
@@ -30,9 +30,9 @@ import functools
30
30
  from pathlib import Path
31
31
 
32
32
  import logic_asts as logic
33
- import logic_asts.ltl as ltl
34
33
  import pytest
35
34
  from lark import Lark
35
+ from logic_asts import ltl
36
36
  from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
37
37
 
38
38
  from morphata.alphabet import powerset_alphabet
@@ -27,8 +27,8 @@ from __future__ import annotations
27
27
  from collections.abc import Set as AbstractSet
28
28
 
29
29
  import logic_asts as logic
30
- import logic_asts.sere as sere
31
30
  import pytest
31
+ from logic_asts import sere
32
32
  from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
33
33
 
34
34
  from morphata.alphabet import BooleanAlphabet, powerset_alphabet
@@ -26,8 +26,8 @@ from __future__ import annotations
26
26
  from collections.abc import Set as AbstractSet
27
27
 
28
28
  import logic_asts as logic
29
- import logic_asts.ltl as ltl
30
29
  import pytest
30
+ from logic_asts import ltl
31
31
  from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
32
32
 
33
33
  from morphata.alphabet import powerset_alphabet
@@ -4,14 +4,14 @@ set -euo pipefail
4
4
  # Usage ------------------------------------------------------------------
5
5
  usage() {
6
6
  cat <<EOF
7
- Usage: $(basename "$0") <bump>
7
+ Usage: $(basename "$0") <version>
8
8
 
9
- bump Version bump kind passed to 'uv version --bump'
10
- (patch, minor, major, etc.)
9
+ version Target release version, without a leading 'v'
10
+ (the project version is derived from the git tag)
11
11
 
12
12
  Examples:
13
- $(basename "$0") patch
14
- $(basename "$0") minor
13
+ $(basename "$0") 2.3.0
14
+ $(basename "$0") 2.2.2
15
15
  EOF
16
16
  exit 1
17
17
  }
@@ -23,7 +23,7 @@ fi
23
23
  PROJECT_DIR="$(cd "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/.." && pwd)"
24
24
  cd "$PROJECT_DIR"
25
25
 
26
- BUMP="$1"
26
+ NEW_VERSION="${1#v}"
27
27
 
28
28
  # Helpers ----------------------------------------------------------------
29
29
  is_jj() { [[ -d "$PROJECT_DIR/.jj" ]]; }
@@ -64,48 +64,46 @@ elif [[ "$UNRELEASED_COUNT" -gt 1 ]]; then
64
64
  exit 1
65
65
  fi
66
66
 
67
- # Bump version and check tag
68
- OLD_VERSION="$(uv version --short)"
69
- NEW_VERSION="$(uv version --bump "$BUMP" --dry-run --short)"
67
+ # Determine versions and check tag
68
+ OLD_TAG="$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null || true)"
69
+ OLD_VERSION="${OLD_TAG#v}"
70
70
  TAG="v${NEW_VERSION}"
71
71
  RELEASE_DATE="$(date +%Y-%m-%d)"
72
72
 
73
- echo "==> Bumping $BUMP version..."
74
- echo " Current version: $OLD_VERSION"
73
+ echo "==> Releasing version $NEW_VERSION..."
74
+ echo " Current version: ${OLD_VERSION:-<none>}"
75
75
  echo " New version: $NEW_VERSION"
76
76
  echo " Tag: $TAG"
77
77
  echo " Date: $RELEASE_DATE"
78
78
 
79
79
  if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null 2>&1; then
80
80
  echo "error: tag '$TAG' already exists" >&2
81
- echo "error: refusing to bump $BUMP version" >&2
82
81
  exit 1
83
82
  fi
84
- uv version --bump "$BUMP"
85
83
 
86
84
  # Promote CHANGELOG `Unreleased` to the new version
87
85
  echo "==> Promoting CHANGELOG Unreleased -> ${NEW_VERSION} (${RELEASE_DATE})"
88
86
  sed -i "s/^## Unreleased$/## ${NEW_VERSION} \xe2\x80\x94 ${RELEASE_DATE}/" CHANGELOG.md
89
87
 
90
88
  # Commit
91
- COMMIT_MSG="chore(release): $(uv version)"
89
+ COMMIT_MSG="chore(release): ${NEW_VERSION}"
92
90
  echo "==> Committing: $COMMIT_MSG"
93
91
 
94
92
  if is_jj; then
95
93
  jj commit -m "$COMMIT_MSG"
96
94
  else
97
- git add pyproject.toml CHANGELOG.md
95
+ git add CHANGELOG.md
98
96
  git commit -m "$COMMIT_MSG"
99
97
  fi
100
98
 
101
99
  # Build the tag annotation from the just-promoted CHANGELOG section.
102
- # Title is "release: $(uv version)"; body is the section content (the
100
+ # Title is "release: <ver>"; body is the section content (the
103
101
  # lines between the new `## <ver> ...` heading and the next `## ` heading).
104
- TAG_TITLE="release: $(uv version)"
102
+ TAG_TITLE="release: ${NEW_VERSION}"
105
103
  TAG_BODY="$(awk -v ver="$NEW_VERSION" -v prev="$OLD_VERSION" '
106
104
  $0 ~ "^## " ver "( |$)" { capture = 1; next }
107
105
  capture && /^## / {
108
- if ($0 !~ "^## " prev "( |$)") {
106
+ if (prev != "" && $0 !~ "^## " prev "( |$)") {
109
107
  printf "error: expected next changelog heading to be %s, got: %s\n", \
110
108
  "## " prev, $0 > "/dev/stderr"
111
109
  exit 2