private void GenerateFirstSetOfEdgesForDivergingMaterialFlow(ProductStructureInput inputParameters,
                                                                     ProductStructure productStructure, XRandom rng, List <HashSet <long> > availableNodes)
        {
            for (var i = inputParameters.DepthOfAssembly; i >= 2; i--)
            {
                for (long j = 1; j <= productStructure.NodesPerLevel[i - 1].LongCount() /*&& availableNodes[i - 2].LongCount() > 0*/; j++)
                {
                    var endNodePos = rng.NextLong(availableNodes[i - 2].LongCount());
                    var endNode    = availableNodes[i - 2].ToArray()[endNodePos];
                    var edge       = new Edge
                    {
                        Start = productStructure.NodesPerLevel[i - 1][j - 1],
                        End   = productStructure.NodesPerLevel[i - 2][endNode]
                    };
                    edge.End.IncomingEdges.Add(edge);
                    productStructure.Edges.Add(edge);
                    availableNodes[i - 2].Remove(endNode);
                }
            }

            for (var i = 1; i < inputParameters.DepthOfAssembly; i++)
            {
                var pk = GetCumulatedProbabilitiesPk2(i, inputParameters.DepthOfAssembly);
                foreach (var j in availableNodes[i - 1])
                {
                    var u   = rng.NextDouble();
                    var sum = 0.0;
                    var k   = 0;
                    while (k < pk.Count - 1)
                    {
                        sum += pk[k].Value;
                        if (u < sum)
                        {
                            break;
                        }

                        k++;
                    }

                    var assemblyLevelOfStartNode = pk[k].Key;
                    var posOfNode = rng.NextLong(productStructure.NodesPerLevel[assemblyLevelOfStartNode - 1].LongCount());
                    var edge      = new Edge
                    {
                        Start = productStructure.NodesPerLevel[assemblyLevelOfStartNode - 1][posOfNode],
                        End   = productStructure.NodesPerLevel[i - 1][j]
                    };
                    edge.End.IncomingEdges.Add(edge);
                    productStructure.Edges.Add(edge);
                }
            }
        }
        private void GenerateFirstSetOfEdgesForConvergingMaterialFlow(ProductStructureInput inputParameters, XRandom rng,
                                                                      Dictionary <int, List <KeyValuePair <int, double> > > pkPerI, List <HashSet <long> > availableNodes,
                                                                      ProductStructure productStructure)
        {
            for (var i = 1; i <= inputParameters.DepthOfAssembly - 1; i++)
            {
                for (long j = 1; j <= productStructure.NodesPerLevel[i - 1].LongCount() /*&& availableNodes[i].LongCount() > 0*/; j++)
                {
                    var startNodePos = rng.NextLong(availableNodes[i].LongCount());
                    var startNode    = availableNodes[i].ToArray()[startNodePos];
                    var edge         = new Edge
                    {
                        Start = productStructure.NodesPerLevel[i][startNode],
                        End   = productStructure.NodesPerLevel[i - 1][j - 1]
                    };
                    edge.End.IncomingEdges.Add(edge);
                    productStructure.Edges.Add(edge);
                    availableNodes[i].Remove(startNode);
                }
            }

            for (var i = inputParameters.DepthOfAssembly; i >= 2; i--)
            {
                foreach (var j in availableNodes[i - 1])
                {
                    var u   = rng.NextDouble();
                    var sum = 0.0;
                    var k   = 0;
                    while (k < pkPerI[i].Count - 1)
                    {
                        sum += pkPerI[i][k].Value;
                        if (u < sum)
                        {
                            break;
                        }

                        k++;
                    }

                    var assemblyLevelOfEndNode = pkPerI[i][k].Key;
                    var posOfNode = rng.NextLong(productStructure.NodesPerLevel[assemblyLevelOfEndNode - 1].LongCount());
                    var edge      = new Edge
                    {
                        Start = productStructure.NodesPerLevel[i - 1][j],
                        End   = productStructure.NodesPerLevel[assemblyLevelOfEndNode - 1][posOfNode]
                    };
                    edge.End.IncomingEdges.Add(edge);
                    productStructure.Edges.Add(edge);
                }
            }
        }
        private static void GenerateSecondSetOfEdges(ProductStructureInput inputParameters, ProductStructure productStructure,
                                                     XRandom rng, long edgeCount, Dictionary <int, List <KeyValuePair <int, double> > > pkPerI)
        {
            var possibleStartNodes = productStructure.NodesCounter - inputParameters.EndProductCount;

            for (var j = productStructure.Edges.LongCount() + 1; j <= edgeCount; j++)
            {
                var startNodePos             = rng.NextLong(possibleStartNodes) + 1;
                var assemblyLevelOfStartNode = 2;
                while (assemblyLevelOfStartNode < inputParameters.DepthOfAssembly)
                {
                    if (startNodePos <= productStructure.NodesPerLevel[assemblyLevelOfStartNode - 1].LongCount())
                    {
                        break;
                    }

                    startNodePos -= productStructure.NodesPerLevel[assemblyLevelOfStartNode - 1].LongCount();
                    assemblyLevelOfStartNode++;
                }

                var u   = rng.NextDouble();
                var sum = 0.0;
                var k   = 0;
                while (k < pkPerI[assemblyLevelOfStartNode].Count - 1)
                {
                    sum += pkPerI[assemblyLevelOfStartNode][k].Value;
                    if (u < sum)
                    {
                        break;
                    }

                    k++;
                }

                var assemblyLevelOfEndNode = pkPerI[assemblyLevelOfStartNode][k].Key;
                var endNodePos             = rng.NextLong(productStructure.NodesPerLevel[assemblyLevelOfEndNode - 1].LongCount());
                var edge = new Edge
                {
                    Start = productStructure.NodesPerLevel[assemblyLevelOfStartNode - 1][startNodePos - 1],
                    End   = productStructure.NodesPerLevel[assemblyLevelOfEndNode - 1][endNodePos]
                };
                edge.End.IncomingEdges.Add(edge);
                productStructure.Edges.Add(edge);
            }
        }