# Path: pyphi/convert.py
# def reverse_bits(i, n):
# def be2le(i, n):
# def nodes2indices(nodes):
# def nodes2state(nodes):
# def state2be_index(state):
# def state2le_index(state):
# def le_index2state(i, number_of_nodes):
# def be_index2state(i, number_of_nodes):
# def be2le_state_by_state(tpm):
# def to_multidimensional(tpm):
# def to_2dimensional(tpm):
# def state_by_state2state_by_node(tpm):
# def _deterministic_sbn2sbs(Sp, Sn, sbn_tpm):
# def _unfold_nodewise_probabilities(Nn, Sn, sbn_row):
# def _nondeterministic_sbn2sbs(Nn, Sn, sbn_tpm):
# def state_by_node2state_by_state(tpm):
#     N = tpm.shape[0]
#     S = np.prod(tpm.shape[:-1])
#     N = tpm.shape[-1]
#     S = tpm.shape[-1]
#     N = int(log2(S))
# 
# Path: pyphi/macro.py
# _NUM_PRECOMPUTED_PARTITION_LISTS = 10
# def reindex(indices):
# def rebuild_system_tpm(node_tpms):
# def remove_singleton_dimensions(tpm):
# def run_tpm(system, steps, blackbox):
#     def node_labels(self):
#     def nodes(self):
#     def pack(system):
#     def apply(self, system):
#     def __init__(
#         self,
#         network,
#         state,
#         nodes=None,
#         cut=None,
#         mice_cache=None,
#         time_scale=1,
#         blackbox=None,
#         coarse_grain=None,
#     ):
#     def _squeeze(system):
#     def _blackbox_partial_noise(blackbox, system):
#     def _blackbox_time(time_scale, blackbox, system):
#     def _blackbox_space(self, blackbox, system):
#     def _coarsegrain_space(coarse_grain, is_cut, system):
#     def cut_indices(self):
#     def cut_mechanisms(self):
#     def cut_node_labels(self):
#     def apply_cut(self, cut):
#     def potential_purviews(self, direction, mechanism, purviews=False):
#     def macro2micro(self, macro_indices):
#         def from_partition(partition, macro_indices):
#     def macro2blackbox_outputs(self, macro_indices):
#     def __repr__(self):
#     def __str__(self):
#     def __eq__(self, other):
#     def __hash__(self):
#     def micro_indices(self):
#     def macro_indices(self):
#     def __len__(self):
#     def reindex(self):
#     def macro_state(self, micro_state):
#     def make_mapping(self):
#     def macro_tpm_sbs(self, state_by_state_micro_tpm):
#     def macro_tpm(self, micro_tpm, check_independence=True):
#     def hidden_indices(self):
#     def micro_indices(self):
#     def macro_indices(self):
#     def __len__(self):
#     def outputs_of(self, partition_index):
#     def reindex(self):
#     def macro_state(self, micro_state):
#     def in_same_box(self, a, b):
#     def hidden_from(self, a, b):
# def _partitions_list(N):
# def all_partitions(indices):
# def all_groupings(partition):
# def all_coarse_grains(indices):
# def all_coarse_grains_for_blackbox(blackbox):
# def all_blackboxes(indices):
#     def __init__(
#         self,
#         network,
#         system,
#         macro_phi,
#         micro_phi,
#         coarse_grain,
#         time_scale=1,
#         blackbox=None,
#     ):
#     def __str__(self):
#     def emergence(self):
# def coarse_graining(network, state, internal_indices):
# def all_macro_systems(
#     network, state, do_blackbox=False, do_coarse_grain=False, time_scales=None
# ):
#     def blackboxes(system):
#     def coarse_grains(blackbox, system):
# def emergence(
#     network, state, do_blackbox=False, do_coarse_grain=True, time_scales=None
# ):
# def phi_by_grain(network, state):
# def effective_info(network):
# class SystemAttrs(namedtuple("SystemAttrs", ["tpm", "cm", "node_indices", "state"])):
# class MacroSubsystem(Subsystem):
# class CoarseGrain(namedtuple("CoarseGrain", ["partition", "grouping"])):
# class Blackbox(namedtuple("Blackbox", ["partition", "output_indices"])):
# class MacroNetwork:
# 
# Path: pyphi/exceptions.py
# class ConditionallyDependentError(ValueError):
#     """The TPM is conditionally dependent."""


import numpy as np
import pytest
from pyphi import convert, macro
from pyphi.exceptions import ConditionallyDependentError
        [[0, 0],
         [0, 1]],
    ])
    # fmt: on
    assert np.array_equal(macro.rebuild_system_tpm(node_tpms), answer)

    node_tpms = [node.tpm_on for node in s.nodes]
    assert np.array_equal(macro.rebuild_system_tpm(node_tpms), s.tpm)


def test_remove_singleton_dimensions():
    # Don't squeeze out last dimension of single-node tpm
    # fmt: off
    tpm = np.array([
        [0], 
        [1],
    ])
    # fmt: on
    assert macro.tpm_indices(tpm) == (0,)
    assert np.array_equal(macro.remove_singleton_dimensions(tpm), tpm)

    # fmt: off
    tpm = np.array([
        [[[0.,  0.,  1.]],
         [[1.,  0.,  0.]]]])
    answer = np.array([
        [0], 
        [0],
    ])
    # fmt: on

# Path: pyphi/convert.py
# def reverse_bits(i, n):
# def be2le(i, n):
# def nodes2indices(nodes):
# def nodes2state(nodes):
# def state2be_index(state):
# def state2le_index(state):
# def le_index2state(i, number_of_nodes):
# def be_index2state(i, number_of_nodes):
# def be2le_state_by_state(tpm):
# def to_multidimensional(tpm):
# def to_2dimensional(tpm):
# def state_by_state2state_by_node(tpm):
# def _deterministic_sbn2sbs(Sp, Sn, sbn_tpm):
# def _unfold_nodewise_probabilities(Nn, Sn, sbn_row):
# def _nondeterministic_sbn2sbs(Nn, Sn, sbn_tpm):
# def state_by_node2state_by_state(tpm):
#     N = tpm.shape[0]
#     S = np.prod(tpm.shape[:-1])
#     N = tpm.shape[-1]
#     S = tpm.shape[-1]
#     N = int(log2(S))
# 
# Path: pyphi/macro.py
# _NUM_PRECOMPUTED_PARTITION_LISTS = 10
# def reindex(indices):
# def rebuild_system_tpm(node_tpms):
# def remove_singleton_dimensions(tpm):
# def run_tpm(system, steps, blackbox):
#     def node_labels(self):
#     def nodes(self):
#     def pack(system):
#     def apply(self, system):
#     def __init__(
#         self,
#         network,
#         state,
#         nodes=None,
#         cut=None,
#         mice_cache=None,
#         time_scale=1,
#         blackbox=None,
#         coarse_grain=None,
#     ):
#     def _squeeze(system):
#     def _blackbox_partial_noise(blackbox, system):
#     def _blackbox_time(time_scale, blackbox, system):
#     def _blackbox_space(self, blackbox, system):
#     def _coarsegrain_space(coarse_grain, is_cut, system):
#     def cut_indices(self):
#     def cut_mechanisms(self):
#     def cut_node_labels(self):
#     def apply_cut(self, cut):
#     def potential_purviews(self, direction, mechanism, purviews=False):
#     def macro2micro(self, macro_indices):
#         def from_partition(partition, macro_indices):
#     def macro2blackbox_outputs(self, macro_indices):
#     def __repr__(self):
#     def __str__(self):
#     def __eq__(self, other):
#     def __hash__(self):
#     def micro_indices(self):
#     def macro_indices(self):
#     def __len__(self):
#     def reindex(self):
#     def macro_state(self, micro_state):
#     def make_mapping(self):
#     def macro_tpm_sbs(self, state_by_state_micro_tpm):
#     def macro_tpm(self, micro_tpm, check_independence=True):
#     def hidden_indices(self):
#     def micro_indices(self):
#     def macro_indices(self):
#     def __len__(self):
#     def outputs_of(self, partition_index):
#     def reindex(self):
#     def macro_state(self, micro_state):
#     def in_same_box(self, a, b):
#     def hidden_from(self, a, b):
# def _partitions_list(N):
# def all_partitions(indices):
# def all_groupings(partition):
# def all_coarse_grains(indices):
# def all_coarse_grains_for_blackbox(blackbox):
# def all_blackboxes(indices):
#     def __init__(
#         self,
#         network,
#         system,
#         macro_phi,
#         micro_phi,
#         coarse_grain,
#         time_scale=1,
#         blackbox=None,
#     ):
#     def __str__(self):
#     def emergence(self):
# def coarse_graining(network, state, internal_indices):
# def all_macro_systems(
#     network, state, do_blackbox=False, do_coarse_grain=False, time_scales=None
# ):
#     def blackboxes(system):
#     def coarse_grains(blackbox, system):
# def emergence(
#     network, state, do_blackbox=False, do_coarse_grain=True, time_scales=None
# ):
# def phi_by_grain(network, state):
# def effective_info(network):
# class SystemAttrs(namedtuple("SystemAttrs", ["tpm", "cm", "node_indices", "state"])):
# class MacroSubsystem(Subsystem):
# class CoarseGrain(namedtuple("CoarseGrain", ["partition", "grouping"])):
# class Blackbox(namedtuple("Blackbox", ["partition", "output_indices"])):
# class MacroNetwork:
# 
# Path: pyphi/exceptions.py
# class ConditionallyDependentError(ValueError):
#     """The TPM is conditionally dependent."""


# Path: test/test_macro.py
import numpy as np
import pytest
from pyphi import convert, macro
from pyphi.exceptions import ConditionallyDependentError

        [[0, 0],
         [0, 1]],
    ])
    # fmt: on
    assert np.array_equal(macro.rebuild_system_tpm(node_tpms), answer)

    node_tpms = [node.tpm_on for node in s.nodes]
    assert np.array_equal(macro.rebuild_system_tpm(node_tpms), s.tpm)


def test_remove_singleton_dimensions():
    # Don't squeeze out last dimension of single-node tpm
    # fmt: off
    tpm = np.array([
        [0], 
        [1],
    ])
    # fmt: on
    assert macro.tpm_indices(tpm) == (0,)
    assert np.array_equal(macro.remove_singleton_dimensions(tpm), tpm)

    # fmt: off
    tpm = np.array([
        [[[0.,  0.,  1.]],
         [[1.,  0.,  0.]]]])
    answer = np.array([
        [0], 
        [0],
    ])
    # fmt: on

    assert macro.tpm_indices(tpm) == (1,)