Exemplo n.º 1
0
def IF(data, flow_to_index, t_shift=1):
    """ IF(E->S)

    Notes
    -----
    The lists are cut as follows: as an example take sequences of length 5 with m=2
    s_n+1 = 0, 1, 2, [3, 4]              }
    s_n   =    0, 1, [2, 3], 4           } 
    e_n   =    0, 1, [2, 3], 4           }
    so we cut m+1 values at most from the start andn 
    """

    # check for integer
    flow_to_index = [flow_to_index] if isinstance(flow_to_index,
                                                  int) else flow_to_index
    flow_from_index = np.setdiff1d(range(len(data)), flow_to_index)

    # make system and env lists from data
    data = np.array(data)
    data_to = np.delete(data, flow_from_index, axis=0)
    data_from = np.delete(data, flow_to_index, axis=0)

    # setting up the array
    series_data = np.zeros((3, len(data[0]) - t_shift))

    # slice the lists
    series_data[0] = data_to[:, t_shift:]
    series_data[1] = data_from[:, :-t_shift]
    series_data[2] = data_to[:, :-t_shift]

    series_pmf = prob.numpy_pmf(series_data)

    return inf.numpy_conditional_mutual_information(series_pmf, 0, 1)
Exemplo n.º 2
0
def non_heteronomy(data, sys_index, m):
    """ H(S_n+1 | E_n, ... , E_n-m) """

    # check for integer
    sys_index = [sys_index] if isinstance(sys_index, int) else sys_index
    env_index = np.setdiff1d(range(len(data)), sys_index)

    # make system and env lists from data
    data = np.array(data)
    sys = np.delete(data, env_index, axis=0)
    env = np.delete(data, sys_index, axis=0)

    # setting up the array
    series_data = np.zeros((m + 3, len(data[0]) - (m + 1)), dtype=int)

    # slice the lists
    series_data[0] = sys[:, m + 1:]

    for i in range(m + 1):
        series_data[1 + i] = env[:, m - i:-1 - i]

    series_pmf = prob.numpy_pmf(series_data)

    return inf.numpy_conditional_entropy(series_pmf,
                                         list(range(len(series_data))[1:]))
Exemplo n.º 3
0
def Astar(data, sys_index, t_shift=1):
    """ Calculate Bertschinger's A* from history

    Parameters
    ----------
    data : array_like
        2-D array with rows representing variables and columns representing entries 
        in the time series.
    sys_index : array_like, integer
        Indices of the data array corresponding to the history of the system

    References
    ----------
    doi:10.1016/j.biosystems.2007.05.018)
    """

    # correct indices
    sys_index = [sys_index] if isinstance(sys_index, int) else sys_index
    env_index = np.setdiff1d(range(len(data)), sys_index)

    # make system list from data
    data = np.array(data)
    sys = np.delete(data, env_index, axis=0)

    # create (S_n+1, S_n) data
    data_Astar = np.vstack((sys[:, t_shift:], sys[:, :-t_shift]))
    Astar_pmf = prob.numpy_pmf(data_Astar)

    return inf.numpy_mutual_information(Astar_pmf, range(len(sys_index)))
Exemplo n.º 4
0
def seq_Astar(data, sys_index, t_shift=1):
    """ I(S_{n+1} ; S_{n}) """
    step_index = [[t_shift, 0]]

    series_data, series_index = seq_maker(data,
                                          sys_index,
                                          step_index,
                                          return_index=True)
    series_pmf = prob.numpy_pmf(series_data)

    return inf.numpy_mutual_information(series_pmf, range(len(*sys_index)))
Exemplo n.º 5
0
def Am(data, sys_index, m):
    """ Calculate Bertschinger's Am from history

    Parameters
    ----------
    data : array_like
        2-D array with rows representing variables and columns representing entries 
        in the time series.
    sys_index : array_like, integer
        Indices of the data array corresponding to the history of the system
    env_index : array_like, integer
        Indices of the data array corresponding to the history of the environment
    m : integer
        Length of environment history where Am = I(S_n+1; S_n | E_n, E_n-1, ... , E_n-m)

    References
    ----------
    doi:10.1016/j.biosystems.2007.05.018)

    Notes
    -----
    The lists are cut as follows: as an example take sequences of length 5 with m=2
    s_n+1 = 0, 1, 2, [3, 4]              }
    s_n   =    0, 1, [2, 3], 4           }3 
    e_n   =    0, 1, [2, 3], 4           }+
    e_n-1 =       0, [1, 2], 3, 4         }m 
    e_n-2 =          [0, 1], 2, 3, 4      } 
    so we cut m+1 values at most from the start andn 
    """

    # check for integer
    sys_index = [sys_index] if isinstance(sys_index, int) else sys_index
    env_index = np.setdiff1d(range(len(data)), sys_index)

    # make system and env lists from data
    data = np.array(data)
    sys = np.delete(data, env_index, axis=0)
    env = np.delete(data, sys_index, axis=0)

    # setting up the array
    series_data = np.zeros((m + 3, len(data[0]) - (m + 1)), dtype=int)

    # slice the lists
    series_data[0] = sys[:, m + 1:]
    series_data[1] = sys[:, m:-1]

    for i in range(m + 1):
        series_data[2 + i] = env[:, m - i:-1 - i]

    series_pmf = prob.numpy_pmf(series_data)

    return inf.numpy_conditional_mutual_information(series_pmf, 0, 1)
Exemplo n.º 6
0
def seq_non_heteronomy(data, sys_index, m, t_shift=1):
    """ H(S_n+1 | E_n, ... , E_n-m) """

    step_index = [[t_shift], [list(range(0, -(m + 1), -1))]]

    series_data, series_index = seq_maker(data,
                                          sys_index,
                                          step_index,
                                          return_index=True)
    series_pmf = prob.numpy_pmf(series_data)

    # fix
    return inf.numpy_conditional_entropy(series_pmf,
                                         list(range(len(series_data))[1:]))
Exemplo n.º 7
0
def seq_Am(data, var_index, m, t_shift=1):
    """ I(S_{n+1} ; S_{n} | E_{n}, E_{n-1}, ... ,E_{n-m}) """
    step_index = [[t_shift, 0], list(range(0, -(m + 1), -1))]

    series_data, series_index = seq_maker(data,
                                          var_index,
                                          step_index,
                                          return_index=True)
    print(series_index)
    series_pmf = prob.numpy_pmf(series_data)

    return inf.numpy_conditional_mutual_information(series_pmf,
                                                    series_index[0],
                                                    series_index[1])
Exemplo n.º 8
0
def seq_IF(data, flow_from_index, flow_to_index, t_shift=1):
    """ IF(E->S) =  I(S_{n+1} : E_{n}|S_{n}) """

    var_index = [flow_to_index, flow_from_index]
    step_index = [[t_shift, 0], [0]]

    series_data, series_index = seq_maker(data,
                                          var_index,
                                          step_index,
                                          return_index=True)
    series_pmf = prob.numpy_pmf(series_data)

    return inf.numpy_conditional_mutual_information(series_pmf,
                                                    series_index[0],
                                                    series_index[2])


##############################################################################################

# def time_gap_correlation(data, t_shift):
#     """ Calculates correlation matrix of time series with itself shifted by time t

#     Parameters
#     ----------
#     data : array_like
#         2-D array with rows representing variables and columns representing entries
#         in the time series.
#     t_shift : integer
#         The amount of steps to shift the correlation by. 0 gives self-correlation.
#     """

#     if t_shift == 0:
#         correlation = np.zeros(len(data)**2)
#         for i, sn_i in enumerate(data):
#             for j, sn_j in enumerate(data):
#                 # when data is constant np.corrcoeff gives a 'nan' array and can cause errors
#                 if i != j:
#                     correlation[i*len(data) + j] = np.corrcoef(np.vstack((sn_i, sn_j)))[0][1]
#                 else:
#                     correlation[i*len(data) + j] = None
#     else:
#         t_data = np.array(data)[:,t_shift:]   # x_n
#         data_t = np.array(data)[:,:-t_shift]  # x_n-t

#         correlation = np.zeros(len(data)**2)
#         for i, sn_i in enumerate(t_data):
#             for j, snn_j in enumerate(data_t):
#                 # when data is constant np.corrcoeff gives a 'nan' array and can cause errors
#                 correlation[i*len(data) + j] = np.corrcoef(np.vstack((sn_i, snn_j)))[0][1]

#     return correlation

# ##################################################################################

# # the transitions are done weirdly, needs to be re-done
# class Bertschinger_Automaton():
#     def __init__(self, S, E, mu, phi, psi) -> None:
#         self.time = 0

#         self.S = S  # (s_0, s_1, ...)
#         self.E = E  # (e_0, e_1, ...)
#         self.phi = phi  # [e][s][s'] = p(s'|s,e)
#         self.psi = psi  # [s][e][e'] = p(e'|e,s)
#         self.mu = mu  # [s][e] = p(s,e)

#         self.history = []

#         self.state = None
#         self.set_state()

#     def set_state(self, state_set=None, t=None):
#         if isinstance(t, int):
#             self.time = t
#             # print(f"time set to {t}")
#         if state_set is not None:
#             self.state = state_set
#             # print(f"state manually set to {self.state}")
#         else:
#             mu_states = []
#             mu_probs = []
#             for i, s_i in enumerate(self.mu):
#                 for j, e_j in enumerate(s_i):
#                     mu_states.append((i,j))
#                     mu_probs.append(e_j)
#             choice = np.random.choice(range(len(mu_probs)), p=mu_probs)
#             self.state = mu_states[choice]
#             # print(f"Initialized to {self.state}")
#         self.history.append((self.time, (self.S[self.state[0]], self.E[self.state[1]])))

#     def run(self, n_steps, phi=None, psi=None):
#         if phi is not None:
#             self.phi = phi
#         if psi is not None:
#             self.psi = psi
#         for _ in range(n_steps):
#             self.time += 1
#             s_n = self.state[0]
#             e_n = self.state[1]
#             phi_n = self.phi[e_n][s_n]
#             psi_n = self.psi[s_n][e_n]
#             s_n1 = np.random.choice(range(len(phi_n)), p=phi_n)
#             e_n1 = np.random.choice(range(len(psi_n)), p=psi_n)
#             self.state = (s_n1, e_n1)
#             self.history.append((self.time, (self.S[self.state[0]], self.E[self.state[1]])))
#             # print("-------------------------------------")
#             # print(f"t={self.time-1}: s_n={self.S[s_n]}, e_n={self.E[e_n]}")
#             # print(f"p_s={phi_n}, p_e={psi_n}")
#             # print(f"t={self.time}: s_n+1 = {self.S[s_n1]}, e_n+1 = {self.E[e_n1]}")
#         # print(f"ran {n_steps} steps")

#     def linear_history(self):
#         sys_history = []
#         env_history = []
#         for entry in self.history:
#             sys_history.append(entry[1][0])
#             env_history.append(entry[1][1])
#         return (sys_history, env_history)

#     def clear_history(self):
#         self.history = []

# def make_phi_6b(p, S, E):
#     """ phi[e][s][s'] = phi(e,s; s') = p(s'|e,s) """
#     phi = np.zeros(shape=(len(E), len(S), len(S)))
#     phi[0][0] = [1-p, p]
#     phi[0][1] = [1, 0]
#     phi[1][0] = [p, 1-p]  $ [0, 1] for 6a
#     phi[1][1] = [0, 1]
#     return phi

# def make_psi(p, S, E):
#     """ psi[s][e][e'] = psi(s,e; e') = p(e'|s,e) """
#     psi = np.zeros(shape=(len(S), len(E), len(E)))
#     psi[0][0] = [p, 1-p]
#     psi[0][1] = [p, 1-p]
#     psi[1][0] = [p, 1-p]
#     psi[1][1] = [p, 1-p]
#     return psi

# def make_mu(S,E):
#     """ mu(s1, e1) = p(s1, e1) """
#     # the distribution should sum to 1
#     mu = np.zeros(shape=(len(S), len(E)))
#     mu[0][0] = 1
#     mu[0][1] = 0
#     mu[1][0] = 0
#     mu[1][1] = 0
#     return mu

# def seq_maker_Am(data, sys_indices, env_indices, m=2):
#     """

#     Intended for use with Bertschinger NTIC paper
#     (doi:10.1016/j.biosystems.2007.05.018)

#     Takes history data from two sources (intended: System and Environment) and
#     returns them in the format [..., [S_n+1, S_n, E_n, E_n-1, ... , E_n-m], ...]

#     e.g. for
#     - data = [(s0, e0), (s1, e1), ..., (s8, e8)]
#     - sys_indices = 0
#     - env_indices = 1

#     S = [s0, s1, s2, s3, s4, s5, s6, s7, s8]
#     E = [e0, e1, e2, e3, e4, e5, e6, e7, e8]
#     The offsets work as follows (eg: n = 9, m = 3)

#     |S_{n+1}   | s0, s1, s2, s3, [s4, s5, s6, s7, s8]
#     |S_{n}     |     s0, s1, s2, [s3, s4, s5, s6, s7], s8
#     -----------------------------------------------------------------
#     |E_{n}     |     e0, e1, e2, [e3, e4, e5, e6, e7], e8
#     |E_{n-1}   |         s0, e1, [e2, e3, e4, e5, e6], e7, e8
#     |E_{n-2}   |             e0, [e1, e2, e3, e4, e5], e6, e7, e8
#     |E_{n-3}   |                 [e0, e1, e2, e3, e4], e5, e6, e7, e8
#     """

#     # check for integer
#     sys_indices = [sys_indices] if isinstance(sys_indices, int) else sys_indices
#     env_indices = [env_indices] if isinstance(env_indices, int) else env_indices

#     # make system and env lists from data
#     sys = np.delete(data.T, env_indices, axis=0)
#     env = np.delete(data.T, sys_indices, axis=0)

#     # slice the lists
#     system_1 = sys[:,m+1:]
#     system_0 = sys[:,m:-1]
#     series_output = np.vstack((system_1, system_0))

#     for i in range(m+1):
#         series_output = np.concatenate((series_output, env[:,m-i:-1-i]), axis=0)

#     return series_output

# def seq_maker_Astar(data, sys_indices):

#     # check for integer
#     sys_indices = [sys_indices] if isinstance(sys_indices, int) else sys_indices

#     # make system state list
#     sys = []
#     for state_n in data:
#         sys_n = []
#         for i in sys_indices:
#             sys_n.append(state_n[i])
#         sys.append(tuple(sys_n))

#     # make (S_n, S_n+1)
#     S_S1 = []
#     for i, s_n in enumerate(sys):
#         try:
#             S_S1.append((s_n, sys[i+1]))
#         except:
#             pass

#     return S_S1

# def sequence_maker_old(system, environment, m=2):
#     """
#     Intended for use with Bertschinger NTIC paper
#     (doi:10.1016/j.biosystems.2007.05.018)

#     S = system
#     E = environment
#     (S_n+1 : S_n | E_n, E_n-1 ... E_n-m)

#     Takes history data from two sources (intended: System and Environment) and
#     returns them in the format [[S_n+1], [S_n], [E_n], [E_n-1], ... , [E_n-m]]]
#     with appropriate offset, so that the data can be read vertically as well.

#     For data:
#     S = [s0, s1, s2, s3, s4, s5, s6, s7, s8]
#     E = [e0, e1, e2, e3, e4, e5, e6, e7, e8]
#     The offsets work as follows (eg: n = 9, m = 3)

#     |S_{n+1}   | s0, s1, s2, s3, [s4, s5, s6, s7, s8]
#     |S_{n}     |     s0, s1, s2, [s3, s4, s5, s6, s7], s8
#     -----------------------------------------------------------------
#     |E_{n}     |     e0, e1, e2, [e3, e4, e5, e6, e7], e8
#     |E_{n-1}   |         s0, e1, [e2, e3, e4, e5, e6], e7, e8
#     |E_{n-2}   |             e0, [e1, e2, e3, e4, e5], e6, e7, e8
#     |E_{n-3}   |                 [e0, e1, e2, e3, e4], e5, e6, e7, e8
#     """

#     system_1 = system[m+1:]
#     system_0 = system[m:-1]
#     series_output = [system_1, system_0]

#     for i in range(m+1):
#         series_output.append(environment[m-i:-1-i])

#     # transpose matrix
#     series_output = [list(i) for i in zip(*series_output)]

#     return series_output