def test_to_n_dimensional(): N = state_by_node.shape[-1] S = state_by_node.shape[0] result = convert.to_n_dimensional(state_by_node) for i in range(S): state = convert.loli_index2state(i, N) assert np.array_equal(result[state], state_by_node[i])
def convert_holi_tpm_to_loli(holi_tpm): # Assumes state by node format states, nodes = holi_tpm.shape loli_tpm = np.zeros([states, nodes]) for i in range(states): loli_state = loli_index2state(i, nodes) holi_tpm_row = state2holi_index(loli_state) loli_tpm[i, :] = holi_tpm[holi_tpm_row, :] return loli_tpm
def loli_tpm(self): # TODO: Condition on background elements """Yield the State-by-node LOLI tpm for the full system. Not conditioned on background elements.""" number_of_states = 2**len(self) number_of_nodes = len(self) tpm = np.zeros([number_of_states, number_of_nodes]) for state_index in range(number_of_states): current_state = loli_index2state(state_index, number_of_nodes) tpm[state_index] = utils.predict_next_state(self, current_state) return tpm
def pretty_print_tpm(node_tokens, tpm): number_of_states, number_of_nodes = tpm.shape for state_index in range(number_of_states): current_state = loli_index2state(state_index, number_of_nodes) next_state = tpm[state_index, :] pretty_tokens = format_node_tokens_by_state(node_tokens, current_state, mode='back') pretty_tokens = format_node_tokens_by_state(pretty_tokens, next_state, mode='fore') print(':'.join(pretty_tokens))
def input_state_permutation(num_nodes, perm): """ Permute input state order according to permutation of nodes given """ # in the permuted tpm the inputs nodes are ordered as in the permutation i.e. 1 2 0 input_states = np.array([loli_index2state(s, num_nodes) for s in range(2**num_nodes)]) # now I have to find the permutation that would convert perm back to 0 1 2 perm_back = [i[0] for i in sorted(enumerate(perm), key=lambda x:x[1])] # now permute columns of input_states using perm_back # used transposed cause I haven't figured out how to index columns permuted_input_states = input_states.T[np.array(perm_back)].T permuted_state_indices = [state2loli_index(permuted_input_states[s]) for s in range(2**num_nodes)] return permuted_state_indices
def test_loli_index2state(): assert convert.loli_index2state(7, 8) == (1, 1, 1, 0, 0, 0, 0, 0) assert convert.loli_index2state(1, 3) == (1, 0, 0) assert convert.loli_index2state(8, 4) == (0, 0, 0, 1)
def plot_3D_constellation(constellation, label_axes=False, label_stars=True, color_code_axes=False, state_fmt='A'): """Generate a 3D-plot of a constellation of concepts in cause-effect space. Examples: >>> big_mip = pyphi.compute.big_mip(sub) >>> plot_3D_constellation(big_mip.unpartitioned_constellation) Written by Billy Marshall, modified by Graham Findlay. Cause-effect space is a high dimensional space, one for each possible past and future state of the system (2 ** (n+1) dimensional for a system of binary elements). Each concept in the constellation is a point in cause-effect space. The size of the point is proportional to the small-phi value of the concept. The location on each axis represents the probability of the corresponding past / future state in the cause-effect repertoires of the concept. Only three dimensions are shown in the plot, the two future states and one past state with greatest variance in the repertoire values. Args: constellation (list(pyphi.models.Concept)): A list of concepts to plot. """ if not constellation: return sub = constellation[0].subsystem n_nodes = sub.size n_states = 2**n_nodes n_concepts = len(constellation) node_labels, sep = fmt.parse_spec(constellation[0], state_fmt) # Get an array of cause-effect repertoires, expanded over the system cause_repertoires = np.zeros((n_concepts, n_states)) effect_repertoires = np.zeros((n_concepts, n_states)) for i, concept in enumerate(constellation): cause_repertoires[i] = concept.expand_cause_repertoire().flatten('F') effect_repertoires[i] = concept.expand_effect_repertoire().flatten('F') # Find the one cause state and two effect states with greatest variance cause_variance = np.var(cause_repertoires, 0) effect_variance = np.var(effect_repertoires, 0) cause_arg = cause_variance.argsort()[-1:] effect_arg = effect_variance.argsort()[-2:] # Set of points in cause-effect space and their size (phi) x = effect_repertoires[:, effect_arg[0]] y = effect_repertoires[:, effect_arg[1]] z = cause_repertoires[:, cause_arg[0]] size = [concept.phi for concept in constellation] # Initialize plot fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # Turn off grid background ax.axis('off') # Draw axes anchor at the origin ax1 = (0, 0) ax3 = (0, 1) # Plan axis colors if color_code_axes: x_ax_color = y_ax_color = 'green' z_ax_color = 'blue' else: x_ax_color = y_ax_color = z_ax_color = 'black' # Draw axes ax.plot(ax1, ax1, ax3, z_ax_color, linewidth=2, zorder=0.3) ax.plot(ax1, ax3, ax1, y_ax_color, linewidth=2, zorder=0.3) ax.plot(ax3, ax1, ax1, x_ax_color, linewidth=2, zorder=0.3) # Label axes with states if label_axes: xs = (1, -0.1, -0.1) ys = (-0.1, 1, -0.1) zs = (-0.1, -0.1, 1) dirs = ('x', 'y', 'z') x_ax_state = loli_index2state(effect_arg[0], n_nodes) y_ax_state = loli_index2state(effect_arg[1], n_nodes) z_ax_state = loli_index2state(cause_arg[0], n_nodes) x_ax_label = r'${}^f$'.format( fmt.state(x_ax_state, node_labels=node_labels, sep=sep)) y_ax_label = r'${}^f$'.format( fmt.state(y_ax_state, node_labels=node_labels, sep=sep)) z_ax_label = r'${}^p$'.format( fmt.state(z_ax_state, node_labels=node_labels, sep=sep)) ax_labels = [x_ax_label, y_ax_label, z_ax_label] for S, D, X, Y, Z in zip(ax_labels, dirs, xs, ys, zs): ax.text(X, Y, Z, S, D) # Add appropriately sized concepts for i in range(n_concepts): ax.scatter(x[i], y[i], z[i], s=size[i] * 1000, marker=u"*", c=u'yellow', zorder=0.1) # Set the ticks for the grid on the plot, no tick labels ax.set_xticks([0, 0.25, 0.5, 0.75, 1]) ax.set_yticks([0, 0.25, 0.5, 0.75, 1]) ax.set_zticks([0, 0.25, 0.5, 0.75, 1]) ax.set_xticklabels([]) ax.set_yticklabels([]) ax.set_zticklabels([]) # Set the size of the space ax.set_zlim(0, 1) ax.set_ylim(0, 1) ax.set_xlim(0, 1) # Default view in elevation and azimuth angle ax.view_init(elev=25, azim=0) # Make actual axes and ticks invisible - using homemade axes ax.w_xaxis.line.set_color((1, 1, 1, 0)) ax.w_yaxis.line.set_color((1, 1, 1, 0)) ax.w_zaxis.line.set_color((1, 1, 1, 0)) ax.tick_params(colors=(1, 1, 1, 0)) # Label stars with their mechanisms if label_stars: star_labels = [] # Holds matplotlib annotation objects for i in range(n_concepts): # Get 2d projection (think "screen coordinates") of the star, since # there's no direct way in matplotlib to annotate a 3D point. x2d, y2d, _ = proj3d.proj_transform(x[i], y[i], z[i], ax.get_proj()) # Get the mechanism's label node_labels, _ = fmt.parse_spec(constellation[0], 'A,') mech_node_labels = [ node_labels[x] for x in constellation[i].mechanism ] mech_label = ','.join(mech_node_labels) # plot and save the label label = ax.annotate(mech_label, xy=(x2d, y2d), xytext=(10, 10), textcoords='offset points') star_labels.append(label) # This callback will update the label positions if the user changes # the plot's perspective interactively. def update_star_labels(event): for i in range(n_concepts): x2d, y2d, _ = proj3d.proj_transform(x[i], y[i], z[i], ax.get_proj()) star_labels[i].xy = x2d, y2d star_labels[i].update_positions(fig.canvas.renderer) fig.canvas.draw() # Register the callback fig.canvas.mpl_connect('button_release_event', update_star_labels) # Show plot plt.show()
def propagation_delay_network(): """A version of the primary example from the IIT 3.0 paper with deterministic COPY gates on each connection. These copy gates essentially function as propagation delays on the signal between OR, AND and XOR gates from the original system. The current and past states of the network are also selected to mimic the corresponding states from the IIT 3.0 paper. Diagram:: +----------+ +------------------+ C (COPY) +<----------------+ v +----------+ | +-------+-+ +-+-------+ | | +----------+ | | | A (OR) +--------------->+ B (COPY) +-------------->+ D (XOR) | | | +----------+ | | +-+-----+-+ +-+-----+-+ | ^ ^ | | | | | | | +----------+ +----------+ | | | +---+ H (COPY) +<----+ +---->+ F (COPY) +---+ | | +----------+ | | +----------+ | | | | | | +-+-----+-+ | | +----------+ | | +----------+ | +-------->+ I (COPY) +-->| G (AND) |<--+ E (COPY) +<--------+ +----------+ | | +----------+ +---------+ Connectivity matrix: +---+---+---+---+---+---+---+---+---+---+ | . | A | B | C | D | E | F | G | H | I | +---+---+---+---+---+---+---+---+---+---+ | A | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | +---+---+---+---+---+---+---+---+---+---+ | B | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+ | C | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+ | D | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+ | E | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+ | F | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+ | G | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | +---+---+---+---+---+---+---+---+---+---+ | H | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+ | I | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | +---+---+---+---+---+---+---+---+---+---+ States: In the IIT 3.0 paper example, the past state of the system has only the XOR gate on. For the propagation delay network, this corresponds to a state of ``(0, 0, 0, 1, 0, 0, 0, 0, 0)``. The current state of the IIT 3.0 example has only the OR gate on. By advancing the propagation delay system two time steps, the current state ``(1, 0, 0, 0, 0, 0, 0, 0, 0)`` is achieved, with corresponding past state ``(0, 0, 1, 0, 1, 0, 0, 0, 0)``. """ num_nodes = 9 num_states = 2**num_nodes tpm = np.zeros((num_states, num_nodes)) for past_state_index in range(num_states): past_state = loli_index2state(past_state_index, num_nodes) current_state = [0 for i in range(num_nodes)] if (past_state[2] == 1 or past_state[7] == 1): current_state[0] = 1 if (past_state[0] == 1): current_state[1] = 1 current_state[8] = 1 if (past_state[3] == 1): current_state[2] = 1 current_state[4] = 1 if (past_state[1] == 1 ^ past_state[5] == 1): current_state[3] = 1 if (past_state[4] == 1 and past_state[8] == 1): current_state[6] = 1 if (past_state[6] == 1): current_state[5] = 1 current_state[7] = 1 tpm[past_state_index, :] = current_state cm = np.array([[0, 1, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 1, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0]]) return Network(tpm, connectivity_matrix=cm)
def plot_3D_constellation(constellation, label_axes=False, label_stars=True, color_code_axes=False, state_fmt='A'): """Generate a 3D-plot of a constellation of concepts in cause-effect space. Examples: >>> big_mip = pyphi.compute.big_mip(sub) >>> plot_3D_constellation(big_mip.unpartitioned_constellation) Written by Billy Marshall, modified by Graham Findlay. Cause-effect space is a high dimensional space, one for each possible past and future state of the system (2 ** (n+1) dimensional for a system of binary elements). Each concept in the constellation is a point in cause-effect space. The size of the point is proportional to the small-phi value of the concept. The location on each axis represents the probability of the corresponding past / future state in the cause-effect repertoires of the concept. Only three dimensions are shown in the plot, the two future states and one past state with greatest variance in the repertoire values. Args: constellation (list(pyphi.models.Concept)): A list of concepts to plot. """ if not constellation: return sub = constellation[0].subsystem n_nodes = sub.size n_states = 2 ** n_nodes n_concepts = len(constellation) node_labels, sep = fmt.parse_spec(constellation[0], state_fmt) # Get an array of cause-effect repertoires, expanded over the system cause_repertoires = np.zeros((n_concepts, n_states)) effect_repertoires = np.zeros((n_concepts, n_states)) for i, concept in enumerate(constellation): cause_repertoires[i] = concept.expand_cause_repertoire().flatten('F') effect_repertoires[i] = concept.expand_effect_repertoire().flatten('F') # Find the one cause state and two effect states with greatest variance cause_variance = np.var(cause_repertoires, 0) effect_variance = np.var(effect_repertoires, 0) cause_arg = cause_variance.argsort()[-1:] effect_arg = effect_variance.argsort()[-2:] # Set of points in cause-effect space and their size (phi) x = effect_repertoires[:, effect_arg[0]] y = effect_repertoires[:, effect_arg[1]] z = cause_repertoires[:, cause_arg[0]] size = [concept.phi for concept in constellation] # Initialize plot fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # Turn off grid background ax.axis('off') # Draw axes anchor at the origin ax1 = (0, 0) ax3 = (0, 1) # Plan axis colors if color_code_axes: x_ax_color = y_ax_color = 'green' z_ax_color = 'blue' else: x_ax_color = y_ax_color = z_ax_color = 'black' # Draw axes ax.plot(ax1, ax1, ax3, z_ax_color, linewidth=2, zorder=0.3) ax.plot(ax1, ax3, ax1, y_ax_color, linewidth=2, zorder=0.3) ax.plot(ax3, ax1, ax1, x_ax_color, linewidth=2, zorder=0.3) # Label axes with states if label_axes: xs = (1, -0.1, -0.1) ys = (-0.1, 1, -0.1) zs = (-0.1, -0.1, 1) dirs = ('x', 'y', 'z') x_ax_state = loli_index2state(effect_arg[0], n_nodes) y_ax_state = loli_index2state(effect_arg[1], n_nodes) z_ax_state = loli_index2state(cause_arg[0], n_nodes) x_ax_label = r'${}^f$'.format(fmt.state(x_ax_state, node_labels=node_labels, sep=sep)) y_ax_label = r'${}^f$'.format(fmt.state(y_ax_state, node_labels=node_labels, sep=sep)) z_ax_label = r'${}^p$'.format(fmt.state(z_ax_state, node_labels=node_labels, sep=sep)) ax_labels = [x_ax_label, y_ax_label, z_ax_label] for S, D, X, Y, Z in zip(ax_labels, dirs, xs, ys, zs): ax.text(X, Y, Z, S, D) # Add appropriately sized concepts for i in range(n_concepts): ax.scatter(x[i], y[i], z[i], s=size[i]*1000, marker=u"*", c=u'yellow', zorder=0.1) # Set the ticks for the grid on the plot, no tick labels ax.set_xticks([0, 0.25, 0.5, 0.75, 1]) ax.set_yticks([0, 0.25, 0.5, 0.75, 1]) ax.set_zticks([0, 0.25, 0.5, 0.75, 1]) ax.set_xticklabels([]) ax.set_yticklabels([]) ax.set_zticklabels([]) # Set the size of the space ax.set_zlim(0, 1) ax.set_ylim(0, 1) ax.set_xlim(0, 1) # Default view in elevation and azimuth angle ax.view_init(elev=25, azim=0) # Make actual axes and ticks invisible - using homemade axes ax.w_xaxis.line.set_color((1, 1, 1, 0)) ax.w_yaxis.line.set_color((1, 1, 1, 0)) ax.w_zaxis.line.set_color((1, 1, 1, 0)) ax.tick_params(colors=(1, 1, 1, 0)) # Label stars with their mechanisms if label_stars: star_labels = [] # Holds matplotlib annotation objects for i in range(n_concepts): # Get 2d projection (think "screen coordinates") of the star, since # there's no direct way in matplotlib to annotate a 3D point. x2d, y2d, _ = proj3d.proj_transform(x[i], y[i], z[i], ax.get_proj()) # Get the mechanism's label node_labels, _ = fmt.parse_spec(constellation[0], 'A,') mech_node_labels = [node_labels[x] for x in constellation[i].mechanism] mech_label = ','.join(mech_node_labels) # plot and save the label label = ax.annotate(mech_label, xy=(x2d, y2d), xytext=(10, 10), textcoords='offset points') star_labels.append(label) # This callback will update the label positions if the user changes # the plot's perspective interactively. def update_star_labels(event): for i in range(n_concepts): x2d, y2d, _ = proj3d.proj_transform(x[i], y[i], z[i], ax.get_proj()) star_labels[i].xy = x2d, y2d star_labels[i].update_positions(fig.canvas.renderer) fig.canvas.draw() # Register the callback fig.canvas.mpl_connect('button_release_event', update_star_labels) # Show plot plt.show()