class HopfieldNetwork:
def __init__(self, k, threshold=0):
self.k = k
self.threshold = threshold
def calculate_energy(self, x):
return -0.5*np.sum(np.matmul(x.T, x)*self.w) + np.sum(x*self.threshold)
def train(self, data):
self.w = np.zeros((self.k, self.k))
for x in data:
self.w += self.calculate_w_per_sample(x)
#print("w:", self.w)
def activation(self, z):
if z > self.threshold:
return 1
return -1
def predict(self, x): #update
x = x.copy()
x = x.reshape(1, -1)
#async update
max_epoch = 1
counter = 0 # counter or not changed states
for e in range(max_epoch):
if (counter > self.k):
break
order = np.arange(self.k)
np.random.shuffle(order)
for i in order:
x_i = x @ self.w[i]
x_i_a = self.activation(x_i)
if (x_i_a != x[0,i]):
counter += 1
x[0,i] = x_i_a
if (self.k < 101):
print("State:", x)
else:
print("Energy:", self.calculate_energy(x))
return x
def calculate_w_per_sample(self, x):
x = x.reshape(1, -1)
n = x.shape[1]
w = np.matmul(x.T, x) * (1 - np.eye(n))
return w
data = np.array([ [1,1,1,1,-1,-1,-1], [-1,1,-1,1,-1,1,-1], [-1,-1,1,1,-1,1,-1] ])
print("Printing only changed states...")
hn = HopfieldNetwork(7)
hn.train(data)
final_state = hn.predict(np.array([-1,-1,-1,1,-1,-1,-1]))
print("final state:", final_state)