/// <summary>
        /// Runs the search algorithm.
        /// Call method Search, which search for solutions.
        /// </summary>
        /// <param name="bestChoiceSearcher">The best choice searcher.</param>
        /// <param name="propagationResult">The propagation result.</param>
        /// <returns>The solutions.</returns>
        public List <Solution> runSearchAlgorithm(IBestChoiceSearcher bestChoiceSearcher, PropagationResult propagationResult)
        {
            List <Solution> solutions = new List <Solution>();

            search(bestChoiceSearcher, propagationResult, solutions);

            return(solutions);
        }
        // old search method

        /*
         *      private void search2(IBestChoiceSearcher bestChoiceSearcher, PropagationResult result, List<Solution> solutions)
         *      {
         *              Set[,] s = result.matrix;
         *
         *  // Find the top list of possible choices of Set with maximum minFactor range.
         *              List<FactorRangeRecord> bestRecords = searchForTheBestRecords(s);
         *  // If the it is only one possible Set, after shorten will be matrix singleton
         *              bool isSingleton = bestRecords.Count == 1;
         *
         *  // Find the set to be shortened.
         *              FactorRangeRecord best = bestChoiceSearcher.chooseBestRecord(bestRecords);
         *              Set currentSet = s[best.Row, best.Col];
         *
         *              // Create the order in which we will try to find a solution, best possibility first.
         *              List<int> sortedMinutes = new List<int>(currentSet.MinimizationFactor.Keys);
         *              sortedMinutes.Sort(delegate(int i, int j)
         *              {
         *                      return currentSet.MinimizationFactor[i] - currentSet.MinimizationFactor[j];
         *              });
         *
         *              // Search for the solution.
         *              foreach (int minute in sortedMinutes)
         *              {
         *                      // TODO: Use the branch and bound prunning.
         *
         *                      // Copy the matrix.
         *                      Set[,] newMatrix = GenerationAlgorithmPESPUtil.cloneDiscreteSetMatrix(s);
         *
         *                      // Create a singleton set.
         *                      Set newSet = new Set(currentSet.Modulo);
         *                      newSet.Add(minute, currentSet.MinimizationFactor[minute]);
         *
         *                      // Remeber to the new matrix.
         *                      newMatrix[best.Row, best.Col] = newSet;
         *                      newMatrix[best.Col, best.Row] = new Set(newSet);
         *                      newMatrix[best.Col, best.Row].Reverse();
         *
         *                      // Propagate newly created constraints.
         *                      PropagationUtils.propagate(newMatrix, result.TrainLinesMap);
         *
         *                      // Check if the solution may be found.
         *                      if (!MatrixUtils.isValid(s))
         *                      {
         *                              continue;
         *                      }
         *
         *                      // If the solution is found, remember it, otherwise search for it.
         *                      if (isSingleton)
         *                      {
         *                              solutions.Add(new Solution(newMatrix));
         *                      }
         *                      else
         *                      {
         *                              search(new PropagationResult(newMatrix, result.TrainLinesMap), solutions);
         *                      }
         *              }
         *      }
         */

        /// <summary>
        /// Searches for solution.
        /// It is called recursively, backtracking all possiblities with respect to specific choice searcher.
        /// </summary>
        /// <param name="bestChoiceSearcher">The best choice searcher.</param>
        /// <param name="propagationResult">The propagation result.</param>
        /// <param name="solutions">The solutions.</param>
        /// <returns>True if solution found, terminate recursive calls. Otherwise continue in backtracking.</returns>
        private Boolean search(IBestChoiceSearcher bestChoiceSearcher, PropagationResult propagationResult, List <Solution> solutions)
        {
            //reportProgress();

            // retreive discrete set matrix after propagation from propagation result
            Set[,] discreteSetMatrix = propagationResult.DiscreteSetMatrix;

            // while until you can still find some solution (still can found best record)
            while (true)
            {
                // Propagate newly created constraints.
                PropagationUtil.propagate(discreteSetMatrix, propagationResult.TrainLinesMap);

                // Check if the solution may be found.
                if (!MatrixUtils.isValid(discreteSetMatrix))
                {
                    // No valid matrix - solution can not be found.
                    return(false);
                }

                // Find the set to be shortened.
                FactorRangeRecord bestRecord;

                // if no best record found ()
                if (!bestChoiceSearcher.chooseBestRecord(discreteSetMatrix, out bestRecord))
                {
                    // then solution found, matrix is single (contains singletons only).
                    solutions.Add(new Solution(discreteSetMatrix));

                    // End of recursive calls
                    return(true);
                }

                reportProgress();

                // fix one potential set with item founded as best
                Set[,] newMatrix = fixOnePotentialOfSetInMatrix(discreteSetMatrix, bestRecord);

                // matrix was changed, continue in recursive calls
                Boolean solutionFound = search(bestChoiceSearcher, new PropagationResult(newMatrix, propagationResult.TrainLinesMap), solutions);

                // Test if solution was found
                if (solutionFound)
                {
                    return(true);
                }

                // after return from recursive call, remove fixed object and try to
                discreteSetMatrix[bestRecord.Row, bestRecord.Col].Remove(bestRecord.MinItemOfSet);
                discreteSetMatrix[bestRecord.Col, bestRecord.Row].RemoveReverse(bestRecord.MinItemOfSet);
            }
        }
        /// <summary>
        /// Runs the specialized generation algorithm.
        /// Propagetes constraints, searches for solutions and constructs timetables.
        /// </summary>
        /// <param name="constraints">The constraints.</param>
        /// <param name="constraintPropagator">The constraint propagator.</param>
        /// <param name="bestChoiceSearcher">The best choice searcher.</param>
        /// <returns>The timetables.</returns>
        public void runSpecializedGenerationAlgorithm(List <Constraint> constraints, IConstraintPropagator constraintPropagator,
                                                      IBestChoiceSearcher bestChoiceSearcher, List <Timetable> timetables)
        {
            // start time
            Stopwatch watch = new Stopwatch();

            watch.Start();

            // Propagate constraints with specific constraintPropagator
            PropagationResult propagationResult = constraintPropagator.runPropagationAlgorithm(constraints, GenerationAlgorithmDSAUtil.MODULO_DEFAULT);
            // Search for the solution with specific bestChoiceSearcher
            List <Solution> solutions = runSearchAlgorithm(bestChoiceSearcher, propagationResult);

            // finish time
            watch.Stop();
            TimeSpan runningTime = watch.Elapsed;

            // crete note for generated solutions
            String note = constraintPropagator.getDescription() + ", " + bestChoiceSearcher.getDescription();

            // Construct timetables from solutions generated above.
            runConstructionTimetableAlgorithm(solutions, propagationResult.TrainLinesMap, timetables, stepCount, note, runningTime);
        }
        /// <summary>
        /// Generates the timetables.
        /// </summary>
        public void generateTimetables(int numberOftimetables)
        {
            // initialize the algorithm
            List <Constraint> constraints;

            runInitializeAlgorithm(out constraints);

            // propagator with set creator will be choosen in this sequence
            IConstraintPropagator[] propagators = new IConstraintPropagator[]
            {
                new BisectionPropagator(new SameTransferTime()),
                new BisectionPropagator(new AlfaTTransferTime()),
                new SimplePropagator(new FullDiscreteSet()),
                new SimplePropagator(new FullDiscreteSet()),
            };

            // best searcher will be choosen in this sequence
            IBestChoiceSearcher[] creators = new IBestChoiceSearcher[]
            {
                new DeterministicSearcher(),
                new DeterministicSearcher(),
                new DeterministicSearcher(),
                new ProbableSearcher()
            };

            // new timetables
            this.timetables.Clear();
            List <Timetable> newTimetables = this.timetables;

            // shift for percentage complete
            double shift = 1 / (double)creators.Length;

            //
            percentageComplete = 0;

            Exception lastException = null;

            // each predefined combination do
            for (int i = 0, c = creators.Length; i < c; ++i)
            {
                try
                {
                    // step count
                    stepCount = 0;
                    // generation for this combination
                    runSpecializedGenerationAlgorithm(
                        constraints,
                        propagators[i],
                        creators[i],
                        newTimetables
                        );
                    // percentage is completed so far
                    percentageComplete += shift;
                    // if cancellation
                    if (IsCancelled)
                    {
                        break;
                    }
                } catch (Exception exception) {
                    lastException = exception;
                }
            }

            if (lastException != null)
            {
                throw lastException;
            }
        }