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.
- {sofic-0.1.0 → sofic-0.2.0}/.gitignore +3 -0
- {sofic-0.1.0 → sofic-0.2.0}/PKG-INFO +1 -1
- {sofic-0.1.0 → sofic-0.2.0}/sofic/__init__.py +20 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/__init__.py +29 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/algorithms.py +38 -4
- sofic-0.2.0/sofic/automata/atomaton.py +102 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/canonical_extraction.py +9 -2
- sofic-0.2.0/sofic/automata/wheeler.py +697 -0
- sofic-0.2.0/sofic/automata/wheeler_index.py +291 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/base.py +36 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/__init__.py +23 -1
- {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/epsilon_machines.py +45 -0
- sofic-0.2.0/sofic/examples/tetris.py +239 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/exceptions.py +12 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/__init__.py +16 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_machine.py +61 -2
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/mixed_state_construction.py +4 -2
- sofic-0.2.0/sofic/generators/reversal.py +182 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/synchronization.py +75 -1
- sofic-0.2.0/sofic/generators/wheeler_epsilon.py +247 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/serialization.py +8 -1
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/__init__.py +16 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/covers.py +16 -0
- sofic-0.2.0/sofic/shifts/wheeler.py +242 -0
- sofic-0.2.0/tests/test_atomaton.py +149 -0
- sofic-0.2.0/tests/test_epsilon_machine.py +203 -0
- sofic-0.2.0/tests/test_tetris.py +142 -0
- sofic-0.2.0/tests/test_wheeler.py +594 -0
- sofic-0.1.0/sofic/automata/atomaton.py +0 -58
- sofic-0.1.0/sofic/generators/reversal.py +0 -66
- sofic-0.1.0/tests/test_atomaton.py +0 -33
- sofic-0.1.0/tests/test_epsilon_machine.py +0 -75
- {sofic-0.1.0 → sofic-0.2.0}/LICENSE.txt +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/README.rst +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/pyproject.toml +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/_config_simulation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/active.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/alergia.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/base.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/buchi.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/buchi_simulation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/canonical_dual.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/dfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/dfasat.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/edsm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/enumeration.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/icdfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/idfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/__init__.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/_quotient_utils.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/atoms.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/automaton_ops.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/base.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/operations.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/quotients.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/languages/residuals.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/learning.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/nfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/nwa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/nwa_simulation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/observation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/papni.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/regex.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/rfsa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/rpni.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/subsequential.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/transducer_operations.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/transducer_simulation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/transducers.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/unifilar.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/vpa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/automata/vpa_simulation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/core.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/processes.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/examples/shifts.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/_word_measures.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/alternative_complexity.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/base.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/bidirectional_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/bidirectional_epsilon_machine.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/block_convergence.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/block_entropy.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/channel_measures.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/conversions.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/directional_flow.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/edge_emissions.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/edge_machine.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_transducer.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_transducer_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/epsilon_transducer_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/hmm_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/information_diagram.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/lumping.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/markov.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/mealy.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/measures.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/minimal_generative_model.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/mixed_state.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/moore.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/nmachine.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/nmachine_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/pfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/prob.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/process_equivalence.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/quasi_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/quasi_realization.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stack_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stack_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stationary.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/stochastic.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/topological_epsilon_enumeration.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/generators/words.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/graph.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/indexing.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/__init__.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/__init__.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/comparison.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/counts.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/diversity.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/epsilon.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/hdp_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/markov.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/pymc_backend.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/bayesian/stack_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/model_selection.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/inference/spectral.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/operations.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/properties.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/algorithms.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/base.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/cover_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/dyck_algorithms.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/dyck_enumeration.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/markov_dyck.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/parry_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sft.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sft_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sliding_block_code.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sofic.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sofic_dyck.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/sofic_relation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/textile.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/tmc.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/tmc_construction.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/shifts/topological_anatomy.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/states.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/testing/__init__.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/testing/strategies.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/__init__.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_context.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_edge.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_format.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_labels.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_names.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_rational.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_tikz_compile.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_tikz_format.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/_tikz_layout.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/assets/vaucanson.tikz +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/graphviz.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/idiagram.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/sofic/viz/tikz.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/__init__.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/conftest.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_active_learning.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_algorithms.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_bayesian_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_bidirectional_epsilon.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_bidirectional_hypothesis.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_block_convergence.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_block_entropy.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_buchi.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_channel_measures.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_cm_gap_measures.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_conversions.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_covers.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_dfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_dfasat.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_edge_machine.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_epsilon_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_epsilon_transducer.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_epsilon_transducer_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_examples.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_examples_nrps.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_graph.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_hdp_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_hmm_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_icdfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_information_anatomy.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_information_anatomy_hypothesis.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_information_diagram.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_languages.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_learning.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_lumping.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_markov.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_markov_dyck.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_mealy_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_measures.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_minimal_generative_model.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_mixed_state.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_mixed_state_recurrent.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_model_selection.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_moore_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_nfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_nmachine.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_nwa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_observation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_pfa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_posterior_diversity.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_processes_port.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_properties.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_quasi_realization.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_reverse.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_rfsa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_sft.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_shift_examples.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_sliding_block_code.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_smoke.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_sofic.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_sofic_dyck.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_sofic_relation.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_spectral_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_stack_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_stack_inference.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_state_merging.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_stochastic.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_subsequential.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_symbolic_hmm.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_synchronization.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_testing_strategies.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_textile.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_tikz.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_tmc.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_topological_anatomy.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_topological_epsilon.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_transducer_composition.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_transducers.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_viz.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_vpa.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_words.py +0 -0
- {sofic-0.1.0 → sofic-0.2.0}/tests/test_yaml.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sofic
|
|
3
|
-
Version: 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 =
|
|
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(
|
|
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()
|
|
54
|
+
atom = rev.reverse()
|
|
48
55
|
return Atomaton(
|
|
49
56
|
input_alphabet=atom.input_alphabet,
|
|
50
57
|
initial_states=atom.initial_states,
|