[FRUIT CLASSIFIER]
shape=int(input("Enter the shape of fruit - 0=elliptical | 1=round: "))
texture=int(input("Enter the texture of fruit - 0=rough | 1=smooth: "))
fruit=int(input("Enter the fruit type - 0=orange | 1=apple: "))

w1=2
w2=2
w3=1
bias=-3

s=(w1*shape + w2*texture + w3*fruit)+bias
print(f"value of s is {s}")

output=-1
if(s>=0):
    output=1
else:
    output=0

print(f"Fruit detected is: {('Orange' if output==0 else 'Apple')}")



[HOPFIELD FACE]
import numpy as np
# 1) Emoji → Bipolar Conversion

def to_bipolar(mat):
    return np.array([1 if c=="🟨" else -1 for row in mat for c in row])

def show(vec):
    for i in range(6):
        row = vec[i*6:(i+1)*6]
        print("".join(["🟨" if x==1 else "⬛" for x in row]))
    print()

# 2) Define all patterns (Smiley / Neutral / Sad)

smiley = [
"🟨🟨🟨🟨🟨🟨",
"🟨⬛🟨🟨⬛🟨",
"🟨🟨🟨🟨🟨🟨",
"🟨⬛🟨🟨⬛🟨",
"🟨⬛⬛⬛⬛🟨",
"🟨🟨🟨🟨🟨🟨"
]

sad = [
"🟨🟨🟨🟨🟨🟨",
"🟨⬛🟨🟨⬛🟨",
"🟨🟨🟨🟨🟨🟨",
"🟨🟨🟨🟨🟨🟨",
"🟨⬛⬛⬛⬛🟨",
"🟨⬛🟨🟨⬛🟨"
]

# Convert to bipolar vectors
P1 = to_bipolar(smiley)
P3 = to_bipolar(sad)

patterns = [P1, P3]

# 3) Train Hopfield Network

N = len(P1)
W = np.zeros((N, N))

for P in patterns:
    W += np.outer(P, P)

np.fill_diagonal(W, 0)

# 4) Define custom noisy pattern HERE (your manual input)

noisy_pattern = [
"🟨🟨🟨🟨⬛🟨",
"🟨⬛🟨🟨🟨🟨",
"🟨🟨🟨🟨🟨🟨",   # <--- I made these 2 rows noisy
"🟨🟨🟨🟨⬛🟨",   # <--- You can change anything here
"🟨🟨⬛⬛⬛🟨",
"🟨⬛🟨🟨⬛🟨"
]

noisy = to_bipolar(noisy_pattern)

# ---------------------------------------------------------
# 5) Hopfield Recall
# ---------------------------------------------------------

def recall(x):
    prev = np.zeros_like(x)
    x = x.copy()
    while not np.array_equal(x, prev):
        prev = x.copy()
        x = np.sign(W @ x)
        x[x==0] = 1
    return x

# ---------------------------------------------------------
# 6) Show results
# ---------------------------------------------------------

print("🔸 Noisy Input:")
show(noisy)

recovered = recall(noisy)

print("🔹 Recovered Output:")
show(recovered)





[KSOM]
'''
1. Load dataset
2. Normalize
3. Define #neurons (clusters)
4. Initialize weight vectors
5. Training loop (BMU update)
6. Assign inputs to nearest neuron
7. Map neurons → cluster names
'''

import numpy as np
X=np.array([
    [22,45,30,0,2],   # P1
    [28,15,60,5,8],   # P2
    [31,10,80,10,12], # P3
    [24,60,55,0,5],   # P4
    [20,30,20,0,1],   # P5
    [27,20,70,7,9]    # P6
])

patients=["p1", "p2", "p3", "p4", "p5", "p6"]

X=(X-X.min(axis=0))/(X.max(axis=0)-X.min(axis=0))

clusters=4      # if the question has said for 4, then use 4 only
learning_rate=0.6
epochs=450

W=np.random.rand(clusters, 5)

for i in range(epochs):
    for x in X:
        d=np.linalg.norm(W-x, axis=1)
        bestMatch=np.argmin(d)
        W[bestMatch]+=learning_rate*(x-W[bestMatch])

assignments={}
for i,x in enumerate(X):
    d=np.linalg.norm(W-x, axis=1)
    c=np.argmin(d)
    assignments[patients[i]]=c+1

print("THUS, THE FINAL THING THAT WE ARE GETTING IS:-")
for p in patients:
    print(f"{p} => Cluster {assignments[p]}")


print("\nNOTE, FOR THE ABOVE, THIS IS WHAT THE CLUSTER MEANS:-")
print("1: Healthy Lifestyle")
print("2: Moderate Risk")
print("3: High Risk")
print("4: Active but High Sugar Intake")



[LVQ]
import numpy as np
# Each row is: [Stress, Sleep, Screen, Social, Work]
X=np.array([
    [3,8,3,6,6],    # P1
    [7,5,4,2,10],   # P2
    [5,6,8,1,7],    # P3
    [8,4,6,1,11],   # P4
    [4,7,5,5,7],    # P5
    [9,3,7,0,12]    # P6
])

# Labels as class numbers
# C1=1, C2=2, C3=3, C4=4
y=np.array([1,2,3,4,1,4])

people=["P1","P2","P3","P4","P5","P6"]

# 2. NORMALIZATION (0-1 scaling)

Xmin=X.min(axis=0)
Xmax=X.max(axis=0)
X=(X-Xmin)/(Xmax-Xmin)

# 3. LVQ PARAMETERS

classes=4                    # number of output classes
learning_rate=0.4
epochs=5

# 4. INITIAL CODEBOOK VECTORS

# since there are 5 features, so, we have this in this format-with 5classes (attributes)
W=np.zeros((classes,5))

# Class reps: C1→P1, C2→P2, C3→P3, C4→P4
W[0]=X[0]   # C1
W[1]=X[1]   # C2
W[2]=X[2]   # C3
W[3]=X[3]   # C4


# ===============================
# 5. LVQ TRAINING
# ===============================

for ep in range(epochs):
    for i,x in enumerate(X):

        # compute distance to all prototypes
        d=np.linalg.norm(W-x,axis=1)
        bmu=np.argmin(d)   # Best Matching Unit

        # LVQ UPDATE
        if (bmu+1)==y[i]:          # correct class prototype
            W[bmu]+=learning_rate*(x-W[bmu])
            print("USED POSITIVE UPDATE")
        else:                      # wrong prototype
            W[bmu]-=learning_rate*(x-W[bmu])
            print("USED NEGATIVE UPDATE")


# 6. CLASSIFICATION OF ALL INPUTS

assignments={}

for i,x in enumerate(X):
    d=np.linalg.norm(W-x,axis=1)
    c=np.argmin(d)+1
    assignments[people[i]]=c


# 7. FINAL OUTPUT

print("=== FINAL LVQ CLASSIFICATION RESULTS ===")
for p in people:
    print(f"{p} => Class {assignments[p]}")

print("\n=== CLASS MEANINGS ===")
print("1: Balanced & Healthy")
print("2: Workaholics with Stress")
print("3: Screen-Dependent & Isolated")
print("4: Vulnerable Group")


[MAZE SOLVER]
import numpy as np
from collections import deque

maze=np.array([[0,1,0,0,0,0],
               [0,1,0,1,1,0],
               [0,0,0,0,1,1],
               [1,0,1,0,1,0],
               [0,0,1,0,0,0]])

start=(0,0)
end=(4,5)

class agent:
    def __init__(self,maze,start,end):
        self.maze=maze
        self.start=start
        self.end=end
        self.rows=len(maze)
        self.cols=len(maze[0])

    def directions(self,x,y):
        return {
            "up":(x>0 and self.maze[x-1][y]==0,(x-1,y)),
            "down":(x<self.rows-1 and self.maze[x+1][y]==0,(x+1,y)),
            "left":(y>0 and self.maze[x][y-1]==0,(x,y-1)),
            "right":(y<self.cols-1 and self.maze[x][y+1]==0,(x,y+1))
        }

    def neighbors(self,x,y):
        moves=self.directions(x,y)
        n=[]
        for ok,(nx,ny) in moves.values():
            if ok:
                n.append((nx,ny))
        return n

    def bfs(self):
        q=deque()
        q.append((self.start,[self.start]))
        visited=set([self.start])

        while q:
            (x,y),path=q.popleft()

            if (x,y)==self.end:
                return path

            for nx,ny in self.neighbors(x,y):
                if (nx,ny) not in visited:
                    visited.add((nx,ny))
                    q.append(((nx,ny),path+[(nx,ny)]))
        return None


def print_maze(maze,path=None):
    path=set(path) if path else set()
    for i,row in enumerate(maze):
        for j,cell in enumerate(row):
            if (i,j) in path:
                print("🟩",end=" ")
            elif cell==1:
                print("⬛",end=" ")
            else:
                print("⬜",end=" ")
        print()
    print()


if __name__=="__main__":
    a=agent(maze,start,end)
    path=a.bfs()

    print("Shortest path:",path)
    print("\nMaze visualization:\n")
    print_maze(maze,path)



[RANDOM BAM]
import numpy as np

# ---------------------------------------------------
# Encode string into bipolar vector (simple method)
# ---------------------------------------------------
def encode_word(word, size=8):
    """
    Encodes a word into a fixed-size bipolar vector.
    Uses ASCII sum mod 2 for each bit — simple + works.
    """
    x = np.zeros(size)
    s = sum(ord(c) for c in word)

    for i in range(size):
        bit = (s >> i) & 1
        x[i] = 1 if bit == 1 else -1
    return x

# BAM TRAINING RULE: W = sum(x_i outer y_i)
def train_bam(pairs, size_x=8, size_y=8):
    W = np.zeros((size_x, size_y))
    for (a, b) in pairs:
        x = encode_word(a, size_x)
        y = encode_word(b, size_y)
        W += np.outer(x, y)
    return W

# Recall Function (Bidirectional)
def recall_x_to_y(W, x):
    y = np.sign(x @ W)
    y[y==0] = 1
    return y

def recall_y_to_x(W, y):
    x = np.sign(W @ y)
    x[x==0] = 1
    return x

# ---------------------------------------------------
# Helper: Nearest decoded word (OPTIONAL)
# ---------------------------------------------------
def decode(vec, dictionary, size=8):
    best = None
    best_dist = 9999
    for w in dictionary:
        v = encode_word(w, size)
        d = np.linalg.norm(vec - v)
        if d < best_dist:
            best_dist = d
            best = w
    return best

# 20 PAIRS OF RELATED/UNRELATED OBJECTS]

pairs = [
    ("dog", "animal"),
    ("cat", "animal"),
    ("chair", "furniture"),
    ("car", "vehicle"),
    ("apple", "fruit"),
    ("banana", "fruit"),
    ("tiger", "wild"),
    ("rose", "flower"),
    ("bed", "furniture"),
    ("fan", "appliance"),
    ("phone", "device"),
    ("laptop", "device"),
    ("sun", "star"),
    ("moon", "satellite"),
    ("shirt", "clothes"),
    ("jeans", "clothes"),
    ("bus", "vehicle"),
    ("train", "vehicle"),
    ("milk", "dairy"),
    ("butter", "dairy")
]

# Build dictionary of all words
dictionary = set([w for p in pairs for w in p])

# ---------------------------------------------------
# TRAIN BAM
# ---------------------------------------------------
W = train_bam(pairs)

# ---------------------------------------------------
# TESTING
# ---------------------------------------------------

test_word = "tiger"
x = encode_word(test_word)
y_recalled = recall_x_to_y(W, x)

print(f"Input X word: {test_word}")
print("X→Y recalled vector:", y_recalled)

decoded = decode(y_recalled, dictionary)
print("Decoded as:", decoded)

# Try reverse (Y→X)
test_word_y = "furniture"
y = encode_word(test_word_y)
x_recalled = recall_y_to_x(W, y)

print(f"\nInput Y word: {test_word_y}")
print("Y→X recalled vector:", x_recalled)
decoded2 = decode(x_recalled, dictionary)
print("Decoded as:", decoded2)


