This commit is contained in:
Moira Daniella A Sebastian
2026-09-06 16:10:46 +02:00
commit 2ae94c2af4

134
Tsetlin_in_Operation.py Normal file
View File

@@ -0,0 +1,134 @@
#!/usr/bin/python
"""
Tsetlin Automata team experiment
--------------------------------
We have 5 independent learning automata. Each one can only choose "No" or "Yes".
Together they form a team. The environment looks at how many said "Yes" (called M)
and then rewards or penalizes them. Over many rounds they learn to keep M near 3,
because that is where the reward probability is highest (0.6).
"""
import random
NUM_AUTOMATA = 5 # team size
STATES_PER_ACTION = 3 # states per action (No / Yes)
ITERATIONS = 10000 # learning rounds
class Environment:
"""Gives reward/penalty based only on M = how many automata said Yes."""
def __init__(self, c_1, c_2):
"""c_1 = 0.2 (step), c_2 = 0.6 (peak reward at M=3)."""
self.c_1 = c_1
self.c_2 = c_2
def give_penalty(self, M):
"""
Sample reward/penalty for one automaton from M.
M = 0..3: P(reward) = M * 0.2
M = 4..5: P(reward) = 0.6 - (M-3)*0.2
Returns True = penalty, False = reward.
Best case is M=3 (P=0.6); too few or too many Yes votes get worse odds.
"""
if M == 0 or M == 1 or M == 2 or M == 3:
if random.random() <= M * self.c_1:
return False
return True
elif M == 4 or M == 5:
if random.random() <= self.c_2 - (M - 3) * self.c_1:
return False
return True
def reward_probability(self, M):
"""Same formulas without randomness — used to print the payoff curve."""
if M == 0 or M == 1 or M == 2 or M == 3:
return M * self.c_1
elif M == 4 or M == 5:
return self.c_2 - (M - 3) * self.c_1
class Tsetlin:
"""
One automaton with actions No/Yes.
With n=3: states 1-3 = No, 4-6 = Yes.
Lower No / higher Yes = more confident. Does not see M, only reward/penalty.
"""
def __init__(self, n):
"""Start at the weak boundary (state n or n+1)."""
self.n = n
self.state = random.choice([self.n, self.n + 1])
def reward(self):
"""Current action was good — move deeper into it (more confident)."""
if self.state <= self.n and self.state > 1:
self.state -= 1
elif self.state > self.n and self.state < 2 * self.n:
self.state += 1
def penalize(self):
"""Current action was bad — move toward the other action (may flip)."""
if self.state <= self.n:
self.state += 1
else:
self.state -= 1
def make_decision(self):
"""Return 'No' or 'Yes' from the current state."""
if self.state <= self.n:
return "No"
return "Yes"
# Build environment and create 5 independent automata
env = Environment(0.2, 0.6)
automata = [Tsetlin(STATES_PER_ACTION) for _ in range(NUM_AUTOMATA)]
m_count = [0] * (NUM_AUTOMATA + 1) # how often each M occurs
# Learning loop: decide -> count Yes (M) -> reward/penalize everyone from M
for _ in range(ITERATIONS):
actions = [la.make_decision() for la in automata]
M = actions.count("Yes")
m_count[M] += 1
print("M:", M, end=" ")
# Shared team feedback: probability depends on M, not on this automaton alone
for j, la in enumerate(automata):
print(f"TA{j + 1} State: {la.state} Action: {actions[j]}", end=" ")
if env.give_penalty(M):
print("Penalty", end=" ")
la.penalize()
else:
print("Reward", end=" ")
la.reward()
print("New State:", la.state, end=" ")
print()
# Results
print("Reward probability P(reward | M):") # theory: peak at M=3
for m in range(NUM_AUTOMATA + 1):
print(f" M={m}: {env.reward_probability(m):.1f}")
print()
print("Final automaton states:") # usually about 3 Yes and 2 No
for i, ta in enumerate(automata, start=1):
print(f" Automaton {i}: state={ta.state} action={ta.make_decision()}")
print()
print(f"Distribution of M over all {ITERATIONS} iterations:") # M=3 should dominate
for m in range(NUM_AUTOMATA + 1):
share = 100.0 * m_count[m] / ITERATIONS
print(f" M={m}: {m_count[m]:6d} ({share:6.2f}%)")
print()
average_m = sum(m * m_count[m] for m in range(NUM_AUTOMATA + 1)) / ITERATIONS
print("Average M over all iterations:") # should be close to 3
print(f" {average_m:.3f}")
print()
print("Optimum of the payoff function is M=3 (P(reward)=0.6).")