#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 12 12:33:08 2018

Describes network components

@author: yaric
"""

import networkx as nx
import sys

class Node(object):
    """
    This describes network node with specific attributes
    """
    def __init__(self, node_id, neuron_type):
        """
        Creates new network node with specified id for given neuron type
        Argumets:
            node_id: the node ID
            neuron_type: the type of neuron unit presented by this node [0 - hidden, 1 - input, 2 - output, 3 - bias]
        """
        self.node_id = node_id
        self.neuron_type = neuron_type
        
    def color(self):
        """
        Returns color of this node
        """
        if self.neuron_type == 0:
            return 'white'
        elif self.neuron_type == 1:
            return 'blue'
        elif self.neuron_type == 2:
            return 'red'
        else:
            return 'yellow'


class Link(object):
    """
    Represent link between two nodes of the network with associated weight
    """
    def __init__(self, node_in, node_out, weight):
        """
        Creates new network edge connecting particular network nodes
        Argumets:
            node_in: the ID of inputing node
            node_out: the ID of node this link affects
            weight: the weight of this link
        """
        self.node_in = node_in
        self.node_out = node_out
        self.weight = weight

class Network(object):
    """
    This describes simple network consisting from nodes and links between them
    """
    def __init__(self):
        """
        Creates new network and initialize internal structures
        """
        self.nodes = {}
        self.links = []
        
    def addNode(self, node_id, neuron_type):
        """
        Adds specified node to the network
        """
        node = Node(node_id, neuron_type)
        self.nodes[node_id] = node
        
    def addLink(self, node_in, node_out, weight):
        """
        Adds specified link to the network
        """
        link = Link(node_in, node_out, weight)
        self.links.append(link)
        
    def buildGraph(self):
        """
        Builds graph from this network and returns it.
        """
        self.normalize()
        
        g = nx.DiGraph()
        
        for k, n in self.nodes.items():
            g.add_node(n.node_id, color=n.color(), n_type=n.neuron_type)
            
        for l in self.links:
            if l.node_in not in self.nodes or l.node_out not in self.nodes:
                raise Exception('Incorrect link detected')
            elif l.node_in == l.node_out:
                nx.add_cycle(g, [l.node_in, l.node_in], weight=l.weight)
            else:
                g.add_edge(l.node_in, l.node_out, weight=l.weight)    
                
        return g
    
    def normalize(self, offset=0.5):
        """
        Used to perform links normalization to be in range [0, inf), i.e. any
        positive numbers.
        """
        minw = sys.float_info.max
        maxw = sys.float_info.min
        for l in self.links:
            if l.weight < minw:
                minw = l.weight
                
            if l.weight > maxw:
                maxw = l.weight
                
        v = abs(minw) + maxw
        for l in self.links:
            l.weight = offset + (l.weight + abs(minw)) / v
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 12 12:33:08 2018

Describes network components

@author: yaric
"""

import networkx as nx
import sys

class Node(object):
    """
    This describes network node with specific attributes
    """
    def __init__(self, node_id, neuron_type):
        """
        Creates new network node with specified id for given neuron type
        Argumets:
            node_id: the node ID
            neuron_type: the type of neuron unit presented by this node [0 - hidden, 1 - input, 2 - output, 3 - bias]
        """
        self.node_id = node_id
        self.neuron_type = neuron_type
        
    def color(self):
        """
        Returns color of this node
        """
        if self.neuron_type == 0:
            return 'white'
        elif self.neuron_type == 1:
            return 'blue'
        elif self.neuron_type == 2:
            return 'red'
        else:
            return 'yellow'


class Link(object):
    """
    Represent link between two nodes of the network with associated weight
    """
    def __init__(self, node_in, node_out, weight):
        """
        Creates new network edge connecting particular network nodes
        Argumets:
            node_in: the ID of inputing node
            node_out: the ID of node this link affects
            weight: the weight of this link
        """
        self.node_in = node_in
        self.node_out = node_out
        self.weight = weight

class Network(object):
    """
    This describes simple network consisting from nodes and links between them
    """
    def __init__(self):
        """
        Creates new network and initialize internal structures
        """
        self.nodes = {}
        self.links = []
        
    def addNode(self, node_id, neuron_type):
        """
        Adds specified node to the network
        """
        node = Node(node_id, neuron_type)
        self.nodes[node_id] = node
        
    def addLink(self, node_in, node_out, weight):
        """
        Adds specified link to the network
        """
        link = Link(node_in, node_out, weight)
        self.links.append(link)
        
    def buildGraph(self):
        """
        Builds graph from this network and returns it.
        """
        self.normalize()
        
        g = nx.DiGraph()
        
        for k, n in self.nodes.items():
            g.add_node(n.node_id, color=n.color(), n_type=n.neuron_type)
            
        for l in self.links:
            if l.node_in not in self.nodes or l.node_out not in self.nodes:
                raise Exception('Incorrect link detected')
            elif l.node_in == l.node_out:
                nx.add_cycle(g, [l.node_in, l.node_in], weight=l.weight)
            else:
                g.add_edge(l.node_in, l.node_out, weight=l.weight)    
                
        return g
    
    def normalize(self, offset=0.5):
        """
        Used to perform links normalization to be in range [0, inf), i.e. any
        positive numbers.
        """
        minw = sys.float_info.max
        maxw = sys.float_info.min
        for l in self.links:
            if l.weight < minw:
                minw = l.weight
                
            if l.weight > maxw:
                maxw = l.weight
                
        v = abs(minw) + maxw
        for l in self.links:
            l.weight = offset + (l.weight + abs(minw)) / v
#!/usr/bin/env python3 # -*- coding: utf-8 -*- Created on Thu Jul 12 12:33:08 2018  Describes network components  @author: yaric This describes network node with specific attributes Creates new network node with specified id for given neuron type         Argumets:             node_id: the node ID             neuron_type: the type of neuron unit presented by this node [0 - hidden, 1 - input, 2 - output, 3 - bias] Returns color of this node Represent link between two nodes of the network with associated weight Creates new network edge connecting particular network nodes         Argumets:             node_in: the ID of inputing node             node_out: the ID of node this link affects             weight: the weight of this link This describes simple network consisting from nodes and links between them Creates new network and initialize internal structures Adds specified node to the network Adds specified link to the network Builds graph from this network and returns it. Used to perform links normalization to be in range [0, inf), i.e. any         positive numbers.