static void Main(string[] args)
        {
            // 階層型ニューラルネットワークを構成
            var nn = new HierarchicalNetwork(2, 2, 1);
            nn[1, 0].Weights[0] = 10.0;
            nn[1, 0].Weights[1] = 10.0;
            nn[1, 0].Threshold = -5.0;
            nn[1, 1].Weights[0] = 10.0;
            nn[1, 1].Weights[1] = 10.0;
            nn[1, 1].Threshold = -15.0;
            nn[2, 0].Weights[0] = 10.0;
            nn[2, 0].Weights[1] = -10.0;
            nn[2, 0].Threshold = -5.0;

            // 発火
            nn.SetInputs(new ConstOutput(0.0), new ConstOutput(1.0));
            nn.Fire();

            // グラフを出力
            var gen = new GraphGenerator();
            using (var writer = new StreamWriter("graph.gv"))
            {
                gen.Generate(writer, nn);
            }
        }
        static void Main(string[] args)
        {
            Func<double, double> f = ((double x) => 1 / (1 + Math.Exp(-x)));
            Func<double, double> df = (x => f(x) * (1 - f(x)));

            // ネットワークの情報読み込み
            HierarchicalNetwork nn;
            var examples = new List<Tuple<double[], double[]>>();

            Console.Error.Write("path >");
            var path = Console.ReadLine();
            using (var reader = new StreamReader(path))
            {
                nn = new HierarchicalNetwork(reader.ReadLine().Split(' ').Select(v => int.Parse(v)).ToArray());
                var exNum = int.Parse(reader.ReadLine());
                for (var i = 0; i < exNum; ++i)
                {
                    var io = reader.ReadLine().Split('|').ToList();
                    examples.Add(Tuple.Create(
                        io[0].Split(' ').Select(v => double.Parse(v)).ToArray(),
                        io[1].Split(' ').Select(v => double.Parse(v)).ToArray()
                        ));
                }
            }

            // 学習
            var bp = new Backpropagation(nn, df, 0.8, 0.75);
            var rnd = new Random();
            using (var writer = new StreamWriter("error.csv"))
            {
                for (var i = 0; i < 1000; ++i)
                {
                    var ex = examples.OrderBy(v => Guid.NewGuid()).ToArray(); // shuffle
                    var errSum = 0.0;
                    for (var j = 0; j < ex.Length; ++j)
                    {
                        bp.Train(ex[j].Item1, ex[j].Item2);
                        errSum += bp.Error;
                    }
                    writer.WriteLine("{0},{1}", i, errSum / ex.Length);
                }
            }

            while (true)
            {
                Console.Error.Write("input >");
                var inputs = Console.ReadLine().Split(' ').Select(v => new ConstOutput(double.Parse(v))).ToArray();
                nn.SetInputs(inputs);
                nn.Fire();
                foreach (var o in nn.GetOutputs())
                {
                    Console.WriteLine("{0:0.0########################################################}", o);
                }
            }
        }
        public Backpropagation(HierarchicalNetwork network, Func<double, double> diffTransferFunction, double learningRate, double stabilizationRate)
        {
            Network = network;
            DiffTransferFunction = diffTransferFunction;
            LearningRate = learningRate;
            StabilizationRate = stabilizationRate;
            Error = 0.0;

            // allocation
            var layers = Network.LayersCount;
            delta = new double[layers][];
            dw = new double[layers][][];
            dh = new double[layers][];
            delta[0] = new double[0];
            dw[0] = new double[0][];
            dh[0] = new double[0];
            var prevCnt = Network.GetNeuronsCount(0);
            for (var layer = 1; layer < layers; ++layer)
            {
                var cnt = Network.GetNeuronsCount(layer);
                delta[layer] = new double[cnt];
                dw[layer] = new double[cnt][];
                dh[layer] = new double[cnt];
                for (var i = 0; i < cnt; ++i)
                {
                    delta[layer][i] = 0.0;
                    dw[layer][i] = new double[prevCnt];
                    dh[layer][i] = 0.0;
                    for (var j = 0; j < prevCnt; ++j)
                    {
                        dw[layer][i][j] = 0.0;
                    }
                }
                prevCnt = cnt;
            }
        }
        public void Generate(StreamWriter writer, HierarchicalNetwork nn, string name = "hierarchical_nn")
        {
            writer.WriteLine("digraph {0} {{", name);
            writer.WriteLine("\tgraph [rankdir=LR, ranksep=1.0];");

            // subgraph in
            writer.WriteLine("\tsubgraph in {");
            writer.WriteLine("\t\tcolor=gray;");
            writer.WriteLine("\t\tnode[style=invis, fixedsize=true, width=0, height=0];");
            writer.WriteLine("\t\t{0};", string.Join(", ",
                Enumerable.Range(0, nn.InputDimention)
                .Select(i => string.Format("i{0}", i + 1))
                ));
            writer.WriteLine("\t}");

            // clusters
            for (var i = 0; i < nn.LayersCount; ++i)
            {
                writer.WriteLine("\tsubgraph cluster{0} {{", i + 1);
                writer.WriteLine("\t\tcolor=gray;");
                if (i == 0)
                {
                    writer.WriteLine("\t\tnode [label=\"\"]");
                    writer.WriteLine("\t\t{0};", string.Join(", ",
                        Enumerable.Range(0, nn.GetNeuronsCount(i))
                        .Select(j => string.Format("n{0}{1}", i + 1, j + 1))
                        ));
                }
                else
                {
                    for (var j = 0; j < nn.GetNeuronsCount(i);  ++j)
                    {
                        writer.WriteLine("\t\tn{0}{1} [label=\"{2:0.00}\"];", i + 1, j + 1, -nn[i, j].Threshold);
                    }
                }
                writer.WriteLine("\t}");
            }

            // subgraph out
            writer.WriteLine("\tsubgraph out {");
            writer.WriteLine("\t\tnode[style=invis, fixedsize=true, width=0, height=0]");
            writer.WriteLine("\t\t{0};", string.Join(", ",
                Enumerable.Range(0, nn.OutputDimention)
                .Select(i => string.Format("o{0}", i + 1))
                ));
            writer.WriteLine("\t}");

            // i? -> n1?
            for (var i = 0; i < nn.InputDimention; ++i)
            {
                writer.WriteLine("\ti{0} -> n1{0} [arrowsize=0.6];", i + 1);
            }

            // n?? -> n??
            for (var i = 0; i < nn.LayersCount - 1; ++i)
            {
                for (var j = 0; j < nn.GetNeuronsCount(i); ++j)
                {
                    for (var k = 0; k < nn.GetNeuronsCount(i + 1); ++k)
                    {
                        if (k == 0)
                        {
                            writer.WriteLine("\tn{0}{1} -> n{2}{3} [taillabel=\"{4:0.00}\", headlabel=\"{5:0.00}\", arrowsize=0.6];",
                                i + 1, j + 1, i + 2, k + 1, nn[i, j].Output, nn[i + 1, k].Weights[j]);
                        }
                        else
                        {
                            writer.WriteLine("\tn{0}{1} -> n{2}{3} [headlabel=\"{4:0.00}\", arrowsize=0.6];",
                                i + 1, j + 1, i + 2, k + 1, nn[i + 1, k].Weights[j]);
                        }
                    }
                }
            }

            // n?? -> o?
            for (var i = 0; i < nn.OutputDimention; ++i)
            {
                writer.WriteLine("\tn{0}{1} -> o{1} [taillabel=\"{2:0.00}\", arrowsize=0.6];",
                    nn.LayersCount, i + 1, nn[nn.LayersCount - 1, i].Output);
            }

            writer.WriteLine("}");
        }