Skip to content
Snippets Groups Projects
NeuralNetwork.cpp 6.23 KiB
Newer Older
/**
 * DESCRIPTION OF THE FILE
 *
 * @author Michal Kravčenko
 * @date 13.6.18 - 
 */

#include "NeuralNetwork.h"
#include "../NetConnection/ConnectionWeightIdentity.h"

NeuralNetwork::NeuralNetwork() {
    this->neurons = new std::vector<Neuron*>(0);
    this->connection_weights = new std::vector<double>(0);

    //TODO tady pozor, pri nedostatecne alokaci se pri pridani hrany nad limit reserve prealokuje cele pole a tim padem padaji reference na vahy v ConnectionWeight
    this->connection_weights->reserve(0);
}

NeuralNetwork::~NeuralNetwork() {
    if(this->neurons){
        delete this->neurons;
        this->neurons = nullptr;
    }
    if(this->output_neurons){
        delete this->output_neurons;
        this->output_neurons = nullptr;
    }
    if(this->input_neurons){
        delete this->input_neurons;
        this->input_neurons = nullptr;
    }
    if(this->active_eval_set){
        delete this->active_eval_set;
        this->active_eval_set = nullptr;
    }
    if(this->connection_weights){
        delete this->connection_weights;
        this->connection_weights = nullptr;
    }
int NeuralNetwork::add_neuron(Neuron *n) {
    this->neurons->push_back(n);
    this->in_out_determined = false;

    return (int)this->neurons->size() - 1;
}

void NeuralNetwork::add_connection_simple(int n1_idx, int n2_idx, int weight_idx, double weight_value) {

    if(weight_idx < 0 || weight_idx >= this->connection_weights->size()){
        //this weight is a new one, we add it to the system of weights
        this->connection_weights->push_back(weight_value);
        weight_idx = (int)this->connection_weights->size() - 1;
    }
    Neuron *neuron_out = this->neurons->at(n1_idx);
    Neuron *neuron_in = this->neurons->at(n2_idx);

    ConnectionWeightIdentity *con_weight_u1u2 = new ConnectionWeightIdentity(this->connection_weights);
    con_weight_u1u2->SetParamIndex(weight_idx, 0);

    Connection *u1u2 = new Connection(neuron_out, neuron_in, con_weight_u1u2);

    neuron_out->add_connection_out(u1u2);
    neuron_in->add_connection_in(u1u2);
}

void NeuralNetwork::add_connection_general(int n1_idx, int n2_idx, std::function<double(double *, int*, int)> *f, int* weight_indices, double* weight_values, int n_weights) {
    ConnectionWeight *con_weight_u1u2 = new ConnectionWeight(n_weights, this->connection_weights, f);
    //we analyze weights
    int weight_idx = 0;
    double weight_value = 0.0;
    for(int wi = 0; wi < n_weights; ++wi){
        weight_idx = weight_indices[wi];
        weight_value = weight_values[wi];

        if(weight_idx < 0 || weight_idx >= this->connection_weights->size()){
            //this weight is a new one, we add it to the system of weights
            this->connection_weights->push_back(weight_value);
            weight_indices[wi] = (int)this->connection_weights->size() - 1;
        }

        con_weight_u1u2->SetParamIndex(weight_indices[wi], wi);
    }

    Neuron *neuron_out = this->neurons->at(n1_idx);
    Neuron *neuron_in = this->neurons->at(n2_idx);
    Connection *u1u2 = new Connection(neuron_out, neuron_in, con_weight_u1u2);

    neuron_out->add_connection_out(u1u2);
    neuron_in->add_connection_in(u1u2);
}

void NeuralNetwork::determine_inputs_outputs() {
    if(this->output_neurons){
        delete this->output_neurons;
    }

    if(this->input_neurons){
        delete this->input_neurons;
    }

    this->output_neurons = new std::vector<Neuron*>(0);
    this->input_neurons = new std::vector<Neuron*>(0);

    if(this->active_eval_set == nullptr){
        this->active_eval_set = new std::vector<Neuron*>(this->neurons->size() * 2);
    }
    else{
        this->active_eval_set->resize(this->neurons->size() * 2);
    }

    for(Neuron* neuron: *this->neurons){
        if(neuron->get_connections_out()->empty()){
            //this neuron has no outgoing connections, it is the output neuron
            this->output_neurons->push_back(neuron);
        }
        else if(neuron->get_connections_in()->empty()){
            //this neuron has no incoming connections, it is the input neuron
            this->input_neurons->push_back(neuron);
        }
    }

    this->n_inputs = (int)this->input_neurons->size();
    this->n_outputs = (int)this->output_neurons->size();

    this->in_out_determined = true;
}

void NeuralNetwork::eval_single(std::vector<double> &input, std::vector<double> &output) {
    if(!this->in_out_determined){
        this->determine_inputs_outputs();
    }


    if(this->n_inputs != input.size()){
        printf("Error, input size != Network input size\n");
        return;
    }

    if(this->n_outputs != output.size()){
        printf("Error, output size != Network output size\n");
        return;
    }

    std::fill(output.begin(), output.end(), 0.0);

    //reset of the potentials
    for(Neuron* neuron: *this->neurons){
        neuron->set_potential(0.0);
        neuron->set_saturation_in(0);
        neuron->set_saturation_out(0);
    }


    int active_set_size[2];
    active_set_size[0] = 0;
    active_set_size[1] = 0;

    int idx1 = 0, idx2 = 1;

    active_set_size[0] = this->n_inputs;
    int i = 0;
    auto n = this->neurons->size();

    for(Neuron* neuron: *this->input_neurons){

        this->active_eval_set->at(i) = neuron;

        neuron->set_potential(input[i]);


        ++i;
    }
    Neuron* active_neuron;
    Neuron* target_neuron;

    while(active_set_size[idx1] > 0){

        //we iterate through the active neurons and propagate the signal
        for(i = 0; i < active_set_size[idx1]; ++i){
            active_neuron = this->active_eval_set->at(i + n * idx1);
            active_neuron->activate();

            for(Connection* connection: *(active_neuron->get_connections_out())){
                connection->pass_signal();

                target_neuron = connection->get_neuron_out();
                target_neuron->adjust_saturation_in(1);

                if(target_neuron->is_saturated_in()){
                    this->active_eval_set->at(active_set_size[idx2] + n * idx2) = target_neuron;
                    active_set_size[idx2]++;
                }
            }
        }

        idx1 = idx2;
        idx2 = (idx1 + 1) % 2;

        active_set_size[idx2] = 0;
    }

    i = 0;
    for(Neuron* neuron: *this->output_neurons){

        output[i] = neuron->get_state();
        ++i;
    }
}