@Override
    synchronized
    public void train() {
        //
        this.init();
        //
        this.notifyStarted();
        //
        // iterate epochs.
        //
        final SampleSet tset = this.trainset;
        //
        double[] minweights = this.net.getWeights().clone();
        double minerror = Double.MAX_VALUE;
        int count = 0;
        //
        for (int i = 0; i < this.epochs; i++) {
            this.epoch = i;
            //
            DoubleTools.fill(this.weights, 1, this.weightsnum, this.rnd, this.lbd, this.ubd);
            double error = NetTools.computeError(this.net, tset);
            //
            this.trainerror = error;
            this.validationerror = error;
            //
            if (error < minerror) {
                minerror   = error;
                minweights = this.net.getWeights().clone();
            }
            //
            this.notifyEpoch();
            //
            if (this.validationerror < this.targeterror) {
                break;
            }
            count++;
        }
        //
        // take best weights.
        //
        if (count > 0) {
            this.trainerror      = minerror;
            this.validationerror = minerror;
            DoubleTools.copy(minweights, 1, this.weights, 1, this.weightsnum);
        }
        //
        this.notifyFinished();
    }