'Train the machine.
Parameters
data: A matrix where each row is a training example consisting of the states of visible units.'

def train(self, data, max_epochs=1000, learning_rate=0.1):

    num_examples = data.shape[0]
    data = np.insert(data, 0, 1, axis=1)
    for epoch in range(max_epochs):
        pos_hidden_activations = np.dot(data, self.weights)
        pos_hidden_probs = self._logistic(pos_hidden_activations)
        pos_hidden_probs[:, 0] = 1
        pos_hidden_states = (pos_hidden_probs > np.random.rand(num_examples, (self.num_hidden + 1)))
        pos_associations = np.dot(data.T, pos_hidden_probs)
        neg_visible_activations = np.dot(pos_hidden_states, self.weights.T)
        neg_visible_probs = self._logistic(neg_visible_activations)
        neg_visible_probs[:, 0] = 1
        neg_hidden_activations = np.dot(neg_visible_probs, self.weights)
        neg_hidden_probs = self._logistic(neg_hidden_activations)
        neg_associations = np.dot(neg_visible_probs.T, neg_hidden_probs)
        self.weights += (learning_rate * ((pos_associations - neg_associations) / num_examples))
        error = np.sum(((data - neg_visible_probs) ** 2))
        if self.debug_print:
            print(('Epoch    %s:    error    is    %s' % (epoch, error)))
