Code viewer for World: Artificial Neural Network

// Use JS to write whatever HTML and data you want to the page 

// One way of using JS to write HTML and data is with a multi-line string
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals




document.write ( `
<div id="menu-controls">
            <span id="menu-title"><h2>ANN Logic Gate</h2>
                
            </span>
            <div id="controls">
                <table id="trainAndTest">
                    <tr>
                        <td><span class="info">?<div class="infotext">
                            <p>The <b>ANN</b> model proposed can <b>simulate</b> the behaviour of the most common binary <b>logic gates</b>. 
                            </p> 
                            <p>The choosen gate is displayed alongside in a light blue box.</p> 
                            <p>Use the <u>change</u> link to select a different one.</p> </div></span></td>
                        <td>
                            <span id="changeGateControl">
                                Logic Gate: <span id="gateText"></span>
                            </span>
                        </td>
                        <td>
                            <span class="jsLink" onclick="showLogicGateSelector()">change</span>
                        </td>
                    </tr>
                    <tr>
                        <td><span class="info">?<div class="infotext">
                            <p>Select the inputs desired using the option fields within the <b>input neurons</b>.</p>
                            <p>Clicking the <b>Train</b> button the system will evaluate the inputs and generate the exact computed output.</p>
                            <p>These data will be <b>propagate</b> in the ANN and <b>weigths</b> will be <b>updated</b> accordingly.</p>
                        </div></span></td>
                        <td>Train with <span>i<sub>0</sub>, i<sub>1</sub></span> inputs</td>
                        <td><button id="propagate">Train</button></td>
                    </tr>

                    <tr>
                        <td><span class="info">?<div class="infotext">
                            <p>Use the input field to <b>type a number</b>.</p>
                            <p>The system will use the number to produce as many <b>random</b> examples which will be used to <b>train the ANN</b>.</p>
                        </div></span></td>
                        <td>
                            <div id="n-examples">Train <input type="number" value="100" placeholder="number" id="times" /> times</div>
                        </td>
                        <td>
                            <button id="train">Train</button>
                        </td>
                    </tr>

                    <tr>
                        <td><span class="info">?<div class="infotext">
                            <p>Select the inputs desired using the <b>input neurons</b>.</p>
                            <p>By clicking the <b>Test</b> button, the ANN will evaluate the inputs.</p>
                            <p>The exact result will be highlighted with a <b>light green outer border</b> in the correspondent output neuron. </p>
                            <p>The ANN's computed result will be displayed lighting up in green the correspondent output neuron.</p>
                        </div></span></td>
                        <td>Test with <span>i<sub>0</sub>, i<sub>1</sub></span> inputs</td>
                        <td><button id="test">Test</button></td>
                    </tr>
                    
                    <tr>
                        <td><span class="info">?<div class="infotext">
                            <p>The ANN will save the <b>number of example</b> used to train it.</p>
                            <p><b>Changing</b> the simulated <b>logic gate</b> will <b>reset</b> this number to 0.</p>
                            <p>The <b>accuracy</b> measure the <b>reliability</b> of the ANN,
                            it is calculated <b>testing a set of inputs</b> and elaborating the <b>total error</b>.</p>
                        </div></span></td>
                        <td>
                            <span class="infoANN">Examples fed: <span id="examplesPropagate">0</span></span>
                        </td>
                        <td>
                            <span class="infoANN">Accuracy: <span id="accuracy">00.00</span>%</span>
                        </td>
                    </tr>
                    <tr>
                        <td><span class="info">?<div class="infotext">
                            <p>This option allows users to <b>track the progress</b> of the ANN by <b>displaying the weigths</b>.</p>
                            <p>Weigths are shown in form of a <b>table</b> between the <b>neuron layers</b> involved</p>
                            <p>Weigths table will be <b>updated</b> after every <b>traing process</b>.</p>
                        </div></span></td>
                        <td>Show weigths</td>
                        <td>
                        <label class="switch">
                            <input onclick="toggleWeigths()" id="weigthsCheckbox" type="checkbox">
                            <span class="slider round"></span>
                          </label>
                        </td>
                    </tr>
                </table>
                
                
            </div>
            <br>
        </div>
        <div id="opacityDiv"></div>
        <div id="logicGateSelector">
            <p>Select a logic operator:</p> <div id="logicalOperatorSelector"></div><br>
            <button onclick="changeLogicGate()">Confirm</button><span class="jsLink" onclick="cancelChange()">Cancel</span>
            <p>Changing the logic operator requests the ANN to be reload <br> <i>All training progress will be lost</i></p>
        </div>
        
        <div id="ANN">
            <div class="layer" id="input_layer"></div>
            <div class="weigth"><table id="w_ih"></table></div>
            <div class="layer" id="hidden_layer"></div>
            <div class="weigth"><table id="w_ho"></table></div>
            <div class="layer" id="output_layer"></div>
        </div>
        
        
        <style>
        body{
            font-family: 'Nunito', sans-serif;
            text-align: center;
            background-color: #fff;
            color: #000;
        }
        
        body > * {
            vertical-align: middle;
        }
        
        .layer{
            position: relative;
            display: block;
            margin-top: 0px;
        }
        .neuron{
            position: relative;
            height: 55px;
            width: 55px;
            border-radius: 55px;
            background-color: #035b96;
            line-height: 55px;
            margin: 20px 20px;
            color: #fff;
            display: inline-block;
        }
        table{
            position: relative;
            display: block;
            text-align: center;
            margin: auto;
        }
        td, th{
            padding: 0px 10px 0px 10px;
        }
        select, option{
            border-radius: 5px;
            border: 1px solid #035b96;
            margin-top: 14px;
        }
        input, select, option{
            font-family: 'Nunito', sans-serif;
        }
        .weigth{
            margin-top: 20px;
            display: inline-block;
        }
        .neuron span{
            letter-spacing: -1px;
        }
        #menu-controls{
            text-align: left;
        }
        #menu-title{
            display: inline-block;
            
        }
        #n-examples{
            display: inline-block;
        
        }
        #logicGateSelector{
            top:0px;
            text-align: center;
            border-radius: 10px;
            position: fixed;
            width: 280px;
            padding: 10px;
            left: 50%;
            margin-left: -150px;
            margin-top: -1000%;
            transition: all 0.3s ease;
            z-index: 100;
            background-color: #ffffff;
            -webkit-box-shadow: 0px 0px 46px -27px rgba(0,0,0,0.75);
            -moz-box-shadow: 0px 0px 46px -27px rgba(0,0,0,0.75);
            box-shadow: 0px 0px 46px -27px rgba(0,0,0,0.75);
        }
        #logicGateSelector i{
            color: red;
        }
        .jsLink{
            text-decoration: underline;
            cursor: pointer;
            margin: 4px;
            color: #7d7d7d;
        }
        .selectedOperator{
            background-color: #035b96!important;
            color: #fff!important;
        }
        .activated{
            background-color: rgb(65, 178, 65)!important;
        }
        .target{
            border: 4px solid rgb(154, 241, 154);
        }
        .separator{
            margin-top: 25px;
        }
        .separator hr { 
            display: block; 
            height: 1px;
            border: 0; 
            border-top: 1px solid #ccc;
            margin: 1em 0; 
            padding: 0;
        }
        .subSection{
            position: relative;
            background-color: #fff;
            max-width: 200px;
            margin: auto;
            margin-top: -30px;
        }
        .info{
            color: #ccc;
            border: 1.5px solid #ccc;
            display: inline-block;
            border-radius: 30px;
            width: 15px;
            height: 15px;
            text-align: center;
            line-height: 15px;
            font-size: 13px;
            transition: all 0.4s ease;
            cursor: pointer;
        }
        .info .infotext{
            display: none;
            position: absolute;
            top: 0px;
            left: 30px;
            background-color: #fff;
            padding: 5px 15px;
            border: 1.5px solid #656565;
            border-radius: 5px;
            color: #656565;
            max-width: 250px;
            text-align: justify;
            font-family: 'Nunito', sans-serif;
            font-size: 15.3px;
            line-height: 20px;
            font-style: normal;
            z-index: 98;
        }
        .info:hover .infotext{
            display: block;
        }
        .info:hover{
            color: #656565;
            border: 1.5px solid #656565;
        }
        .operatorSelector{
            display: inline-block;
            padding: 10px;
            background-color: #ceeaff;
            color: #035b96;
            margin: 5px;
            border-radius: 7px;
            cursor: pointer;
            transition: all 0.5s ease;
        }
        .operatorSelector:hover{
            color: #fff;
            background-color: #035b96!important;
        }
        
        #opacityDiv{
            top:0px;
            opacity: 0.2;
            position: fixed;
            width: 100%;
            height: 100%;
            background-color: #fff;
            margin-top: -1000%;
            z-index: 99;
        }
        #changeGateControl, #changeGateControl span, #controls .jsLink{
            font-family: 'Nunito', sans-serif!important;
            font-style: normal!important;
        }
        #gateText{
            font-size: 16px;
            background-color: #ceeaff;
            color: #035b96;
            padding: 3px 7px;
            margin: 5px;
            border-radius: 30px;
        }
        
        button, input{
            background-color: transparent;
            color: #035b96;
            border: 1.5px solid #035b96;
            border-radius: 5px;
            padding: 5px;
        }
        input[type=number] {
            border: 1px solid #ccc!important;
            color: #000!important;
        }
        input::-webkit-outer-spin-button,
        input::-webkit-inner-spin-button {
          -webkit-appearance: none;
          margin: 0;
        }
        
        /* Firefox */
        input[type=number] {
          -moz-appearance: textfield;
        }
        
        button{
            cursor: pointer;
            margin: 4px;
            transition: all 0.5s ease;
            font-weight: bold;
            width: 70px;
        }
        button:hover{
            color: #fff;
            background-color: #035b96;
        }
        
        .neuron span{
            color: #000;
        }
        
        #ANNinfo, #menu-controls{
            display: inline-block;
        }
        table{
            color: #aaa;
        }
        #times{
            width: 60px;
        }
        #controls .jsLink{
            font-size: 16px;
        }
        #menu-title h2{
            position: relative;
            top:2px;
            display: inline-block;
        }
        
        th, .neuron span, #trainAndTest span{
            font-family: 'Noto Serif', serif;
            font-style: italic;
        }
        #trainAndTest{
            color: #000;
            text-align: left;
        }
        .infoANN, .infoANN span{
            font-family: 'Nunito', sans-serif!important;
            font-style: normal!important;
        }
        .infoANN span{
            font-weight: bold;
        }
        #trainAndTest td {
            padding: 4px 4px;
        }
          #ANN{
              display: inline-block;
          }
          #doc-container, #doc-header{
              max-width: 800px;
              text-align: justify;
              margin: auto;
              padding: 5px 20px;
              font-size: 18px;
              
          }
          #doc-container{
              margin-bottom: 150px;
          }
          figure{
              text-align: center;
              padding: 10px 0px;
          }
          figure img{
            max-width: 400px;
            margin: auto;
          }
          figcaption{
              color: #7d7d7d;
          }
          table.illustrate{
              border: 1px solid #7d7d7d;
              display: inline-block;
              color: #000;
              margin: 15px;
          }
        table.illustrate td{
            border: 1px solid #7d7d7d;
        }
        table.illustrate th{
            font-family: 'Nunito', sans-serif;
            color: #035b96;
            font-style: normal;
            border: 1px solid #7d7d7d;
        }
        table.illustrate th i{
            color:#03961a;
            font-style: normal;
        }
        .quote{
            font-style: italic;
            font-weight: bold;
        }
        .in-bl{
            display: inline-block;
        }
        .center-equation{
            line-height: 40px;
            text-align: center;
            margin-bottom: 25px;
        }
        .center-equation .MathJax{
            margin: 0px 30px;
        }
        .mathSerif{
            font-family: 'Times New Roman', Times, serif;
        }
        a, a:visited{
            color: #035b96;
        }
        /********** Slider CSS ***********/

         /* The switch - the box around the slider */
         .switch {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 25px;
          }
          
          /* Hide default HTML checkbox */
          .switch input {
            opacity: 0;
            width: 0;
            height: 0;
          }
          
          /* The slider */
          .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            -webkit-transition: .4s;
            transition: .4s;
          }
          
          .slider:before {
            position: absolute;
            content: "";
            height: 18px;
            width: 18px;
            left: 4px;
            bottom: 4px;
            background-color: white;
            -webkit-transition: .4s;
            transition: .4s;
          }
          
          input:checked + .slider {
            background-color: #035b96;
          }
          
          input:focus + .slider {
            box-shadow: 0 0 1px #035b96;
          }
          
          input:checked + .slider:before {
            -webkit-transform: translateX(23px);
            -ms-transform: translateX(23px);
            transform: translateX(23px);
          }
          
          /* Rounded sliders */
          .slider.round {
            border-radius: 34px;
          }
          
          .slider.round:before {
            border-radius: 50%;
          } 
  /* ************ END SLIDER ********** */
        </style>
` );

/* VARIABLES */
/**
 * This script aims to give a representation of an 
 * ANN using the SGD algorithm.
 * The ANN needs two boolean variables in input and 
 * outputs the result of a logic function.
 */

/**
 * Defining Logical operators as Classes
 */
 class AND{
    constructor(){this.name = 'AND'}
    evaluate = function(a,b){
        return Number(a&&b);
    }
}
class OR{
    constructor(){this.name = 'OR'}
    evaluate = function(a,b){
        return Number(a||b);
    }
}
class NOR{
    constructor(){this.name = 'NOR'}
    evaluate = function(a,b){
        return Number(!(a||b));
    }
}
class XOR{
    constructor(){this.name = 'XOR'}
    evaluate = function(a,b){
        return Number((a && !b) || (b && !a));
    }
}
class NAND{
    constructor(){this.name = 'NAND'}
    evaluate = function(a,b){
        return Number(!(a&&b));
    }
}

/**
 * Select the operator in position binaryOperator[0]
 */
var selectedOperator = 0;

//var unaryOperators = [{0: "NOT"}];
var binaryOperators = [new AND(), new OR(), new XOR(), new NOR(), new NAND()];

var d = 2; // input layer size (default)
var e = 4; // hidden layer size (default)
var f = 2; // output layer size (default)
const noActivationRange = 0;
const activationRange = 1;


/** Values of dataset used to learn */
var input_data_set = []

function createInput(){
    let i1 = Number(Math.random() < 0.5);
    let i2 = Number(Math.random() < 0.5);
    return createInputGiven(i1,i2);
}

function createInputGiven(i1, i2){
    var operator = binaryOperators[selectedOperator];
    var strInput = i1.toString() + i2.toString()
    var result = operator.evaluate(Number(i1),Number(i2));
    var out = obj(result);
    return {input: strInput.toString(), objective: out};
}

var numberOfExamplesPropagate = 0;
/* END VARIABLES */

/* ANN */

/**
 * This script contains the core feautures of the ANN.
 * In the proposed model the ANN will present a single hidden layer
 * Author: Stefano Marzo
 * website: www.stefanomarzo.it
 */

/**
 *  Dimension of layers:
 */
const i_length = d;
const o_length = f;
const h_length = e;

/**
 * Learning rate
 */
var learning_rate = 0.5;

/**
 * Array of weigths between layers in order:
 * (input-hidden), (hidden-output)
 */
var w_ih = [];
var w_ho = [];

/**
 * Arrays containing the neurons of the ANN
 */
var input_layer = [];
var hidden_layer = [];
var output_layer = [];

/**
 * Array containing the Objective values
 */
var objective = [];

/**
 * Initialize all the weights randomly.
 * Weights are stored in the w_xy array container.
 * Access to a weight can be performed by using
 * the w_xy array container with (j,k) indixes
 * representing the j-th neuron giver and the 
 * k-th neuron receiver. E.g. w_ih[1][3] is the
 * weight between input_layer[1] and hidden_layer[3]
 */
function initRandomWeights(){
    w_ih = [];
    w_ho = [];
    for(let i = 0; i < i_length; i++){
        let wi = [];
        for(let j = 0; j < h_length; j++){
            wi.push(Math.random());
        }
        w_ih.push(wi);
    }
    for(let i = 0; i < h_length; i++){
        let wh = [];
        for(let j = 0; j < o_length; j++){
            wh.push(Math.random());
        }
        w_ho.push(wh);
    }
}

/**
 * Function used to create the objective vector.
 * Initialize an array with the same length of the 
 * output_layer array.
 * Pushes noActivationRange value in every cell of
 * the array and sets the activationRange value only
 * to the cell representing the expected output from
 * a training dataset.
 */
function obj(v){
    var l = [];
    for(let i = 0; i < o_length; i++){
        l.push(noActivationRange);
    }
    l[v]=activationRange;
    return l;
}

/**
 * calculate the net function of the j-th hidden neuron 
 */
function neth(j){
    let sum = 0;
    for(let n = 0; n < i_length; n++) {
        sum += input_layer[n]*w_ih[n][j];
    }
    return sum;
}

/**
 * calculate the net function of the k-th output neuron 
 */
function neto(k){
    let sum = 0;
    for(let n = 0; n < h_length; n++) {
        sum += hidden_layer[n]*w_ho[n][k];
    }
    return sum;
}

/**
 * calculate the activation function of the j-th 
 * hidden neuron 
 */
function acth(j){
    return sigmoid(neth(j));
}

/**
 * calculate the activation function of the k-th 
 * output neuron 
 */
function acto(k){
    return sigmoid(neto(k));
}

/**
 * calculate the error function of the k-th output neuron 
 */
function eo(k){
    return Math.pow(objective[k] - output_layer[k], 2)/2;
}

/**
 * calculate the total error function of the ANN 
 */
function etot(){
    let sum = 0;
    for(let n = 0; n < o_length; n++){
        sum += eo(n); 
    }
    return sum;
}

/**
 * calculate the delta parameter used to update weights
 */
function delta(y, z){
    return (output_layer[z]-objective[z]) * output_layer[z] * (1-output_layer[z]) * hidden_layer[y];
}

/**
 * calculate the numeric derivative of the total error
 * with respect to w_ho[y][z].
 * The value is multiplied by learning_rate and is
 * used to update the weight w_ho[y][z].
 */
function newWho(y, z){
    return delta(y, z)*learning_rate;
}

/**
 * calculate the numeric derivative of the total error
 * with respect to w_ih[x][y].
 * The value is multiplied by learning_rate and is
 * used to update the weight w_ih[x][y].
 */
function newWih(x,y){
    let sum = 0;
    for(let z = 0; z < o_length; z++) {
        sum += delta(y,z) * (1 - hidden_layer[y]) * w_ho[y][z] * input_layer[x];
    }
    return sum * learning_rate;
    
}

/**
 * The activation function chosen for the ANN.
 */
function sigmoid(x){
    return activationRange/(1+Math.pow(Math.E,-x));
}

/**
 * The derivative of the activation function 
 * chosen for the ANN.
 */
function sigmoidDeriv(x){
    return sigmoid(x)*(1-sigmoid(x));
}

/**
 * Assuming data is an object in form of:
 * {input: String, objective: Array<Number>}.
 * Sets the ANN's input_layer and objective arrays 
 * by parsing the data.input and data.objective values
 * and using the values of activation stored in 
 * activationRange and noActivationRange.
 * Prepares the ANN to propagate the input and calculate
 * the error.  
 */
function initInputAndObjective(data){
    objective = (data.objective);
    let inputConstuctor = [];
    for(let ch = 0; ch < data.input.length; ch++) {
        let cha = Number(data.input.charAt(ch));
        (cha==0) ? inputConstuctor.push(noActivationRange) : inputConstuctor.push(activationRange);
    }
    input_layer = inputConstuctor;
}

/**
 * Propagates the input by activating all the neurons
 * of hidden and output layers.
 */
function propagate(){
    for(let n = 0; n < h_length; n++) {
        hidden_layer[n] = acth(n);
    }
    for(let n = 0; n < o_length; n++) {
        output_layer[n] = acto(n);
    }
}

/**
 * Calculates the contribution of every weight to
 * the error produced by the ANN and updates the 
 * weights accordingly.
 */
function backpropagate(){
    for(let x = 0; x < i_length; x++){
        for(let y = 0; y < h_length; y++) {
            w_ih[x][y] -= newWih(x,y);
        }
    }
    for(let y = 0; y < h_length; y++){
        for(let z = 0; z < o_length; z++) {
            w_ho[y][z] -= newWho(y,z);
        }
    }
}

/**
 * Incapsulate the process of initialization,
 * propagation and backpropagation with respect 
 * to a given data.
 */
function train(data){
    initInputAndObjective(data);
    propagate();
    backpropagate();
}

/**
 * Accuracy is expressed in terms of %
 * 
 * In this project we can feed the ANN
 * with all the possible combination of
 * inputs due to the manageble size.
 * This may not apply in other cases.
 */
function calculateAccuracy(){
    var eAvarage = calculateAvarageLoss();
    return 100/Math.pow((eAvarage + 1),10);
}

function calculateAvarageLoss(){
    var datas = [
        createInputGiven(0,0),
        createInputGiven(0,1),
        createInputGiven(1,0),
        createInputGiven(1,1),
    ];
    var sumErr = 0;
    for(let input of datas) {
        initInputAndObjective(input);
        propagate();
        sumErr += etot();
    }
    return sumErr/datas.length;
}

initRandomWeights();

/* ANN ENDS */

/* GRAPHICS */
function drawInputLayer(){
    let s = ""
    for(let i = 0; i < i_length; i++) {
        s += '<div id="i'+i+'" class="neuron input_neuron"><br><span>i<sub>'+(i)+'</sub></span></div>';
    }
    document.getElementById("input_layer").innerHTML = s;
}

function drawHiddenLayer(){
    let s = ""
    for(let i = 0; i < h_length; i++) {
        s += '<div id="h'+i+'" class="neuron hidden_neuron"><br><span>h<sub>'+(i)+'</sub></span></div>';
    }
    document.getElementById("hidden_layer").innerHTML = s;
}

function drawOutputLayer(){
    let s = ""
    for(let i = 0; i < o_length; i++) {
        s += '<div id="o'+i+'" class="neuron output_neuron"><br><span>o<sub>'+(i)+'</sub></span></div>';
    }
    document.getElementById("output_layer").innerHTML = s;
}

function drawLayers(){
    drawInputLayer();
    drawHiddenLayer();
    drawOutputLayer();
}



function truncateNumbTo2Decimals(num) {
    return with2Decimals = num.toString().match(/^-?\d+(?:\.\d{0,2})?/)[0];
}

function drawIHWeigths(){
    let s = "<tr><th>Weigth</th>";
    for(i in w_ih[0]){
        s+='<th>h<sub>'+(i)+'</sub></th>';
    }
    s+="</tr>";

    for(i in w_ih){
        s+='<tr><th>i<sub>'+(i)+'</sub></th>';
        for(j in w_ih[i]){
            s+='<td>' + truncateNumbTo2Decimals(w_ih[i][j]) + '</td>';
        }
        s+='</tr>';
    }
    document.getElementById("w_ih").innerHTML = s;
}

function drawHOWeigths(){
    let s = "<tr><th>Weigth</th>";
    for(i in w_ho[0]){
        s+='<th>o<sub>'+(i)+'</sub></th>';
    }
    s+="</tr>";

    for(i in w_ho){
        s+='<tr><th>h<sub>'+(i)+'</sub></th>';
        for(j in w_ho[i]){
            s+='<td>' + truncateNumbTo2Decimals(w_ho[i][j]) + '</td>';
        }
        s+='</tr>';
    }
    document.getElementById("w_ho").innerHTML = s;
}


function drawHiddenActivationValues(){
    for(i in hidden_layer){
        document.getElementById('h'+i).innerHTML = truncateNumbTo2Decimals(hidden_layer[i])
         + '<span><br>h<sub>'+(i)+'</sub></span>';
    }
}

function drawOutputActivationValues(){
    for(i in output_layer){
        document.getElementById('o'+i).innerHTML = truncateNumbTo2Decimals(output_layer[i]) 
        + '<span><br>o<sub>'+(i)+'</sub> &rArr; '+i+'</span>';
    }
}

function provideInputCommands(){
    for(let i = 0; i < i_length; i++) {
        document.getElementById("i"+i).innerHTML = 
        '<select id="inputs'+i+'"><option value="0">0</option><option value="1">1</option></select>'
        +
        document.getElementById("i"+i).innerHTML;
    }
}

function drawWeigths(){
    drawIHWeigths();
    drawHOWeigths();
}
function drawANN(){
    drawLayers();
    drawWeigths();
}


function showLogicGateSelector(){
    document.getElementById('logicGateSelector').style.marginTop = '20px';
    document.getElementById('opacityDiv').style.marginTop = '0%';
}

function hideLogicGateSelector(){
    document.getElementById('logicGateSelector').style.marginTop = '-1000%';
    document.getElementById('opacityDiv').style.marginTop = '-1000%';
}


function drawLogicGates(){
    let s = '';
    for(let i in binaryOperators) {
        s += '<div id="operator'+i+'" onclick="selectOperator('+i+')" class="operatorSelector">'+binaryOperators[i].name+'</div>';
    }
    document.getElementById("logicalOperatorSelector").innerHTML = s;
}


function drawCurrentLogicGate(){
    var text = binaryOperators[selectedOperator].name;
    document.getElementById('gateText').innerText = text;
}

function updateNumOfPropagation(n){
    numberOfExamplesPropagate+=Number(n);
    document.getElementById('examplesPropagate').innerText = numberOfExamplesPropagate;
}

function updateAccuracy(){
    var a = calculateAccuracy();
    var s = '';
    if(a < 10) s += '0';
    document.getElementById('accuracy').innerText = s+truncateNumbTo2Decimals(a);
}

function reDraw(){
    drawANN();
    drawHiddenActivationValues();
    drawOutputActivationValues();
    provideInputCommands();
}

function toggleWeigths(){
    var c = document.getElementById('weigthsCheckbox').checked;
    var w = document.getElementsByClassName('weigth');
    if(c) {
        for(el of w) el.style.display = 'inline-block';
    }
    else{
        for(el of w) el.style.display = 'none';
    }
}

function removeHighlightActivation(){
    var actives = document.getElementsByClassName('activated');
    if(actives.length > 0) {
        for(el of actives) {
            el.classList.remove('activated');
        }
    }
}

function highlightActivation(){
    var max = -1;
    var index = -1;
    for(neuron in output_layer){
        if(output_layer[neuron] > max){ 
            max = output_layer[neuron];
            index = neuron;
        }
    }
    document.getElementById('o'+index).classList.add('activated');
}
function removeHighlightTarget(){
    var targets = document.getElementsByClassName('target');
    if(targets.length > 0) {
        for(el of targets) {
            el.classList.remove('target');
        }
    }
}
function highlightTarget() {
    let nTarget = -1;
    for(let i in objective) {
        if(objective[i] == activationRange) {
            nTarget = i;
        }
    }
    if(nTarget != -1) {
        document.getElementById('o'+nTarget).classList.add('target');
    }
}

drawANN();
toggleWeigths();
provideInputCommands();
/* GRAPHICS END */

/* CONTROLS */
var operatorId = 'operator';

document.getElementById("propagate").onclick = function(){
    let currData = getCurrentData();
    updateNumOfPropagation(1);
    train(currData);
    reDraw();
    //removeHighlightActivation();
    highlightActivation();
    //removeHighlightTarget();
    highlightTarget();
    updateAccuracy();
}

document.getElementById("train").onclick = function(){
    let n = document.getElementById("times").value;
    for(let i = 0; i < n; i++) {
        var data = createInput();
        train(data);
    }
    updateNumOfPropagation(n);
    reDraw();
    //removeHighlightActivation();
    highlightActivation();
    //removeHighlightTarget();
    highlightTarget();
    updateAccuracy();
}

document.getElementById("test").onclick = function(){
    let currData = getCurrentData();
    initInputAndObjective(currData);
    propagate();
    //removeHighlightActivation();
    reDraw();
    highlightActivation();
    highlightTarget();
    updateAccuracy();
}

function getCurrentData(){
    let i1 = document.getElementById("inputs0").value;
    let i2 = document.getElementById("inputs1").value;
    return createInputGiven(i1,i2);
}

function selectOperator(i) {
    /**
     * removes the previous selected class if there's one
     */
    var selectedEl = document.getElementsByClassName('selectedOperator');
    if(selectedEl.length == 1){
        selectedEl[0].classList.remove('selectedOperator')
    }
    /**
     * Select the requested class
     */
    document.getElementById(operatorId+i).classList.add('selectedOperator');
}

/**
 * triggered on confirm to change operator button 
 */
function changeLogicGate(){
    var selectedEl = document.getElementsByClassName('selectedOperator');
    if(selectedEl.length == 1){
        var selOperator = selectedEl[0].id.substring(operatorId.length);
    }
    let hasChanged = selectedOperator != selOperator;
    if(hasChanged){
        selectedOperator = Number(selOperator);
        drawCurrentLogicGate();
        hideLogicGateSelector();
        initRandomWeights();
        reDraw();
        numberOfExamplesPropagate = 0;
        document.getElementById('accuracy').innerText = '0';
        updateNumOfPropagation(0);
    }
}

function cancelChange(){
    hideLogicGateSelector();
    selectOperator(selectedOperator);
}


drawLogicGates();
selectOperator(selectedOperator);
drawCurrentLogicGate();

/* CONTROLS END */