/// <summary>
        /// Loads job-shop scheduling problem input from file specified by <see cref="path"/> into <see cref="JobShop"/>.
        /// </summary>
        /// <param name="path">File path.</param>
        /// <returns></returns>
        public JobShop Load(string path, bool validate = true)
        {
            using (var reader = new StreamReader(path))
            {
                int[] jobsAndMachinesCount = reader.ReadLine().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
                int   jobsCount            = jobsAndMachinesCount[0];
                var   jobs        = new List <Job>();
                int   operationId = 0;
                for (int jobId = 0; jobId < jobsCount; jobId++)
                {
                    var      operations = new List <Operation>();
                    string[] lineArgs   = reader.ReadLine().Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                    for (int order = 0; order < lineArgs.Length / 2; order++)
                    {
                        int    machineId = int.Parse(lineArgs[order * 2]);
                        double cost      = double.Parse(lineArgs[order * 2 + 1]);
                        cost = Math.Abs(cost) < double.Epsilon ? cost + 10e-6 : cost;
                        operations.Add(new Operation(operationId, jobId, machineId, order, cost));
                        operationId++;
                    }

                    jobs.Add(new Job(operations));
                }

                var jobShop = new JobShop(jobs, validate);

                return(jobShop);
            }
        }
        /// <summary>
        /// Creates new instance of <see cref="JobShop"/>.
        /// </summary>
        /// <param name="jobOperationCounts">Array where index i contains number of operations that i-th job has.</param>
        /// <param name="machinesCount">Total number of machines.</param>
        /// <returns>Returns new instance of <see cref="JobShop"/>.</returns>
        public JobShop Generate(int[] jobOperationCounts, int machinesCount)
        {
            var jobs = new List <Job>();
            int maximumOperationCost = 50;

            int lastFreeOperationId = 0;

            for (int jobId = 0; jobId < jobOperationCounts.Length; jobId++)
            {
                int operationCount = jobOperationCounts[jobId];
                var operations     = new List <Operation>();
                for (int operationOrder = 0; operationOrder < operationCount; operationOrder++)
                {
                    int    machineId     = random.Next(0, machinesCount);
                    double operationCost = random.NextDouble() * maximumOperationCost;

                    var operation = new Operation(lastFreeOperationId, jobId, machineId, operationOrder, operationCost);
                    operations.Add(operation);

                    lastFreeOperationId++;
                }

                var job = new Job(operations);
                jobs.Add(job);
            }

            var jobShop = new JobShop(jobs);

            return(jobShop);
        }