sofic 0.1.0__tar.gz → 0.2.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 (243) hide show
  1. {sofic-0.1.0 → sofic-0.2.0}/.gitignore +3 -0
  2. {sofic-0.1.0 → sofic-0.2.0}/PKG-INFO +1 -1
  3. {sofic-0.1.0 → sofic-0.2.0}/sofic/__init__.py +20 -0
  4. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/__init__.py +29 -0
  5. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/algorithms.py +38 -4
  6. sofic-0.2.0/sofic/automata/atomaton.py +102 -0
  7. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/canonical_extraction.py +9 -2
  8. sofic-0.2.0/sofic/automata/wheeler.py +697 -0
  9. sofic-0.2.0/sofic/automata/wheeler_index.py +291 -0
  10. {sofic-0.1.0 → sofic-0.2.0}/sofic/base.py +36 -0
  11. {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/__init__.py +23 -1
  12. {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/epsilon_machines.py +45 -0
  13. sofic-0.2.0/sofic/examples/tetris.py +239 -0
  14. {sofic-0.1.0 → sofic-0.2.0}/sofic/exceptions.py +12 -0
  15. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/__init__.py +16 -0
  16. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_machine.py +61 -2
  17. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/mixed_state_construction.py +4 -2
  18. sofic-0.2.0/sofic/generators/reversal.py +182 -0
  19. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/synchronization.py +75 -1
  20. sofic-0.2.0/sofic/generators/wheeler_epsilon.py +247 -0
  21. {sofic-0.1.0 → sofic-0.2.0}/sofic/serialization.py +8 -1
  22. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/__init__.py +16 -0
  23. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/covers.py +16 -0
  24. sofic-0.2.0/sofic/shifts/wheeler.py +242 -0
  25. sofic-0.2.0/tests/test_atomaton.py +149 -0
  26. sofic-0.2.0/tests/test_epsilon_machine.py +203 -0
  27. sofic-0.2.0/tests/test_tetris.py +142 -0
  28. sofic-0.2.0/tests/test_wheeler.py +594 -0
  29. sofic-0.1.0/sofic/automata/atomaton.py +0 -58
  30. sofic-0.1.0/sofic/generators/reversal.py +0 -66
  31. sofic-0.1.0/tests/test_atomaton.py +0 -33
  32. sofic-0.1.0/tests/test_epsilon_machine.py +0 -75
  33. {sofic-0.1.0 → sofic-0.2.0}/LICENSE.txt +0 -0
  34. {sofic-0.1.0 → sofic-0.2.0}/README.rst +0 -0
  35. {sofic-0.1.0 → sofic-0.2.0}/pyproject.toml +0 -0
  36. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/_config_simulation.py +0 -0
  37. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/active.py +0 -0
  38. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/alergia.py +0 -0
  39. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/base.py +0 -0
  40. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/buchi.py +0 -0
  41. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/buchi_simulation.py +0 -0
  42. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/canonical_dual.py +0 -0
  43. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/dfa.py +0 -0
  44. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/dfasat.py +0 -0
  45. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/edsm.py +0 -0
  46. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/enumeration.py +0 -0
  47. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/icdfa.py +0 -0
  48. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/idfa.py +0 -0
  49. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/__init__.py +0 -0
  50. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/_quotient_utils.py +0 -0
  51. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/atoms.py +0 -0
  52. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/automaton_ops.py +0 -0
  53. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/base.py +0 -0
  54. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/operations.py +0 -0
  55. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/quotients.py +0 -0
  56. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/residuals.py +0 -0
  57. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/learning.py +0 -0
  58. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/nfa.py +0 -0
  59. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/nwa.py +0 -0
  60. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/nwa_simulation.py +0 -0
  61. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/observation.py +0 -0
  62. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/papni.py +0 -0
  63. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/regex.py +0 -0
  64. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/rfsa.py +0 -0
  65. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/rpni.py +0 -0
  66. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/subsequential.py +0 -0
  67. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/transducer_operations.py +0 -0
  68. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/transducer_simulation.py +0 -0
  69. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/transducers.py +0 -0
  70. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/unifilar.py +0 -0
  71. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/vpa.py +0 -0
  72. {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/vpa_simulation.py +0 -0
  73. {sofic-0.1.0 → sofic-0.2.0}/sofic/core.py +0 -0
  74. {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/processes.py +0 -0
  75. {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/shifts.py +0 -0
  76. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/_word_measures.py +0 -0
  77. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/alternative_complexity.py +0 -0
  78. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/base.py +0 -0
  79. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/bidirectional_construction.py +0 -0
  80. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/bidirectional_epsilon_machine.py +0 -0
  81. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/block_convergence.py +0 -0
  82. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/block_entropy.py +0 -0
  83. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/channel_measures.py +0 -0
  84. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/conversions.py +0 -0
  85. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/directional_flow.py +0 -0
  86. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/edge_emissions.py +0 -0
  87. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/edge_machine.py +0 -0
  88. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_construction.py +0 -0
  89. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_inference.py +0 -0
  90. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_transducer.py +0 -0
  91. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_transducer_construction.py +0 -0
  92. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_transducer_inference.py +0 -0
  93. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/hmm_inference.py +0 -0
  94. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/information_diagram.py +0 -0
  95. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/lumping.py +0 -0
  96. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/markov.py +0 -0
  97. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/mealy.py +0 -0
  98. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/measures.py +0 -0
  99. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/minimal_generative_model.py +0 -0
  100. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/mixed_state.py +0 -0
  101. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/moore.py +0 -0
  102. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/nmachine.py +0 -0
  103. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/nmachine_construction.py +0 -0
  104. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/pfa.py +0 -0
  105. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/prob.py +0 -0
  106. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/process_equivalence.py +0 -0
  107. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/quasi_inference.py +0 -0
  108. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/quasi_realization.py +0 -0
  109. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stack_hmm.py +0 -0
  110. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stack_inference.py +0 -0
  111. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stationary.py +0 -0
  112. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stochastic.py +0 -0
  113. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/topological_epsilon_enumeration.py +0 -0
  114. {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/words.py +0 -0
  115. {sofic-0.1.0 → sofic-0.2.0}/sofic/graph.py +0 -0
  116. {sofic-0.1.0 → sofic-0.2.0}/sofic/indexing.py +0 -0
  117. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/__init__.py +0 -0
  118. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/__init__.py +0 -0
  119. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/comparison.py +0 -0
  120. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/counts.py +0 -0
  121. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/diversity.py +0 -0
  122. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/epsilon.py +0 -0
  123. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/hdp_hmm.py +0 -0
  124. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/markov.py +0 -0
  125. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/pymc_backend.py +0 -0
  126. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/stack_hmm.py +0 -0
  127. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/model_selection.py +0 -0
  128. {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/spectral.py +0 -0
  129. {sofic-0.1.0 → sofic-0.2.0}/sofic/operations.py +0 -0
  130. {sofic-0.1.0 → sofic-0.2.0}/sofic/properties.py +0 -0
  131. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/algorithms.py +0 -0
  132. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/base.py +0 -0
  133. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/cover_construction.py +0 -0
  134. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/dyck_algorithms.py +0 -0
  135. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/dyck_enumeration.py +0 -0
  136. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/markov_dyck.py +0 -0
  137. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/parry_construction.py +0 -0
  138. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sft.py +0 -0
  139. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sft_construction.py +0 -0
  140. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sliding_block_code.py +0 -0
  141. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sofic.py +0 -0
  142. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sofic_dyck.py +0 -0
  143. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sofic_relation.py +0 -0
  144. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/textile.py +0 -0
  145. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/tmc.py +0 -0
  146. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/tmc_construction.py +0 -0
  147. {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/topological_anatomy.py +0 -0
  148. {sofic-0.1.0 → sofic-0.2.0}/sofic/states.py +0 -0
  149. {sofic-0.1.0 → sofic-0.2.0}/sofic/testing/__init__.py +0 -0
  150. {sofic-0.1.0 → sofic-0.2.0}/sofic/testing/strategies.py +0 -0
  151. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/__init__.py +0 -0
  152. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_context.py +0 -0
  153. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_edge.py +0 -0
  154. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_format.py +0 -0
  155. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_labels.py +0 -0
  156. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_names.py +0 -0
  157. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_rational.py +0 -0
  158. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_tikz_compile.py +0 -0
  159. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_tikz_format.py +0 -0
  160. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_tikz_layout.py +0 -0
  161. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/assets/vaucanson.tikz +0 -0
  162. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/graphviz.py +0 -0
  163. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/idiagram.py +0 -0
  164. {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/tikz.py +0 -0
  165. {sofic-0.1.0 → sofic-0.2.0}/tests/__init__.py +0 -0
  166. {sofic-0.1.0 → sofic-0.2.0}/tests/conftest.py +0 -0
  167. {sofic-0.1.0 → sofic-0.2.0}/tests/test_active_learning.py +0 -0
  168. {sofic-0.1.0 → sofic-0.2.0}/tests/test_algorithms.py +0 -0
  169. {sofic-0.1.0 → sofic-0.2.0}/tests/test_bayesian_inference.py +0 -0
  170. {sofic-0.1.0 → sofic-0.2.0}/tests/test_bidirectional_epsilon.py +0 -0
  171. {sofic-0.1.0 → sofic-0.2.0}/tests/test_bidirectional_hypothesis.py +0 -0
  172. {sofic-0.1.0 → sofic-0.2.0}/tests/test_block_convergence.py +0 -0
  173. {sofic-0.1.0 → sofic-0.2.0}/tests/test_block_entropy.py +0 -0
  174. {sofic-0.1.0 → sofic-0.2.0}/tests/test_buchi.py +0 -0
  175. {sofic-0.1.0 → sofic-0.2.0}/tests/test_channel_measures.py +0 -0
  176. {sofic-0.1.0 → sofic-0.2.0}/tests/test_cm_gap_measures.py +0 -0
  177. {sofic-0.1.0 → sofic-0.2.0}/tests/test_conversions.py +0 -0
  178. {sofic-0.1.0 → sofic-0.2.0}/tests/test_covers.py +0 -0
  179. {sofic-0.1.0 → sofic-0.2.0}/tests/test_dfa.py +0 -0
  180. {sofic-0.1.0 → sofic-0.2.0}/tests/test_dfasat.py +0 -0
  181. {sofic-0.1.0 → sofic-0.2.0}/tests/test_edge_machine.py +0 -0
  182. {sofic-0.1.0 → sofic-0.2.0}/tests/test_epsilon_inference.py +0 -0
  183. {sofic-0.1.0 → sofic-0.2.0}/tests/test_epsilon_transducer.py +0 -0
  184. {sofic-0.1.0 → sofic-0.2.0}/tests/test_epsilon_transducer_inference.py +0 -0
  185. {sofic-0.1.0 → sofic-0.2.0}/tests/test_examples.py +0 -0
  186. {sofic-0.1.0 → sofic-0.2.0}/tests/test_examples_nrps.py +0 -0
  187. {sofic-0.1.0 → sofic-0.2.0}/tests/test_graph.py +0 -0
  188. {sofic-0.1.0 → sofic-0.2.0}/tests/test_hdp_hmm.py +0 -0
  189. {sofic-0.1.0 → sofic-0.2.0}/tests/test_hmm_inference.py +0 -0
  190. {sofic-0.1.0 → sofic-0.2.0}/tests/test_icdfa.py +0 -0
  191. {sofic-0.1.0 → sofic-0.2.0}/tests/test_information_anatomy.py +0 -0
  192. {sofic-0.1.0 → sofic-0.2.0}/tests/test_information_anatomy_hypothesis.py +0 -0
  193. {sofic-0.1.0 → sofic-0.2.0}/tests/test_information_diagram.py +0 -0
  194. {sofic-0.1.0 → sofic-0.2.0}/tests/test_languages.py +0 -0
  195. {sofic-0.1.0 → sofic-0.2.0}/tests/test_learning.py +0 -0
  196. {sofic-0.1.0 → sofic-0.2.0}/tests/test_lumping.py +0 -0
  197. {sofic-0.1.0 → sofic-0.2.0}/tests/test_markov.py +0 -0
  198. {sofic-0.1.0 → sofic-0.2.0}/tests/test_markov_dyck.py +0 -0
  199. {sofic-0.1.0 → sofic-0.2.0}/tests/test_mealy_hmm.py +0 -0
  200. {sofic-0.1.0 → sofic-0.2.0}/tests/test_measures.py +0 -0
  201. {sofic-0.1.0 → sofic-0.2.0}/tests/test_minimal_generative_model.py +0 -0
  202. {sofic-0.1.0 → sofic-0.2.0}/tests/test_mixed_state.py +0 -0
  203. {sofic-0.1.0 → sofic-0.2.0}/tests/test_mixed_state_recurrent.py +0 -0
  204. {sofic-0.1.0 → sofic-0.2.0}/tests/test_model_selection.py +0 -0
  205. {sofic-0.1.0 → sofic-0.2.0}/tests/test_moore_hmm.py +0 -0
  206. {sofic-0.1.0 → sofic-0.2.0}/tests/test_nfa.py +0 -0
  207. {sofic-0.1.0 → sofic-0.2.0}/tests/test_nmachine.py +0 -0
  208. {sofic-0.1.0 → sofic-0.2.0}/tests/test_nwa.py +0 -0
  209. {sofic-0.1.0 → sofic-0.2.0}/tests/test_observation.py +0 -0
  210. {sofic-0.1.0 → sofic-0.2.0}/tests/test_pfa.py +0 -0
  211. {sofic-0.1.0 → sofic-0.2.0}/tests/test_posterior_diversity.py +0 -0
  212. {sofic-0.1.0 → sofic-0.2.0}/tests/test_processes_port.py +0 -0
  213. {sofic-0.1.0 → sofic-0.2.0}/tests/test_properties.py +0 -0
  214. {sofic-0.1.0 → sofic-0.2.0}/tests/test_quasi_realization.py +0 -0
  215. {sofic-0.1.0 → sofic-0.2.0}/tests/test_reverse.py +0 -0
  216. {sofic-0.1.0 → sofic-0.2.0}/tests/test_rfsa.py +0 -0
  217. {sofic-0.1.0 → sofic-0.2.0}/tests/test_sft.py +0 -0
  218. {sofic-0.1.0 → sofic-0.2.0}/tests/test_shift_examples.py +0 -0
  219. {sofic-0.1.0 → sofic-0.2.0}/tests/test_sliding_block_code.py +0 -0
  220. {sofic-0.1.0 → sofic-0.2.0}/tests/test_smoke.py +0 -0
  221. {sofic-0.1.0 → sofic-0.2.0}/tests/test_sofic.py +0 -0
  222. {sofic-0.1.0 → sofic-0.2.0}/tests/test_sofic_dyck.py +0 -0
  223. {sofic-0.1.0 → sofic-0.2.0}/tests/test_sofic_relation.py +0 -0
  224. {sofic-0.1.0 → sofic-0.2.0}/tests/test_spectral_inference.py +0 -0
  225. {sofic-0.1.0 → sofic-0.2.0}/tests/test_stack_hmm.py +0 -0
  226. {sofic-0.1.0 → sofic-0.2.0}/tests/test_stack_inference.py +0 -0
  227. {sofic-0.1.0 → sofic-0.2.0}/tests/test_state_merging.py +0 -0
  228. {sofic-0.1.0 → sofic-0.2.0}/tests/test_stochastic.py +0 -0
  229. {sofic-0.1.0 → sofic-0.2.0}/tests/test_subsequential.py +0 -0
  230. {sofic-0.1.0 → sofic-0.2.0}/tests/test_symbolic_hmm.py +0 -0
  231. {sofic-0.1.0 → sofic-0.2.0}/tests/test_synchronization.py +0 -0
  232. {sofic-0.1.0 → sofic-0.2.0}/tests/test_testing_strategies.py +0 -0
  233. {sofic-0.1.0 → sofic-0.2.0}/tests/test_textile.py +0 -0
  234. {sofic-0.1.0 → sofic-0.2.0}/tests/test_tikz.py +0 -0
  235. {sofic-0.1.0 → sofic-0.2.0}/tests/test_tmc.py +0 -0
  236. {sofic-0.1.0 → sofic-0.2.0}/tests/test_topological_anatomy.py +0 -0
  237. {sofic-0.1.0 → sofic-0.2.0}/tests/test_topological_epsilon.py +0 -0
  238. {sofic-0.1.0 → sofic-0.2.0}/tests/test_transducer_composition.py +0 -0
  239. {sofic-0.1.0 → sofic-0.2.0}/tests/test_transducers.py +0 -0
  240. {sofic-0.1.0 → sofic-0.2.0}/tests/test_viz.py +0 -0
  241. {sofic-0.1.0 → sofic-0.2.0}/tests/test_vpa.py +0 -0
  242. {sofic-0.1.0 → sofic-0.2.0}/tests/test_words.py +0 -0
  243. {sofic-0.1.0 → sofic-0.2.0}/tests/test_yaml.py +0 -0
@@ -37,6 +37,9 @@ coverage_html_report/
37
37
  # Documentation
38
38
  docs/_build/
39
39
 
40
+ # macOS
41
+ .DS_Store
42
+
40
43
  # Misc
41
44
  .cache/
42
45
  .pypirc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sofic
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Python package for hidden Markov models, symbolic dynamics, finite state machines, and stochastic symbol generators.
5
5
  Project-URL: Homepage, https://github.com/dit/sofic
6
6
  Project-URL: Repository, https://github.com/dit/sofic
@@ -33,17 +33,23 @@ from sofic.automata import (
33
33
  UnifilarAutomaton,
34
34
  VisiblyPushdownAutomaton,
35
35
  WeightedFiniteStateTransducer,
36
+ WheelerError,
37
+ WheelerIndex,
38
+ WheelerOrder,
36
39
  automaton_to_regex,
37
40
  cartesian_product_gg,
38
41
  cartesian_product_tt,
42
+ colex_width,
39
43
  complete,
40
44
  compose_tg,
41
45
  compose_tt,
42
46
  determinize,
43
47
  equivalent,
48
+ is_wheeler,
44
49
  minimize,
45
50
  transduce_generator,
46
51
  trim,
52
+ wheeler_order,
47
53
  )
48
54
  from sofic.core import EPSILON, StateIndex, StateMachine, Transition, TransitionGraph
49
55
  from sofic.generators import (
@@ -75,6 +81,8 @@ from sofic.generators import (
75
81
  is_lumpable,
76
82
  lump,
77
83
  minimal_generative_model,
84
+ wheeler_presentation,
85
+ wheeler_statistical_complexity,
78
86
  wyner_generative_model,
79
87
  )
80
88
  from sofic.operations import reverse
@@ -93,6 +101,8 @@ from sofic.shifts import (
93
101
  SymbolicModel,
94
102
  TextileSystem,
95
103
  TopologicalMarkovChain,
104
+ WheelerCover,
105
+ wheeler_cover,
96
106
  )
97
107
 
98
108
  __all__ = [
@@ -158,15 +168,21 @@ __all__ = [
158
168
  "UnifilarAutomaton",
159
169
  "VisiblyPushdownAutomaton",
160
170
  "WeightedFiniteStateTransducer",
171
+ "WheelerCover",
172
+ "WheelerError",
173
+ "WheelerIndex",
174
+ "WheelerOrder",
161
175
  "WynerGenerativeModel",
162
176
  "automaton_to_regex",
163
177
  "cartesian_product_gg",
164
178
  "cartesian_product_tt",
179
+ "colex_width",
165
180
  "complete",
166
181
  "compose_tg",
167
182
  "compose_tt",
168
183
  "determinize",
169
184
  "equivalent",
185
+ "is_wheeler",
170
186
  "minimize",
171
187
  "from_yaml",
172
188
  "functional_generative_model",
@@ -180,6 +196,10 @@ __all__ = [
180
196
  "reverse",
181
197
  "transduce_generator",
182
198
  "trim",
199
+ "wheeler_cover",
200
+ "wheeler_order",
201
+ "wheeler_presentation",
202
+ "wheeler_statistical_complexity",
183
203
  "wyner_generative_model",
184
204
  "__version__",
185
205
  ]
@@ -106,6 +106,21 @@ from sofic.automata.vpa import (
106
106
  kleene_star_vpa,
107
107
  union_vpa,
108
108
  )
109
+ from sofic.automata.wheeler import (
110
+ WheelerError,
111
+ WheelerOrder,
112
+ colex_width,
113
+ is_input_consistent,
114
+ is_wheeler,
115
+ maximum_colex_relation,
116
+ minimum_wdfa,
117
+ wheeler_canonical_form,
118
+ wheeler_isomorphic,
119
+ wheeler_order,
120
+ wheeler_state_index,
121
+ wnfa_to_wdfa,
122
+ )
123
+ from sofic.automata.wheeler_index import WheelerIndex, wheeler_index
109
124
 
110
125
  __all__ = [
111
126
  "Atomaton",
@@ -150,8 +165,12 @@ __all__ = [
150
165
  "Transducer",
151
166
  "UnifilarAutomaton",
152
167
  "WeightedFiniteStateTransducer",
168
+ "WheelerError",
169
+ "WheelerIndex",
170
+ "WheelerOrder",
153
171
  "VisiblyPushdownAutomaton",
154
172
  "automaton_to_regex",
173
+ "colex_width",
155
174
  "cartesian_product_gg",
156
175
  "cartesian_product_tt",
157
176
  "complement_vpa",
@@ -172,7 +191,9 @@ __all__ = [
172
191
  "flags_from_string",
173
192
  "icdfa_string_to_dfa",
174
193
  "intersection_vpa",
194
+ "is_input_consistent",
175
195
  "is_well_matched",
196
+ "is_wheeler",
176
197
  "iter_icdfa",
177
198
  "iter_icdfa_empty_strings",
178
199
  "iter_idfa_strings",
@@ -189,7 +210,9 @@ __all__ = [
189
210
  "learn_mealy_lstar",
190
211
  "learn_pfa_alergia",
191
212
  "learn_sofic_dyck_shift_papni",
213
+ "maximum_colex_relation",
192
214
  "minimize",
215
+ "minimum_wdfa",
193
216
  "next_flags",
194
217
  "next_icdfa_empty_string",
195
218
  "papni_encode",
@@ -204,4 +227,10 @@ __all__ = [
204
227
  "union_vpa",
205
228
  "validate_idfa_string",
206
229
  "validate_icdfa_empty_string",
230
+ "wheeler_canonical_form",
231
+ "wheeler_index",
232
+ "wheeler_isomorphic",
233
+ "wheeler_order",
234
+ "wheeler_state_index",
235
+ "wnfa_to_wdfa",
207
236
  ]
@@ -134,7 +134,42 @@ def minimize_moore(dfa: DFA, *, alphabet: frozenset[Any] | None = None) -> DFA:
134
134
  if not states:
135
135
  return work
136
136
 
137
- partition = _initial_partition(states, work.accepting_states)
137
+ partition = _moore_refine(work, states, symbols)
138
+ return _quotient_from_partition(work, partition, symbols)
139
+
140
+
141
+ def nerode_partition(
142
+ dfa: DFA,
143
+ *,
144
+ alphabet: frozenset[Any] | None = None,
145
+ ) -> tuple[frozenset[Hashable], ...]:
146
+ """Return the Nerode classes of ``dfa``: states grouped by right language.
147
+
148
+ The DFA is completed with a trap state so that missing transitions compare
149
+ correctly, and the trap is dropped from the result. Unlike
150
+ :func:`minimize_moore`, states are *not* trimmed first, so states with an
151
+ empty right language survive as their own class. Callers that reason about
152
+ every state of a given DFA -- rather than about the language it recognizes
153
+ -- need that distinction.
154
+ """
155
+ symbols = alphabet if alphabet is not None else _effective_alphabet(dfa)
156
+ work = complete(dfa, symbols)
157
+ states = sorted(work.states(), key=repr)
158
+ if not states:
159
+ return ()
160
+
161
+ partition = _moore_refine(work, states, symbols)
162
+ blocks = (frozenset(block) - {_TRAP} for block in partition)
163
+ return tuple(block for block in blocks if block)
164
+
165
+
166
+ def _moore_refine(
167
+ dfa: DFA,
168
+ states: Sequence[Hashable],
169
+ symbols: frozenset[Any],
170
+ ) -> list[set[Hashable]]:
171
+ """Refine the accepting/non-accepting split until it is stable."""
172
+ partition = _initial_partition(states, dfa.accepting_states)
138
173
  changed = True
139
174
  while changed:
140
175
  changed = False
@@ -146,7 +181,7 @@ def minimize_moore(dfa: DFA, *, alphabet: frozenset[Any] | None = None) -> DFA:
146
181
  for piece in refined:
147
182
  groups: dict[int, set[Hashable]] = {}
148
183
  for state in piece:
149
- successor = _dfa_successor(work, state, symbol)
184
+ successor = _dfa_successor(dfa, state, symbol)
150
185
  index = -1 if successor is None else _block_index(partition, successor)
151
186
  groups.setdefault(index, set()).add(state)
152
187
  next_refined.extend(groups.values())
@@ -155,8 +190,7 @@ def minimize_moore(dfa: DFA, *, alphabet: frozenset[Any] | None = None) -> DFA:
155
190
  changed = True
156
191
  new_partition.extend(refined)
157
192
  partition = new_partition
158
-
159
- return _quotient_from_partition(work, partition, symbols)
193
+ return partition
160
194
 
161
195
 
162
196
  def minimize_hopcroft(dfa: DFA, *, alphabet: frozenset[Any] | None = None) -> DFA:
@@ -0,0 +1,102 @@
1
+ """Atomic and átomaton NFA presentations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Hashable
6
+ from typing import TYPE_CHECKING, Any, cast
7
+
8
+ from sofic.automata.dfa import DFA
9
+ from sofic.automata.languages.base import RegularLanguage
10
+ from sofic.automata.nfa import NFA
11
+ from sofic.exceptions import SoficValidationError
12
+
13
+ if TYPE_CHECKING:
14
+ from sofic.automata.observation import ObservationTable
15
+ from sofic.automata.rfsa import CanonicalRFSA
16
+
17
+
18
+ def atomic_states(nfa: NFA, *, alphabet: frozenset[Any] | None = None) -> frozenset[Hashable]:
19
+ r"""Return the states of ``nfa`` whose right language is a union of atoms.
20
+
21
+ An *atom* of a regular language is a non-empty intersection of complemented
22
+ or uncomplemented left quotients; the atoms partition :math:`\Sigma^*` and
23
+ every quotient is a union of them. A state is *atomic* when its right
24
+ language is such a union.
25
+
26
+ Implements Theorem 4 of :cite:`BrzozowskiTamm2014`: a state :math:`q` is
27
+ atomic if and only if :math:`\{s \in N^{RD} : q \in s\}` is a union of
28
+ Nerode classes of :math:`N^{RD}`, the subset construction applied to the
29
+ reversal of ``nfa``.
30
+ """
31
+ from sofic.automata.algorithms import _effective_alphabet, nerode_partition
32
+
33
+ symbols = alphabet if alphabet is not None else _effective_alphabet(nfa)
34
+ reverse_subsets = nfa.reverse().determinize(alphabet=symbols)
35
+ blocks = nerode_partition(reverse_subsets, alphabet=symbols)
36
+ # Subset-construction states are frozensets of the original NFA's states.
37
+ subsets = cast("list[frozenset[Hashable]]", list(reverse_subsets.states()))
38
+
39
+ atomic = set()
40
+ for state in nfa.states():
41
+ containing = {subset for subset in subsets if state in subset}
42
+ if all(block <= containing or block.isdisjoint(containing) for block in blocks):
43
+ atomic.add(state)
44
+ return frozenset(atomic)
45
+
46
+
47
+ def is_atomic(nfa: NFA, *, alphabet: frozenset[Any] | None = None) -> bool:
48
+ """Return whether every state of ``nfa`` has a right language of atoms.
49
+
50
+ Equivalently -- Corollary 2 of :cite:`BrzozowskiTamm2014` -- whether
51
+ :math:`N^{RD}` is minimal, which is exactly the condition under which the
52
+ subset construction applied to :math:`N^R` yields a minimal DFA.
53
+ """
54
+ return atomic_states(nfa, alphabet=alphabet) == frozenset(nfa.states())
55
+
56
+
57
+ class AtomicAutomaton(NFA):
58
+ """NFA whose states accept unions of atoms."""
59
+
60
+ def validate(self) -> None:
61
+ super().validate()
62
+ non_atomic = frozenset(self.states()) - atomic_states(self)
63
+ if non_atomic:
64
+ listed = ", ".join(sorted(map(repr, non_atomic)))
65
+ raise SoficValidationError(f"right language is not a union of atoms for state(s) {listed}")
66
+
67
+
68
+ class Atomaton(AtomicAutomaton):
69
+ """Canonical átomaton whose states are all atoms of L."""
70
+
71
+ @classmethod
72
+ def from_language(cls, language: RegularLanguage | NFA, **kwargs: Any) -> Atomaton:
73
+ from sofic.automata.canonical_extraction import atomaton_from_language
74
+
75
+ return atomaton_from_language(language)
76
+
77
+ def to_minimal_dfa_via_double_reversal(self) -> DFA:
78
+ from sofic.automata.algorithms import minimize
79
+
80
+ return minimize(self, algorithm="brzozowski")
81
+
82
+
83
+ class MaximizedPrimeAtomaton(AtomicAutomaton):
84
+ """Maximized prime átomaton — dual of the canonical RFSA."""
85
+
86
+ @classmethod
87
+ def from_language(cls, language: RegularLanguage | NFA, **kwargs: Any) -> MaximizedPrimeAtomaton:
88
+ from sofic.automata.canonical_extraction import maximized_prime_atomaton_from_language
89
+
90
+ return maximized_prime_atomaton_from_language(language)
91
+
92
+ @classmethod
93
+ def from_observation_table(cls, table: ObservationTable, **kwargs: Any) -> MaximizedPrimeAtomaton:
94
+ from sofic.automata.canonical_extraction import observation_to_maximized_prime_atomaton
95
+
96
+ return observation_to_maximized_prime_atomaton(table)
97
+
98
+ @classmethod
99
+ def from_canonical_rfsa(cls, rfsa: CanonicalRFSA, **kwargs: Any) -> MaximizedPrimeAtomaton:
100
+ from sofic.automata.canonical_dual import dual_atomaton_from_rfsa
101
+
102
+ return dual_atomaton_from_rfsa(rfsa)
@@ -40,11 +40,18 @@ def canonical_rfsa_from_language(language: RegularLanguage | NFA | DFA) -> Canon
40
40
 
41
41
 
42
42
  def atomaton_from_language(language: RegularLanguage | NFA | DFA) -> Atomaton:
43
- """Build átomaton via double-reversal pipeline."""
43
+ """Build átomaton via double-reversal pipeline.
44
+
45
+ The átomaton is the *reverse of the minimal DFA of the reverse language*
46
+ (:cite:`BrzozowskiTamm2014`, Theorem 2), so the pipeline must stop at the
47
+ reversal: determinizing once more would collapse it back to the minimal DFA
48
+ of ``language``, which is Brzozowski's minimization rather than the
49
+ átomaton.
50
+ """
44
51
  aut = _language_automaton(language)
45
52
  dfa = minimal_dfa_from_language(aut)
46
53
  rev = dfa.reverse().determinize().minimize()
47
- atom = rev.reverse().determinize()
54
+ atom = rev.reverse()
48
55
  return Atomaton(
49
56
  input_alphabet=atom.input_alphabet,
50
57
  initial_states=atom.initial_states,