All pastes #1298876 Raw Edit

Stuff

public text v1 · immutable
#1298876 ·published 2009-01-03 09:35 UTC
rendered paste body
import random

class HopfieldUnit(object):
  def __init__(self):
    # Bullpoop default values for inputs and weights so I know what's in the
    # object
    self.inputs = []
    self.weights = []
    self.state = False
    # set to True initially so that HopfieldNetwork won't falsely report
    # convergence
    self.has_changed = True

  def update(self):
    old_state = self.state

    # Take weighted sum of inputs
    weighted_sum = sum(u.state * w for u, w in zip(self.inputs, self.weights))

    if weighted_sum >= 0:
      new_state = True
    else:
      new_state = False

    # Used to tell whether the Hopfield network has converged
    if old_state == new_state:
      self.has_changed = False

    self.state = new_state

class HopfieldNetwork(object):
  def __init__(self, n):
    self.units = []
    # Preserved for convenience
    self.n = n

    # Fill the network with n Hopfield units
    for i in xrange(n):
      self.units.append(HopfieldUnit())
      # Weights are initially zeros--there are n, rather than n-1 weights
      # for simplicity. For any unit j, its own weight is always zero and
      # essentially ignored
      self.units[-1].weights = [0] * n

    # Make a complete graph of interconnects
    for i in xrange(n):
      # Tuple saves memory
      # inputs = tuple([u for u, j in zip(self.units, range(n)) if j != i])
      inputs = tuple(self.units)
      self.units[i].inputs = inputs

  def _get_state(self):
    state_vector = []

    for u in self.units:
      state_vector.append(u.state)

    return state_vector

  def _set_state(self, state_vector):
    for i in xrange(self.n):
      self.units[i].state = state_vector[i]

  state = property(_get_state, _set_state)

  def _has_converged(self):
    for u in self.units:
      if u.has_changed == True:
        return False

    # Fall-through
    return True

  has_converged = property(_has_converged)

  def train(self, pattern):
    for j in xrange(self.n):
      # j has j as its own input, but the weight is zero and plays no role
      for i in [i for i in xrange(self.n) if i != j]:
        if pattern[j] == pattern[i]:
          self.units[j].weights[i] += 1
        else:
          self.units[j].weights[i] -= 1

  def recall(self):
    # run update loop until convergence
    while not self.has_converged:
      # update_schedule is the list that tells this method which order to
      # update the Hopfield units in
      update_schedule = range(self.n)
      # it is randomized to simulate biological behavior
      random.shuffle(update_schedule)

      for i in update_schedule:
        self.units[i].update()