Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME#v}"
built=$(ls dist/pensive-*.tar.gz | sed -E 's|.*/pensive-(.+)\.tar\.gz|\1|')
built=$(ls dist/sofic-*.tar.gz | sed -E 's|.*/sofic-(.+)\.tar\.gz|\1|')
echo "tag=$tag built=$built"
[ "$tag" = "$built" ] || { echo "::error::Built version $built != tag $tag"; exit 1; }

Expand All @@ -42,7 +42,7 @@ jobs:
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/pensive
url: https://pypi.org/p/sofic
permissions:
id-token: write
contents: write
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ MANIFEST
.venv/

# Packaging
pensive.egg-info/
sofic.egg-info/

# Test and coverage
.coverage*
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Contributing
------------

If you'd like a feature added to ``pensive`` or notice any problems, please file an issue, or, even better, open a pull request. We'll work with you to ensure that the code is tested and documented.
If you'd like a feature added to ``sofic`` or notice any problems, please file an issue, or, even better, open a pull request. We'll work with you to ensure that the code is tested and documented.

It's appropriate to file an issue when you encounter a problem with `pensive`. Be sure to include
It's appropriate to file an issue when you encounter a problem with `sofic`. Be sure to include

* the `pensive` version you're using
* the `sofic` version you're using
* the operating system and Python version
* full tracebacks

Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2026, pensive contributors.
Copyright (c) 2026, sofic contributors.
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
62 changes: 31 additions & 31 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
=======
pensive
sofic
=======

``pensive`` is a Python package for hidden Markov models, symbolic dynamics,
``sofic`` is a Python package for hidden Markov models, symbolic dynamics,
finite state machines, and other stochastic symbol generators.

Basic Information
Expand All @@ -11,12 +11,12 @@ Basic Information
Documentation
~~~~~~~~~~~~~~

https://pensive.readthedocs.io
https://sofic.readthedocs.io

Repository
~~~~~~~~~~

https://github.com/dit/pensive
https://github.com/dit/sofic

Dependencies
~~~~~~~~~~~~
Expand All @@ -35,8 +35,8 @@ Clone the repository and install development dependencies with ``uv``:

.. code-block:: bash

git clone https://github.com/dit/pensive.git
cd pensive
git clone https://github.com/dit/sofic.git
cd sofic
uv sync --extra dev

Run tests with ``uv run pytest``. See the ``generalinfo`` page in the Sphinx
Expand All @@ -47,7 +47,7 @@ Introduction

Many natural and engineered processes produce sequences of symbols whose
statistics are governed by latent structure: hidden states, transition rules,
or algebraic constraints on allowed paths. ``pensive`` collects algorithms and
or algebraic constraints on allowed paths. ``sofic`` collects algorithms and
data structures for representing, simulating, and analyzing such generators
behind a single, composable Python API.

Expand All @@ -56,15 +56,15 @@ construction, validation, simulation, visualization, (de)serialization, and a
large library of structural and information-theoretic measures. The three
main families are:

* **Stochastic generators** (``pensive.generators``) — Markov chains, hidden
* **Stochastic generators** (``sofic.generators``) — Markov chains, hidden
Markov models (Moore and Mealy presentations), ε-machines, probabilistic
finite automata, mixed-state presentations, and quasiprobabilistic
generators. These assign probabilities to sequences.
* **Finite automata** (``pensive.automata``) — DFAs, NFAs, transducers
* **Finite automata** (``sofic.automata``) — DFAs, NFAs, transducers
(Mealy/Moore machines), regular languages, Büchi automata, visibly pushdown
and nested-word automata, and residual finite-state automata. These recognize
or transform languages.
* **Symbolic shifts** (``pensive.shifts``) — shifts of finite type, sofic
* **Symbolic shifts** (``sofic.shifts``) — shifts of finite type, sofic
shifts, topological Markov chains, and Dyck/sofic-Dyck shifts. These describe
the *support* (set of allowed sequences) of a process.

Expand All @@ -77,15 +77,15 @@ Installation

.. code-block:: bash

pip install pensive
pip install sofic

Optional extras:

* ``pensive[viz]`` — Graphviz diagrams in terminals and Jupyter
* ``pensive[bayes]`` — PyMC/ArviZ backends for Bayesian inference
* ``pensive[test]`` — pytest, hypothesis, and graphviz for the test suite
* ``pensive[docs]`` — Sphinx, IPython, and matplotlib for the docs
* ``pensive[dev]`` — linting, type checking, docs, and all of the above
* ``sofic[viz]`` — Graphviz diagrams in terminals and Jupyter
* ``sofic[bayes]`` — PyMC/ArviZ backends for Bayesian inference
* ``sofic[test]`` — pytest, hypothesis, and graphviz for the test suite
* ``sofic[docs]`` — Sphinx, IPython, and matplotlib for the docs
* ``sofic[dev]`` — linting, type checking, docs, and all of the above

Quickstart
----------
Expand All @@ -102,7 +102,7 @@ Stochastic generators

.. code-block:: python

from pensive import MarkovChain
from sofic import MarkovChain

mc = MarkovChain(initial_distribution={"sunny": 0.5, "rainy": 0.5})
mc.add_transition("sunny", "sunny", 0.9)
Expand All @@ -120,7 +120,7 @@ states and ``P(target | source)`` on edges:

.. code-block:: python

from pensive import MooreHMM
from sofic import MooreHMM

moore = MooreHMM(
observation_alphabet=frozenset({"H", "T"}),
Expand All @@ -144,7 +144,7 @@ states and ``P(target | source)`` on edges:

.. code-block:: python

from pensive import MealyHMM
from sofic import MealyHMM

gm = MealyHMM(
observation_alphabet=frozenset({0, 1}),
Expand All @@ -159,16 +159,16 @@ states and ``P(target | source)`` on edges:
gm.is_unifilar() # True
gm.word_probability([1, 0, 1]) # 0.1667

Many canonical models ship in ``pensive.examples``, so the golden mean is
also just ``from pensive.examples import golden_mean; gm = golden_mean(0.5)``.
Many canonical models ship in ``sofic.examples``, so the golden mean is
also just ``from sofic.examples import golden_mean; gm = golden_mean(0.5)``.

**ε-machine** — the minimal unifilar (causal-state) presentation of a stationary
process. Build one from any HMM, from an observed sequence, or directly, and
read off computational-mechanics quantities:

.. code-block:: python

from pensive import EpsilonMachine
from sofic import EpsilonMachine

eps = EpsilonMachine.from_hmm(gm) # minimize an HMM presentation
# eps = EpsilonMachine.from_sequence(data, method="cssr", Lmax=4) # infer
Expand All @@ -187,7 +187,7 @@ be checked as you go):

.. code-block:: python

from pensive import DFA
from sofic import DFA

dfa = DFA(
input_alphabet=frozenset({"a", "b"}),
Expand All @@ -212,7 +212,7 @@ when you need one:

.. code-block:: python

from pensive import NFA
from sofic import NFA

nfa = NFA(
input_alphabet=frozenset({"a", "b"}),
Expand All @@ -233,7 +233,7 @@ inverts bits:

.. code-block:: python

from pensive import MealyMachine
from sofic import MealyMachine

inv = MealyMachine(
input_alphabet=frozenset({"0", "1"}),
Expand All @@ -258,7 +258,7 @@ forbidden words. The golden-mean shift forbids ``11``:

.. code-block:: python

from pensive import ShiftOfFiniteType
from sofic import ShiftOfFiniteType

sft = ShiftOfFiniteType.from_forbidden_words(
{("1", "1")},
Expand All @@ -276,7 +276,7 @@ topological entropy or extract the measure of maximal entropy:
.. code-block:: python

import numpy as np
from pensive import TopologicalMarkovChain
from sofic import TopologicalMarkovChain

tmc = TopologicalMarkovChain.from_adjacency(
np.array([[1, 1], [1, 0]], dtype=float), # golden-mean adjacency
Expand All @@ -292,7 +292,7 @@ NFA). This is the even shift (even-length runs of ``0`` between ``1``\ s):

.. code-block:: python

from pensive import SoficShift
from sofic import SoficShift

even = SoficShift(symbol_alphabet=frozenset({0, 1}))
even.add_transition("even", "even", 0)
Expand Down Expand Up @@ -342,7 +342,7 @@ Every model can also be round-tripped through YAML:

text = eps.to_yaml()
restored = EpsilonMachine.from_yaml(text)
# or: pensive.model_to_yaml(eps) / pensive.model_from_yaml(text)
# or: sofic.model_to_yaml(eps) / sofic.model_from_yaml(text)

Information anatomy (advanced)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -352,7 +352,7 @@ transient-information anatomy of a process (James, Burke & Crutchfield, 2013):

.. code-block:: python

from pensive.examples import golden_mean_bidirectional, tent_map_misiurewicz_bidirectional
from sofic.examples import golden_mean_bidirectional, tent_map_misiurewicz_bidirectional

bidir = golden_mean_bidirectional(0.5)
bidir.statistical_complexity() # 1.5850 bits (C±)
Expand All @@ -366,4 +366,4 @@ transient-information anatomy of a process (James, Burke & Crutchfield, 2013):
License
-------

``pensive`` is distributed under the BSD 3-Clause License; see ``LICENSE.txt``.
``sofic`` is distributed under the BSD 3-Clause License; see ``LICENSE.txt``.
8 changes: 4 additions & 4 deletions docs/automata/algorithms.rst
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
.. algorithms.rst
.. py:module:: pensive.automata.algorithms
.. py:module:: sofic.automata.algorithms

**********
Algorithms
**********

Standard automata operations on :class:`~pensive.automata.base.LabeledAutomaton`
Standard automata operations on :class:`~sofic.automata.base.LabeledAutomaton`
instances. The implementations cover subset construction, DFA equivalence and
minimization, Brzozowski double reversal, Moore refinement, Hopcroft refinement,
and state-elimination conversion to regular expressions
:cite:`RabinScott1959,Brzozowski1962,Moore1956,Hopcroft1971,Kleene1956`.

.. ipython::

In [1]: from pensive.automata import DFA, trim, minimize, equivalent
In [1]: from sofic.automata import DFA, trim, minimize, equivalent

In [2]: dfa = DFA(
...: input_alphabet=frozenset({0}),
Expand Down Expand Up @@ -43,6 +43,6 @@ API
.. autofunction:: minimize_moore
.. autofunction:: minimize_brzozowski
.. autofunction:: equivalent
.. autofunction:: pensive.automata.regex.automaton_to_regex
.. autofunction:: sofic.automata.regex.automaton_to_regex

.. autodata:: MinimizationAlgorithm
2 changes: 1 addition & 1 deletion docs/automata/atomaton.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.. atomaton.rst
.. py:module:: pensive.automata.atomaton
.. py:module:: sofic.automata.atomaton

********
Átomaton
Expand Down
2 changes: 1 addition & 1 deletion docs/automata/automata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Automata
********

The :mod:`pensive.automata` package provides finite automata, transducers, and
The :mod:`sofic.automata` package provides finite automata, transducers, and
regular-language algebra. The finite-automata foundations follow the classical
DFA/NFA and regular-language literature :cite:`RabinScott1959,HopcroftUllman1979`.

Expand Down
6 changes: 3 additions & 3 deletions docs/automata/buchi.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.. buchi.rst
.. py:module:: pensive.automata.buchi
.. py:module:: sofic.automata.buchi

*****************
Büchi Automata
Expand All @@ -14,5 +14,5 @@ API
.. autoclass:: BuchiAutomaton
:members: accepts_lasso, accepts_omega

.. autofunction:: pensive.automata.buchi_simulation.accepts_lasso_buchi
.. autofunction:: pensive.automata.buchi_simulation.accepts_omega_buchi
.. autofunction:: sofic.automata.buchi_simulation.accepts_lasso_buchi
.. autofunction:: sofic.automata.buchi_simulation.accepts_omega_buchi
4 changes: 2 additions & 2 deletions docs/automata/dfa.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.. dfa.rst
.. py:module:: pensive.automata.dfa
.. py:module:: sofic.automata.dfa

***
DFA
Expand All @@ -11,7 +11,7 @@ and no ε-transitions, following the standard finite-automata model

.. ipython::

In [1]: from pensive.automata import DFA
In [1]: from sofic.automata import DFA

In [2]: dfa = DFA(
...: input_alphabet=frozenset({0, 1}),
Expand Down
10 changes: 5 additions & 5 deletions docs/automata/icdfa.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.. icdfa.rst
.. py:module:: pensive.automata.icdfa
.. py:module:: sofic.automata.icdfa

*****
ICDFA
Expand All @@ -23,7 +23,7 @@ API
.. autofunction:: count_icdfa
.. autofunction:: count_icdfa_empty

.. autofunction:: pensive.automata.idfa.iter_idfa_strings
.. autofunction:: pensive.automata.idfa.rank_idfa_string
.. autofunction:: pensive.automata.idfa.unrank_idfa_string
.. autofunction:: pensive.automata.idfa.count_accessible_idfa
.. autofunction:: sofic.automata.idfa.iter_idfa_strings
.. autofunction:: sofic.automata.idfa.rank_idfa_string
.. autofunction:: sofic.automata.idfa.unrank_idfa_string
.. autofunction:: sofic.automata.idfa.count_accessible_idfa
Loading
Loading