Skip to content

Initial support for Implicit TPMs #105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 191 commits into
base: feature/iit-4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
191 commits
Select commit Hold shift + click to select a range
a9be5c2
`tpm.ProxyMetaclass`: Change list to generator expression
isacdaavid Jan 3, 2023
d0000b1
`tpm`: Improve documentation
isacdaavid Jan 3, 2023
39796ca
Move TPM documentation to `tpm.ExplicitTPM` class
isacdaavid Jan 3, 2023
a357031
`tpm.ExplicitTPM`: Remove superfluous call to super constructor
isacdaavid Jan 5, 2023
b15924a
`tpm.ExplicitTPM`: Preserve column alignment in string representation.
isacdaavid Jan 5, 2023
9c349e2
`subsystem`: Complete `ExplicitTPM.enforce` cleanup
isacdaavid Jan 6, 2023
91772ac
Refactor `Node` to use xarray DataArray (accessor namespace for now)
isacdaavid Jan 7, 2023
db0a505
`Node`: Add support for multivalued and heterogeneous units
isacdaavid Jan 10, 2023
b77efbb
`Node`: Fix docstring
isacdaavid Jan 11, 2023
890ed62
`Node.node`: Singleton coords aren't necessarily due to marginalization
isacdaavid Jan 11, 2023
f31a38a
`tpm`: Add abstract class `ImplicitTPM` and decorate for `xr.Dataset`
isacdaavid Jan 12, 2023
5c8c626
Refactor `Network` and `Node` for future implicit TPM support
isacdaavid Jan 13, 2023
7e43f6f
Send duplicate state space filtering to `utils.build_state_space()`
isacdaavid Jan 16, 2023
b3687c7
`Network.__init__`: Avoid transient storage of nodes beyond the TPM
isacdaavid Jan 16, 2023
34e7032
`Network.to_json` Include state_space attribute.
isacdaavid Jan 16, 2023
0dd6036
`Network.__len__`: Go back to counting nodes in the TPM (now a Dataset).
isacdaavid Jan 16, 2023
ed3bce3
build_state_space(): Fix Union declaration
dviggiano Jan 17, 2023
3c9760c
Fix widespread Union declaration typo
dviggiano Jan 17, 2023
5c1f1b5
Squeeze singleton dimensions in `Node`
isacdaavid Jan 17, 2023
5351aec
Implement ImplicitTPM validation
isacdaavid Jan 18, 2023
bf64cfc
Merge remote-tracking branch
isacdaavid Jan 18, 2023
955fe69
Update `Network` `__eq__()` method.
isacdaavid Jan 18, 2023
03f6a04
`Network`: revert to a `__repr__` ammenable to JSON serialization.
isacdaavid Jan 18, 2023
d192cbf
Miscellaneous bug fixes in `Node` attribute setters and getters.
isacdaavid Jan 18, 2023
60e67ec
`tpm.ImplicitTPM`: Implement condition_tpm()
isacdaavid Jan 18, 2023
6301380
Minor import and docstring cleanup in `subsystem`
isacdaavid Jan 18, 2023
f4b7d74
Change state space structure to use a dictionary.
isacdaavid Jan 27, 2023
1687293
Revert to using dummy singleton dimensions in multidimensional node TPMs
isacdaavid Feb 2, 2023
719cb7c
`Node._hash`: temporary workaround when the TPM array is mutable.
isacdaavid Feb 2, 2023
db89127
Implement function to properly unalign DataArray's
isacdaavid Feb 17, 2023
819b34f
`Node.streamline()`: use more consistent variable declarations.
isacdaavid Feb 20, 2023
fd35bcc
Avoid xarray Dataset altogether
isacdaavid Feb 20, 2023
ebe1c3a
Network.__init__(): Handle network as tpm argument
dviggiano Feb 20, 2023
db8ce13
Fix error message
dviggiano Feb 20, 2023
52adc21
Merge pull request #87 from dviggiano/feature/tpm-class
dviggiano Feb 20, 2023
ded144b
`Network`: Fix `build_cm()` when None is provided.
isacdaavid Feb 20, 2023
db677d1
`Network.__init__()`: maximum line length.
isacdaavid Feb 20, 2023
a6c3b3a
`Network.__init__()`: Pass xarray nodes to the `ImplicitTPM` construc…
isacdaavid Feb 21, 2023
3ca0284
Implement proper indexing for the `ImplicitTPM`
isacdaavid Feb 21, 2023
83c64bb
`Node.project_index()`: remove leftover print statements.
isacdaavid Feb 22, 2023
88989c3
`tpm`: miscellaneous cleanup.
isacdaavid Feb 22, 2023
47e09f3
`tpm.ImplicitTPM`: implement __len__ method.
isacdaavid Feb 22, 2023
150b8c3
`Node.project_index`: make positional indexing consistent with name i…
isacdaavid Feb 22, 2023
8d89879
`tpm.ImplicitTPM: implement ndim property`
isacdaavid Feb 22, 2023
a615250
Modularize code to compute the shape of an `ImplicitTPM`
isacdaavid Feb 22, 2023
92b216d
`tpm`: refactor `ImplicitTPM.condition_tpm()`
isacdaavid Feb 23, 2023
102691d
Handle potential KeyError if user passes nonexisting dimension labels.
isacdaavid Feb 23, 2023
2efa780
`Subsystem`: remove unused property.
isacdaavid Feb 23, 2023
cb6f289
Fix `ImplicitTPM.condition_tpm` and generalize argument
isacdaavid Feb 24, 2023
a3deedf
Filter `.nodes` attribute based on membership to `Subsystem.node_indi…
isacdaavid Feb 24, 2023
d0c4787
Call `Node` directly and `DataArray` through callback-like reference …
isacdaavid Feb 24, 2023
2630552
Network.__init__(): Verify nodes against CM
dviggiano Feb 27, 2023
d93f037
Merge branch 'feature/tpm-class' of https://github.com/dviggiano/pyph…
dviggiano Feb 27, 2023
8d27f2c
Fix bad merge
dviggiano Feb 27, 2023
074dcfb
Network: Include attrs in repr, remove redundancy
dviggiano Feb 27, 2023
eb5fac6
Network.__init__(): Exclude cache
dviggiano Feb 27, 2023
0621de5
Network.__init__(): Properly grab CM columns
dviggiano Feb 27, 2023
d700e87
Update error message
dviggiano Feb 27, 2023
05165c5
Fix operator, error message
dviggiano Feb 27, 2023
63ba053
Fix _state_space assignment
dviggiano Feb 27, 2023
2ab4c4a
Merge pull request #88 from dviggiano/feature/tpm-class
dviggiano Feb 27, 2023
9da3677
Fix bug in `tpm.ImplicitTPM.shape`
isacdaavid Feb 27, 2023
3c32d34
Network._build_cm(): Account for multiple nodes
dviggiano Feb 27, 2023
6e3fd48
Network.__init__(): Assign attributes in all cases
dviggiano Feb 27, 2023
694b681
Fix redundancy
dviggiano Feb 27, 2023
87f939c
Merge branch 'wmayner:feature/tpm-class' into feature/tpm-class
dviggiano Feb 27, 2023
a9ef879
Merge pull request #89 from dviggiano/feature/tpm-class
dviggiano Feb 27, 2023
23918bd
Merge branch 'feature/tpm-class' of github.com:wmayner/pyphi into fea…
isacdaavid Feb 27, 2023
95e7b31
network.py: format source code
isacdaavid Mar 1, 2023
8425577
Fix bug in `Network._build_cm()` for explicit TPMs.
isacdaavid Mar 1, 2023
fa535ad
Cosmetic refactoring of `Network._build_cm()`
isacdaavid Mar 1, 2023
75e5fe1
Don't reference `self.cm` before it has been set.
isacdaavid Mar 1, 2023
1a6d7ec
_build_cm(): Should use cm param, not self.cm
dviggiano Mar 1, 2023
6099530
Merge branch 'feature/tpm-class' of https://github.com/dviggiano/pyph…
dviggiano Mar 1, 2023
f2be2d4
test_network(): Add test_build_cm_implicit_tpm()
dviggiano Mar 1, 2023
127303a
Merge pull request #90 from dviggiano/feature/tpm-class
dviggiano Mar 1, 2023
ad75e77
test_network: Add test_build_cm_explicit_tpm()
dviggiano Mar 1, 2023
bac25b7
DictCache: allow for reconstruction with __repr__
dviggiano Mar 1, 2023
40a4fe5
test_network.test_build_cm_explicit_tpm(); Allow for DictCache recons…
dviggiano Mar 1, 2023
7c89049
test_build_cm_explicit_tpm(): Use np.ones()
dviggiano Mar 1, 2023
e981209
Merge pull request #92 from dviggiano/feature/tpm-class
dviggiano Mar 1, 2023
902c90c
Don't assume network state_space dict is ordered.
isacdaavid Mar 1, 2023
cbe9255
test_build_cm(): Combine into one test
dviggiano Mar 1, 2023
328c965
Merge pull request #93 from dviggiano/feature/tpm-class
dviggiano Mar 1, 2023
f959a5d
Network.__repr__(): Only use dict for state_space
dviggiano Mar 1, 2023
0de955f
Merge branch 'wmayner:feature/tpm-class' into feature/tpm-class
dviggiano Mar 1, 2023
9b8ba10
Merge pull request #94 from dviggiano/feature/tpm-class
dviggiano Mar 1, 2023
434cd29
Set the state of the `subsystem` nodes.
isacdaavid Mar 1, 2023
aa8e67f
test_network: Add test_init_with_explicit_tpm()
dviggiano Mar 1, 2023
a36e2f8
Merge pull request #95 from dviggiano/feature/tpm-class
dviggiano Mar 1, 2023
8a1c3fd
Change semantics of Node.tpm for direct access to ExplicitTPM methods.
isacdaavid Mar 2, 2023
b299e3a
Merge branch 'feature/tpm-class' of github.com:wmayner/pyphi into fea…
isacdaavid Mar 2, 2023
50faed6
Avoid reuse of subsystem nodes after cut
isacdaavid Mar 2, 2023
9fd3b11
Guarantee marginalization of non_inputs when generating `Node`s.
isacdaavid Mar 2, 2023
3011435
Inherit `TPM.tpm_indices()` and make it agnostic to state cardinality
isacdaavid Mar 3, 2023
dfdde3a
Rehabilitate validate.network()
isacdaavid Mar 4, 2023
37da9b7
`test_network.py`: add fixture for making implicit TPMs
isacdaavid Mar 7, 2023
1671e08
Infer network shape from nodes' last dimension.
isacdaavid Mar 7, 2023
68e4808
Deduplicate code and turn into `ImplicitTPM.shapes` attribute
isacdaavid Mar 8, 2023
38740ae
Add equals method to ImplicitTPM
dviggiano Mar 8, 2023
fe8fb01
Merge pull request #96 from dviggiano/feature/tpm-class
dviggiano Mar 8, 2023
1c79fd0
Fix bug in ImplicitTPM._node_shapes_to_shape()
isacdaavid Mar 8, 2023
d293340
Merge branch 'feature/tpm-class' of github.com:wmayner/pyphi into fea…
isacdaavid Mar 8, 2023
9c773e5
Ibidem
isacdaavid Mar 8, 2023
faa98cf
Add state space reroute
dviggiano Mar 8, 2023
9820b04
Merge pull request #97 from dviggiano/feature/tpm-class
dviggiano Mar 8, 2023
5695358
Include state_space in node declarations
dviggiano Mar 8, 2023
14df30b
Merge branch 'wmayner:feature/tpm-class' into feature/tpm-class
dviggiano Mar 8, 2023
74c66ac
Merge pull request #98 from dviggiano/feature/tpm-class
dviggiano Mar 8, 2023
59f82f0
Use `hasattr` instead of try-catch
dviggiano Mar 8, 2023
c8c2dff
Merge pull request #99 from dviggiano/feature/tpm-class
dviggiano Mar 8, 2023
81b1e18
Do not use `tpm.tpm`
dviggiano Mar 8, 2023
9dd8c10
Merge pull request #100 from dviggiano/feature/tpm-class
dviggiano Mar 8, 2023
4cc5909
`tpm.py`: extend subtpm() and reconstitute_tpm()
isacdaavid Mar 10, 2023
5b2bc17
Merge branch 'feature/tpm-class' of github.com:wmayner/pyphi into fea…
isacdaavid Mar 10, 2023
432a0a7
test_tpm.py: Convert to np.ndarray when comparing matrices.
isacdaavid Mar 14, 2023
552c4a6
tpm: inherit `infer_cm()` and `infer_edge` from parent class
isacdaavid Mar 14, 2023
6f21890
Implement `marginalize_out()` for `ImplicitTPM`
isacdaavid Mar 14, 2023
53d4e15
Fix reconstitute_tpm so that it considers singletons
isacdaavid Mar 15, 2023
2a71b04
Implement ImplicitTPM.squeeze
isacdaavid Mar 16, 2023
a49c2e9
Refactor `remove_singleton_dimensions()`
isacdaavid Mar 16, 2023
62a821e
Sync macro.py with latest TPM code
isacdaavid Mar 17, 2023
8bce05d
Fix bug in auxilary method _node_shapes_to_shape
isacdaavid Mar 19, 2023
c2cc056
Make node_labels parameter mandatory when building a state space
isacdaavid Mar 20, 2023
57c51e4
macro.py: cast TPM type if necessary
isacdaavid Mar 20, 2023
e26c555
test_node: Convert ImplicitTPMs for generate_nodes
dviggiano Mar 20, 2023
a721f4f
MacroSubsystem.nodes(): Reconstitute TPM
dviggiano Mar 20, 2023
cbfa0c2
test_macro.test_pack_attrs(): Fix TPM comparison
dviggiano Mar 20, 2023
98d309e
Merge branch 'feature/tpm-class' of https://github.com/dviggiano/pyph…
dviggiano Mar 20, 2023
a8aa4ae
generate_nodes(): Handle Implicit network TPMs
dviggiano Mar 20, 2023
6a1a4f7
Merge pull request #101 from dviggiano/feature/tpm-class
dviggiano Mar 20, 2023
057c52c
node.py: Avoid circular import
dviggiano Mar 20, 2023
69e96a8
Merge branch 'wmayner:feature/tpm-class' into feature/tpm-class
dviggiano Mar 20, 2023
5b85b06
Merge pull request #102 from dviggiano/feature/tpm-class
dviggiano Mar 20, 2023
1e22c86
Catch calls to ImplicitTPM.array_equals and route accordingly
isacdaavid Mar 20, 2023
4ea97f7
Merge branch 'feature/tpm-class' of github.com:wmayner/pyphi into fea…
isacdaavid Mar 20, 2023
317c560
Subsystem: set node TPM state early
isacdaavid Mar 20, 2023
02981cf
(Cleanup) Exclude ExplicitTPM from top-level namespace
isacdaavid Mar 20, 2023
861ef9d
TPM: allow `tpm_indices` to discard singletons
isacdaavid Mar 21, 2023
7a89612
macro: tidy remaining references to reconstitute_tpm
isacdaavid Mar 21, 2023
336ff75
Harmonize {MacroSubsystem._,ImplicitTPM.}squeeze and fix test_blackbo…
isacdaavid Mar 22, 2023
7d8e21a
validate.state_reachable(): Reconstitute TPM
dviggiano Mar 22, 2023
f19439a
Implement `ImplicitTPM.__hash__()`
dviggiano Mar 22, 2023
a4f342f
Merge pull request #103 from dviggiano/feature/tpm-class
dviggiano Mar 22, 2023
ebb68eb
ImplicitTPM.__hash__(): Fix syntax
dviggiano Mar 22, 2023
fd3b454
Merge branch 'wmayner:feature/tpm-class' into feature/tpm-class
dviggiano Mar 22, 2023
058a257
Merge pull request #104 from dviggiano/feature/tpm-class
dviggiano Mar 22, 2023
6b8f36c
validate.state_reachable: only cast if necessary
isacdaavid Mar 23, 2023
52d0fcc
Re-enable validation at Subsystem constructor
isacdaavid Mar 23, 2023
273ca3e
test_validate: Don't refer to `tpm.tpm`
isacdaavid Mar 23, 2023
d2b3fec
Refactor _validate_probabilities (and use utils.eq)
isacdaavid Mar 24, 2023
0281d42
`distribution.is_unitary`: Remove superfluous flattening
isacdaavid Mar 24, 2023
6c79407
Make sure node shapes are validated if CM is passed
isacdaavid Mar 24, 2023
f268f4d
tpm: Remove old ProxyMetaclass code
isacdaavid Mar 24, 2023
3525ae7
Remove `validate.node_states`, deprecated by `Node.state` setter
isacdaavid Mar 25, 2023
2e958f9
Add support for state labels in validate.state_reachable
isacdaavid Mar 25, 2023
45646f2
Fix `Network` creation from existing `ImplicitTPM`
isacdaavid Mar 26, 2023
818164f
Remove Node.streamline
isacdaavid Mar 26, 2023
b7d5537
Refactor implicit_tpm fixture
isacdaavid Mar 26, 2023
7f04bac
Disable state reachability validation until reimplemented in implicit…
isacdaavid Apr 10, 2023
f66101a
Merge feature/iit-4.0 into feature/tpm-class
isacdaavid Nov 21, 2023
89bad27
tpm: Simplify subtpm method
isacdaavid Nov 21, 2023
20808fe
Refactor TPM validation
isacdaavid Nov 22, 2023
e687f26
subsystem: Fix proper_tpm
isacdaavid Nov 24, 2023
0454ad7
Tidy documentation
isacdaavid Nov 24, 2023
460e9c8
node.py: Improve code formatting
isacdaavid Nov 24, 2023
0f8bafc
Rename DataArray accessor to something more explicit
isacdaavid Nov 24, 2023
74ac75f
validate: Disable state reachability warning for now
isacdaavid Dec 5, 2023
6593f21
tpm: add `number_of_units` getter in the ImplicitTPM case
isacdaavid Dec 12, 2023
ac5fc86
ImplicitTPM.number_of_units: more efficient implementation
isacdaavid Dec 21, 2023
685cb7f
test_tpm: validate arguments in `implicit_tpm` test
isacdaavid Dec 26, 2023
e4f1757
tpm: implement `probability_of_current_state()` and `backward_tpm()` …
isacdaavid Dec 28, 2023
1014cec
Refactor `backward_tpm as instance methods`
isacdaavid Dec 28, 2023
1d5939a
Rename DataArray accessor to something more expressive
isacdaavid Dec 28, 2023
f69f7a4
test_tpm: Add `test_backward_tpm`
isacdaavid Dec 29, 2023
a357ee4
Move Fig 8 counter network to `examples`
isacdaavid Jan 3, 2024
1740585
`utils`: Add `equivalent_states` generator
isacdaavid Jan 3, 2024
53b56c3
Rework state reachability validation to avoid computing joint prob.
isacdaavid Jan 3, 2024
5ae32c5
Merge branch feature/iit-4.0.
isacdaavid Mar 22, 2024
34aae42
Merge branch 'feature/iit-4.0' into feature/tpm-class
isacdaavid Mar 23, 2024
64331cc
Only compute potential purviews if not overriden
wmayner Mar 27, 2024
78ff393
Merge remote-tracking branch 'refs/remotes/origin/feature/tpm-class' …
wmayner Mar 27, 2024
d44b760
`validate.state_reachable`: Shortcircuit intersection as soon as poss…
isacdaavid May 25, 2024
8083a71
`validate.state_reachable`: Don't expand equivalence classes, use sym…
isacdaavid May 27, 2024
fa9a3e4
validate.state_reachable: parallelize intersection between symbolic e…
isacdaavid May 28, 2024
484f3b4
Merge branch 'feature/tpm-class' of github.com:wmayner/pyphi into fea…
isacdaavid May 28, 2024
a08fc2b
`validate`: Refactor scope and add documentation/tests.
isacdaavid May 28, 2024
4b93ca1
Improve state validation when creating subsystems
isacdaavid May 29, 2024
34010f6
`validate.state_value`: Fix off-by-one error
isacdaavid May 29, 2024
ab4c202
Remove parallelization of `state_reachable` for now
isacdaavid May 29, 2024
bec9e9b
Backport unified subsystem interface to tpm-class branch
isacdaavid Aug 6, 2024
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
12 changes: 6 additions & 6 deletions docs/examples/magic_cut.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,15 @@ into existence.
>>> C = (2,)
>>> AB = (0, 1)

The cut applied to the subsystem severs the connections going to |C| from
either |A| or |B|. In this circumstance, knowing the state of |A| or |B| does
not tell us anything about the state of |C|; only the previous state of |C| can
tell us about the next state of |C|. ``C_node.tpm_on`` gives us the probability
of |C| being ON in the next state, while ``C_node.tpm_off`` would give us the
The cut applied to the subsystem severs the connections going to |C| from either
|A| or |B|. In this circumstance, knowing the state of |A| or |B| does not tell
us anything about the state of |C|; only the previous state of |C| can tell us
about the next state of |C|. ``C_node.tpm[..., 1]`` gives us the probability of
|C| being ON in the next state, while ``C_node.tpm[..., 0]`` would give us the
probability of |C| being OFF.

>>> C_node = cut_subsystem.indices2nodes(C)[0]
>>> C_node.tpm_on.flatten()
>>> C_node.tpm[..., 1].flatten()
array([0.5 , 0.75])

This states that |C| has a 50% chance of being ON in the next state if it
Expand Down
1 change: 0 additions & 1 deletion pyphi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
from .direction import Direction
from .network import Network
from .subsystem import Subsystem
from .tpm import ExplicitTPM

# Skip modules that require optional dependencies
_skip_import = ["visualize", "graphs"]
Expand Down
13 changes: 9 additions & 4 deletions pyphi/cache/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ class DictCache:
Intended to be used as an object-level cache of method results.
"""

def __init__(self):
self.cache = {}
self.hits = 0
self.misses = 0
def __init__(self, cache=None, hits=0, misses=0):
self.cache = dict() if cache is None else cache
self.hits = hits
self.misses = misses

def clear(self):
self.cache = {}
Expand Down Expand Up @@ -148,6 +148,11 @@ def key(self, *args, _prefix=None, **kwargs):
if kwargs:
raise NotImplementedError("kwarg cache keys not implemented")
return (_prefix,) + tuple(args)

def __repr__(self):
return "{}(cache={}, hits={}, misses={})".format(
type(self).__name__, self.cache, self.hits, self.misses
)


def validate_parent_cache(parent_cache):
Expand Down
Empty file modified pyphi/convert.py
100644 → 100755
Empty file.
6 changes: 5 additions & 1 deletion pyphi/data_structures/array_like.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ class ArrayLike(NDArrayOperatorsMixin):

# TODO(tpm) populate this list
_TYPE_CLOSED_FUNCTIONS = (
np.all,
np.any,
np.concatenate,
np.expand_dims,
np.stack,
np.all,
np.sum,
np.result_type,
np.broadcast_to,
)

# Holds the underlying array
Expand Down
1 change: 1 addition & 0 deletions pyphi/distribution.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import numpy as np

from .cache import cache
from .utils import eq


def normalize(a):
Expand Down
25 changes: 25 additions & 0 deletions pyphi/examples.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -1512,3 +1512,28 @@ def get_net(
print(transition)
account = actual.account(transition)
print(account)

@register_example
def functionally_equivalent():
"""The 2nd deterministic system from Figure 8 of the IIT 4.0 paper:
Functionally equivalent networks with different Φ-structures.
"""
node_labels = ("A", "B", "C")
# fmt: off
cm = np.array([
[1, 1, 0,],
[0, 1, 1,],
[1, 1, 1,],
])
tpm = np.array([
[1, 0, 0],
[0, 1, 0],
[1, 1, 1],
[0, 1, 1],
[0, 0, 0],
[1, 1, 0],
[0, 0, 1],
[1, 0, 1],
])
# fmt: on
return Network(tpm, cm=cm, node_labels=node_labels)
98 changes: 66 additions & 32 deletions pyphi/macro.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
from .labels import NodeLabels
from .network import irreducible_purviews
from .node import expand_node_tpm, generate_nodes
from .state_space import build_state_space
from .subsystem import Subsystem

# TODO(tpm) use ImplicitTPM type consistently throughout module
from .tpm import ExplicitTPM

# Create a logger for this module.
Expand Down Expand Up @@ -43,25 +46,6 @@ def rebuild_system_tpm(node_tpms):
return ExplicitTPM(tpm, validate=True)


# TODO This should be a method of the TPM class in tpm.py
def remove_singleton_dimensions(tpm):
"""Remove singleton dimensions from the TPM.

Singleton dimensions are created by conditioning on a set of elements.
This removes those elements from the TPM, leaving a TPM that only
describes the non-conditioned elements.

Note that indices used in the original TPM must be reindexed for the
smaller TPM.
"""
# Don't squeeze out the final dimension (which contains the probability)
# for networks with one element.
if tpm.ndim <= 2:
return tpm

return tpm.squeeze()[..., tpm.tpm_indices()]


def run_tpm(system, steps, blackbox):
"""Iterate the TPM for the given number of timesteps.

Expand All @@ -73,7 +57,8 @@ def run_tpm(system, steps, blackbox):
# boxes.
node_tpms = []
for node in system.nodes:
node_tpm = node.tpm_on
# TODO: nonbinary nodes.
node_tpm = node.tpm[..., 1]
for input_node in node.inputs:
if not blackbox.in_same_box(node.index, input_node):
if input_node in blackbox.output_indices:
Expand All @@ -92,7 +77,11 @@ def run_tpm(system, steps, blackbox):
return ExplicitTPM(convert.state_by_state2state_by_node(tpm), validate=True)


class SystemAttrs(namedtuple("SystemAttrs", ["tpm", "cm", "node_indices", "state"])):
class SystemAttrs(
namedtuple(
"SystemAttrs", ["tpm", "cm", "node_indices", "state"]
)
):
"""An immutable container that holds all the attributes of a subsystem.

Versions of this object are passed down the steps of the micro-to-macro
Expand All @@ -106,15 +95,34 @@ def node_labels(self):
labels = list("m{}".format(i) for i in self.node_indices)
return NodeLabels(labels, self.node_indices)

@property
def state_space(self):
state_space, _ = build_state_space(
self.node_labels,
self.tpm.shape[:-1],
node_states=None,
)
return state_space

@property
def nodes(self):
return generate_nodes(
self.tpm, self.cm, self.state, self.node_indices, self.node_labels
self.tpm,
self.cm,
self.state_space,
self.node_indices,
self.node_labels,
network_state=self.state,
)

@staticmethod
def pack(system):
return SystemAttrs(system.tpm, system.cm, system.node_indices, system.state)
return SystemAttrs(
system.tpm,
system.cm,
system.node_indices,
system.state,
)

def apply(self, system):
system.tpm = self.tpm
Expand Down Expand Up @@ -214,11 +222,12 @@ def _squeeze(system):
Reindexes the subsystem so that the nodes are ``0..n`` where ``n`` is
the number of internal indices in the system.
"""
assert system.node_indices == system.tpm.tpm_indices()
assert system.node_indices == system.tpm.tpm_indices(reconstituted=True)

internal_indices = system.tpm.tpm_indices()
internal_indices = system.tpm.tpm_indices(reconstituted=True)
tpm = system.tpm.remove_singleton_dimensions()

tpm = remove_singleton_dimensions(system.tpm)
# TODO(tpm): deduplicate commonalities with tpm.ImplicitTPM.squeeze.

# The connectivity matrix is the network's connectivity matrix, with
# cut applied, with all connections to/from external nodes severed,
Expand All @@ -229,10 +238,24 @@ def _squeeze(system):

# Re-index the subsystem nodes with the external nodes removed
node_indices = reindex(internal_indices)
nodes = generate_nodes(tpm, cm, state, node_indices)
node_labels = NodeLabels(None, node_indices)
state_space, _ = build_state_space(
node_labels,
tpm.shape[:-1],
)

nodes = generate_nodes(
tpm,
cm,
state_space,
node_indices,
node_labels,
network_state=state
)

# Re-calcuate the tpm based on the results of the cut
tpm = rebuild_system_tpm(node.tpm_on for node in nodes)
# TODO: nonbinary nodes.
tpm = rebuild_system_tpm(node.tpm[..., 1] for node in nodes)

return SystemAttrs(tpm, cm, node_indices, state)

Expand All @@ -242,7 +265,8 @@ def _blackbox_partial_noise(blackbox, system):
# Noise inputs from non-output elements hidden in other boxes
node_tpms = []
for node in system.nodes:
node_tpm = node.tpm_on
# TODO: nonbinary nodes.
node_tpm = node.tpm[..., 1]
for input_node in node.inputs:
if blackbox.hidden_from(input_node, node.index):
node_tpm = node_tpm.marginalize_out([input_node])
Expand All @@ -264,7 +288,12 @@ def _blackbox_time(time_scale, blackbox, system):
n = len(system.node_indices)
cm = np.ones((n, n))

return SystemAttrs(tpm, cm, system.node_indices, system.state)
return SystemAttrs(
tpm,
cm,
system.node_indices,
system.state,
)

def _blackbox_space(self, blackbox, system):
"""Blackbox the TPM and CM in space.
Expand All @@ -282,7 +311,8 @@ def _blackbox_space(self, blackbox, system):

assert blackbox.output_indices == tpm.tpm_indices()

tpm = remove_singleton_dimensions(tpm)
new_tpm = tpm.remove_singleton_dimensions()

n = len(blackbox)
cm = np.zeros((n, n))
for i, j in itertools.product(range(n), repeat=2):
Expand All @@ -294,8 +324,12 @@ def _blackbox_space(self, blackbox, system):

state = blackbox.macro_state(system.state)
node_indices = blackbox.macro_indices
state_space, _ = build_state_space(
NodeLabels(None, node_indices),
tpm.shape[:-1]
)

return SystemAttrs(tpm, cm, node_indices, state)
return SystemAttrs(new_tpm, cm, node_indices, state)

@staticmethod
def _coarsegrain_space(coarse_grain, is_cut, system):
Expand Down
Loading