def Train(self, inputs, targets):
        # Calc errors
        self.FeedForward(inputs)
        targets = Matrix.FromArray(targets)
        output_errors = Matrix.Subtract(targets, self.outputs)
        weights_ho_T = Matrix.Transpose(self.weights_ho)
        hidden_errors = Matrix.Multiply(weights_ho_T, output_errors)
        # Calc gradients
        gradient_o = Matrix.StaticMap(self.outputs, dsigmoid)
        gradient_o.ElementMultiply(output_errors)
        gradient_o.ElementMultiply(self.lr)
        hidden_T = Matrix.Transpose(self.hidden)
        delta_weights_ho = Matrix.Multiply(gradient_o, hidden_T)

        gradient_h = Matrix.StaticMap(self.hidden, dsigmoid)
        gradient_h.ElementMultiply(hidden_errors)
        gradient_h.ElementMultiply(self.lr)
        input_T = Matrix.Transpose(self.inputs)
        delta_weights_ih = Matrix.Multiply(gradient_h, input_T)

        # Adjusting weights and biases
        # self.weights_ih.Display()
        self.weights_ih.Add(delta_weights_ih)
        self.bias_h.Add(gradient_h)
        # delta_weights_ho.Display()
        self.weights_ho.Add(delta_weights_ho)
        self.bias_o.Add(gradient_o)
 def FeedForward(self, arr):
     # Hidden nodes
     self.inputs = Matrix.FromArray(arr)
     self.hidden = Matrix.Multiply(self.weights_ih, self.inputs)
     self.hidden.Add(self.bias_h)
     self.hidden.Map(sigmoid)
     # Output nodes
     self.outputs = Matrix.Multiply(self.weights_ho, self.hidden)
     self.outputs.Add(self.bias_o)
     self.outputs.Map(sigmoid)
     return self.outputs