Source code for pyphi.substrate_generator.utils
# substrate_generator/utils.py
"""Utilities for creating systems."""
import numpy as np
[docs]
def weighted_inputs(element, weights, state):
weights, state = inputs(element, weights, state)
return weights * state
[docs]
def inputs(element, weights, state, ordering="topological", layers=None):
"""Return the inputs being sent to the given element.
Inputs are returned in the order specified by `ordering`.
Topological ordering rotates the indices so that the element is first.
"""
state = np.array(state)
_input_weights = input_weights(element, weights)
if layers is None:
layers = [list(range(weights.shape[0]))]
if ordering == "topological":
_input_weights, state = to_topological_ordering(
element, _input_weights, state, layers
)
idx = np.nonzero(_input_weights)
return _input_weights[idx], state[idx]
[docs]
def to_topological_ordering(element, weights, state, layers):
topo_input_weights = []
topo_state = []
layer_sizes = set()
for layer in layers:
layer_sizes.add(len(layer))
if len(layer_sizes) > 1:
raise NotImplementedError(
"cannot use topological ordering with different layer sizes"
)
sorted_layer = sorted(layer)
layer_input_weights = weights[sorted_layer]
layer_state = state[sorted_layer]
topo_input_weights.extend(np.roll(layer_input_weights, -element))
topo_state.extend(np.roll(layer_state, -element))
return np.array(topo_input_weights), np.array(topo_state)
[docs]
def total_weighted_input(element, weights, state):
"""Return the amount of weighted input being sent to the given element."""
return np.dot(state, weights[:, element])
[docs]
def total_input_weight(element, weights):
"""Return the sum of connection weights being sent to the given element."""
return np.sum(weights[:, element])
[docs]
def input_weights(element, weights):
"""Return the connection weights being sent to the given element."""
return weights[:, element]
[docs]
def sigmoid(energy, temperature=1.0, field=0.0):
"""The logistic function."""
return 1 / (1 + np.exp(-(energy - field) / temperature))
[docs]
def inverse_sigmoid(p, sum_w, field):
"""The inverse of the logistic function."""
return np.log(p / (1 - p)) / (sum_w - field)
[docs]
def map_to_floor_and_ceil(y, floor, ceiling):
"""Rescale an activation probability ``y`` in [0, 1] to [floor, ceiling]."""
return floor + (ceiling - floor) * y
[docs]
def binary2spin(binary_state):
"""Return the Ising spin state corresponding to the given binary state.
This just replaces 0 with -1.
"""
state = np.array(binary_state)
state[np.where(state == 0)] = -1
return state