public static double[] main(String[] args) {
        /*
        int[] numUnits = {1, 4, 4, 1}; // 4-4-1 network
        Network ctrlNet = new Network(3, numUnits); // our control
        Network net = new Network(3, numUnits);
        double[][] trainingInputs = new double[100][];
        double[][] trainingOutputs = new double[100][];
        for (int i = 0; i < 100; i++) {
            double x = (double) i / 100;
            trainingInputs[i] = new double[] {x};
            trainingOutputs[i] = new double[] {Math.sin(Math.PI*x) + 2};
        }
        for (int j = 0; j < 100; j++) {
            net.trainOnFunction(trainingInputs, trainingOutputs);
            System.out.println(net.run(trainingInputs[0])[0] - trainingOutputs[0][0]);
        }
        */

        int[] numUnits = {1, 4, 4, 1};
        Network net = new Network(3, numUnits);

        // manually training the network
        /*
        net.dummyNode.getOutgoingEdges().get(0).a = 1 + 0.1;
        net.dummyNode.getOutgoingEdges().get(0).b = 1 + 0.1;
        net.dummyNode.getOutgoingEdges().get(1).a = Math.sqrt(3) + 0.1;
        net.dummyNode.getOutgoingEdges().get(1).b = Math.sqrt(2) + 0.1;
        net.nodes[0][0].getOutgoingEdges().get(0).a = Math.sqrt(2) + 0.1;
        net.nodes[0][0].getOutgoingEdges().get(0).b = Math.sqrt(3) + 0.1;
        net.nodes[1][0].getOutgoingEdges().get(0).a = 0 + 0.1;
        net.nodes[1][0].getOutgoingEdges().get(0).b = 1 + 0.1;
        */

        final int SAMPLES = 100;
        double[][] trainingInputs = new double[SAMPLES][];
        double[][] trainingOutputs = new double[SAMPLES][];
        for (int i = 0; i < SAMPLES; i++) {
            double x = (double) i / SAMPLES;
            trainingInputs[i] = new double[] {x};
            //trainingOutputs[i] = new double[] {3*Math.pow(3*x+1, 2) / (22*x*x + 16*x + 3)};
            trainingOutputs[i] = new double[] {Math.sin(Math.PI*x) + 2};
        }
        double errorL2 = 0;
        for (int i = 0; i < 1000; i++) {
            net.trainOnFunction(trainingInputs, trainingOutputs);
            double[] y = new double[5];
            for (int j = 0; j < 5; j++) {
                y[j] = net.run(trainingInputs[20*j])[0];// - trainingOutputs[j][0];
            }
            double errorL2_new = 0;
            for (int j = 0; j < SAMPLES; j++) {
                errorL2_new += Math.pow(net.run(trainingInputs[j])[0] - trainingOutputs[j][0], 2) / SAMPLES;
            }
            if (errorL2_new < errorL2) {
                Globals.ETA *= 1.05;
            } else if (errorL2_new / errorL2 > 1.0001) {
                Globals.ETA /= 2;
            }
            errorL2 = errorL2_new;
            System.out.printf("Round %d: %s; error = %.9f, eta = %.9f\n", i+1, Arrays.toString(y), Math.sqrt(errorL2), Globals.ETA);
            System.out.println(trainingOutputs[20][0]);
            double a = net.nodes[0][0].getOutgoingEdges().get(0).a;
            double b = net.nodes[0][0].getOutgoingEdges().get(0).b;
            //System.out.printf("(%f, %f)\n", a, b);
        }
        double[] retval = new double[100];
        for (int i = 0; i < 100; i++) {
            retval[i] = net.run(trainingInputs[i])[0];
        }
        return retval;
    }