Skip to content

Commit

Permalink
Merge pull request #14 from CogitoNTNU/feat/genetic-algorithm
Browse files Browse the repository at this point in the history
Feat/genetic algorithm
  • Loading branch information
tobiasfremming authored Nov 12, 2024
2 parents 3a33ebb + ef9c920 commit 841961f
Show file tree
Hide file tree
Showing 22 changed files with 2,427 additions and 755 deletions.
564 changes: 440 additions & 124 deletions main.py

Large diffs are not rendered by default.

404 changes: 404 additions & 0 deletions models/best_genome2961_555819068663.json

Large diffs are not rendered by default.

404 changes: 404 additions & 0 deletions models/best_genome3159_670865969072.json

Large diffs are not rendered by default.

98 changes: 0 additions & 98 deletions neat.py

This file was deleted.

62 changes: 37 additions & 25 deletions src/NEATnetwork.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
from src.genome import Genome
# src/NEATnetwork.py

from collections import defaultdict, deque
import numpy as np
from src.genome import Genome, Node, Connection
from typing import List


class NEATNetwork():
class NEATNetwork:

def __init__(self, genome: Genome):

# Store genome information
self.genome = genome

# Create dictionaries for nodes and connections
self.node_dict = {node.id: node for node in genome.nodes}
self.connection_dict = {conn.innovation_number: conn for conn in genome.connections if conn.enabled}

self.connection_dict = {
conn.innovation_number: conn for conn in genome.connections if conn.enabled
}

# Topologically sort nodes based on connections
self.topological_order = self._topological_sort()

def sigmoid(self, x: np.ndarray) -> np.ndarray:
""" Sigmoid activation function.
Args:
x (np.ndarray): Input array
Returns:
np.ndarray: Output array after applying sigmoid function
"""
"""Sigmoid activation function."""
return 1 / (1 + np.exp(-x))

def ReLU(self, x):
"""ReLU activation function."""
return np.maximum(0, x)

def _topological_sort(self) -> list:
def _topological_sort(self) -> List[int]:
"""
Performs topological sorting on the nodes based on their connections.
"""
Expand All @@ -45,7 +44,10 @@ def _topological_sort(self) -> list:
in_degree[conn.out_node] += 1

# Initialize the queue with input nodes (no incoming connections)
queue = deque([node.id for node in self.genome.nodes if in_degree[node.id] == 0])
input_nodes = [
node.id for node in self.genome.nodes if node.node_type == "input"
]
queue = deque([node_id for node_id in input_nodes if in_degree[node_id] == 0])

topological_order = []
while queue:
Expand All @@ -68,12 +70,19 @@ def forward(self, x: np.ndarray) -> np.ndarray:
Returns:
Output array from the network
"""
if len(x) == 0:
raise ValueError(
"Input array 'x' is empty. Check if 'num_inputs' is set correctly in the genome."
)

# Dictionary to store outputs of each node
node_outputs = {}

# Assume input nodes are provided in the correct order
input_nodes = [node for node in self.genome.nodes if node.node_type == 'input']
output_nodes = [node for node in self.genome.nodes if node.node_type == 'output']
input_nodes = [node for node in self.genome.nodes if node.node_type == "input"]
output_nodes = [
node for node in self.genome.nodes if node.node_type == "output"
]

# Assign input values
for i, node in enumerate(input_nodes):
Expand All @@ -86,18 +95,21 @@ def forward(self, x: np.ndarray) -> np.ndarray:
continue

# Compute the value of this node based on incoming connections
incoming_connections = [conn for conn in self.genome.connections if conn.out_node == node_id and conn.enabled]
incoming_connections = [
conn
for conn in self.genome.connections
if conn.out_node == node_id and conn.enabled
]

node_sum = 0
for conn in incoming_connections:
in_node = conn.in_node
weight = conn.weight
node_sum += node_outputs[in_node] * weight
node_sum = node_sum/50 # Random shit because sum is not normalized
# Apply activation (sigmoid for hidden and output nodes)
node_sum += node_outputs.get(in_node, 0) * weight

# Apply activation (ReLU for hidden and output nodes)
node_outputs[node_id] = self.ReLU(node_sum)

# Collect the outputs for final output nodes
output = np.array([node_outputs[node.id] for node in output_nodes])
return output

output = np.array([node_outputs.get(node.id, 0) for node in output_nodes])
return output / 200 # Normalize the output
Loading

0 comments on commit 841961f

Please sign in to comment.