private static void CreateLayerInGraph(ComponentGraph graph, ComponentVertex vertex, RandomNumberGenerator <float> random)
        {
            if (graph.InDegree(vertex) == 0)
            {
                // use some arbitrary layout to start
                // source layer must be input layer that overrides it
                vertex.Layer = Layer.CreateFromArchitecture(new Shape(Shape.BWHC, -1, 100, 100, 100), vertex.Architecture, random);
            }
            else
            {
                IList <Shape> shapes = new List <Shape>();
                foreach (Edge <ComponentVertex> edge in graph.InEdges(vertex))
                {
                    if (edge.Source.Layer == null)
                    {
                        NetworkGraphBuilder.CreateLayerInGraph(graph, edge.Source, random);
                    }

                    shapes.Add(edge.Source.Layer.OutputShape);
                }

                vertex.Layer = shapes.Count == 1 ?
                               Layer.CreateFromArchitecture(shapes[0], vertex.Architecture, random) :
                               Layer.CreateFromArchitecture(shapes, vertex.Architecture, random);
            }
        }
        public static NetworkGraph CreateNetworkGraph(string architecture, bool addActivationLayers, bool addLossLayer)
        {
            if (architecture == null)
            {
                throw new ArgumentNullException(nameof(architecture));
            }

            if (string.IsNullOrEmpty(architecture))
            {
                throw new ArgumentException(Properties.Resources.E_InvalidNetArchitecture_NoLayers, nameof(architecture));
            }

            // 1. parse architecture string and build preliminary graph
            ComponentGraph componentGraph = NetworkGraphBuilder.ParseArchitecture(architecture, false);

            // 2. create layers in the preliminary graph
            RandomNumberGenerator <float> random = null; //// new Random(0);

            foreach (ComponentVertex sink in componentGraph.Sinks)
            {
                NetworkGraphBuilder.CreateLayerInGraph(componentGraph, sink, random);
            }

            // 3. convert to network graph
            NetworkGraph graph = new NetworkGraph();

            foreach (Edge <ComponentVertex> edge in componentGraph.Edges)
            {
                /*NetworkGraph sourceGraph = (edge.Source.Layer as RNNLayer)?.Graph;
                 * NetworkGraph targetGraph = (edge.Target.Layer as RNNLayer)?.Graph;
                 *
                 * if (sourceGraph != null)
                 * {
                 *  graph.AddGraph(sourceGraph);
                 *  if (targetGraph != null)
                 *  {
                 *      graph.AddEdges(sourceGraph.Sinks, targetGraph.Sources);
                 *      graph.AddGraph(targetGraph);
                 *  }
                 *  else
                 *  {
                 *      graph.AddEdges(sourceGraph.Sinks, edge.Target.Layer);
                 *  }
                 * }
                 * else if (targetGraph != null)
                 * {
                 *  graph.AddEdges(edge.Source.Layer, targetGraph.Sources);
                 *  graph.AddGraph(targetGraph);
                 * }
                 * else*/
                {
                    graph.AddEdge(edge.Source.Layer, edge.Target.Layer);
                }
            }

            // 4. add missing loss layers
            if (addLossLayer)
            {
                NetworkGraphBuilder.AddLossLayers(graph);
            }

            // 5. add missing activation layers
            if (addActivationLayers)
            {
                NetworkGraphBuilder.AddActivationLayers(graph);
            }

            // 6. initialize stochastic biases with ReLU activations
            NetworkGraphBuilder.InitializeReLUs(graph);

            return(graph);
        }