// Copy constructor
        public Schedule(Schedule c, bool setupOnly)
        {
            if (setupOnly)
            {
                // reserve space for time-space slots in chromosomes code
                _slots = new List<CourseClass>[(DAYS_NUM * DAY_HOURS * Configuration.GetInstance.GetNumberOfRooms())];
                for (int ptr = 0; ptr < (DAYS_NUM * DAY_HOURS * Configuration.GetInstance.GetNumberOfRooms()); ptr++)
                    _slots[ptr] = new List<CourseClass>();

                // reserve space for flags of class requirements
                _criteria = new bool[(Configuration.GetInstance.GetNumberOfCourseClasses() * numberOfScores)];
            }
            else
            {
                // copy code
                _slots = c._slots;
                _classes = c._classes;

                // copy flags of class requirements
                _criteria = c._criteria;

                // copy fitness
                _fitness = c._fitness;
            }

            // copy parameters
            _numberOfCrossoverPoints = c._numberOfCrossoverPoints;
            _mutationSize = c._mutationSize;
            _crossoverProbability = c._crossoverProbability;
            _mutationProbability = c._mutationProbability;
        }
 public CreateDataGridViews(Dictionary<int, Room> rooms, Form rFrm)
 {
     _schedule = null;
     _running = false;
     _resultWindow = rFrm;
     roomList = rooms;
     LastDGV_Location = new Point(12, 25);
     LastLabel_Location = new Point(12, 7);
     Create_FristTime();
     //
     // add DataGridView
     //
     foreach (KeyValuePair<int, DataGridView> kvp in DgvList)
     {
         _resultWindow.Controls["panelRoomDGV"].Controls.Add(kvp.Value);
     }
     //
     // add Label
     //
     foreach (KeyValuePair<int, Label> kvp in LblRoom)
     {
         _resultWindow.Controls["panelRoomDGV"].Controls.Add(kvp.Value);
     }
 }
        // Initializes genetic algorithm
        public Algorithm(int numberOfChromosomes, int replaceByGeneration, int trackBest,
            Schedule prototype, Schedule.ScheduleObserver observer)
        {
            NumberOfChromosomes = numberOfChromosomes;
            TrackBest = trackBest;
            ReplaceByGeneration = replaceByGeneration;
            _currentBestSize = 0;
            _prototype = prototype;
            _observer = observer;
            _currentGeneration = 0;
            _state =  AlgorithmState.AS_USER_STOPPED;

            // reserve space for population
            _chromosomes = new Schedule[NumberOfChromosomes];
            _bestFlags = new bool[NumberOfChromosomes];

            // reserve space for best chromosome group
            _bestChromosomes = new int[TrackBest];

            // clear population
            for (int i = _chromosomes.Length - 1; i >= 0; --i)
            {
                _chromosomes[i] = null;
                _bestFlags[i] = false;
            }
            _instance = this;

            #region Find number of Active CPU or CPU core's for this Programs
            long Affinity_Dec = System.Diagnostics.Process.GetCurrentProcess().ProcessorAffinity.ToInt64();
            string Affinity_Bin = Convert.ToString(Affinity_Dec, 2); // toBase 2
            foreach (char anyOne in Affinity_Bin.ToCharArray())
                if (anyOne == '1') numCore++;
            #endregion
            }
        // new Thread for Start GA
        private void GA_Start(object Parallel_Mutex_On)
        {
            if ((Boolean)Parallel_Mutex_On) // Parallel Process Requirement's
            {
                #region GA for Mutex On

                while (true) //------------------------------------------------------------------------
                {
                    // user has stopped execution?
                    if (_state == AlgorithmState.AS_CRITERIA_STOPPED || _state == AlgorithmState.AS_USER_STOPPED)
                    {
                        break;
                    }
                    else if (_state == AlgorithmState.AS_SUSPENDED)
                    {
                        if (Thread.CurrentThread.IsAlive)
                            Thread.CurrentThread.Suspend();
                    }

                    // Save a Elite Chromosome for protection in Mutation and etc.
                    Schedule best = GetBestChromosome();

                    // algorithm has reached criteria?
                    if (best.GetFitness() >= 1)
                    {
                         _state = AlgorithmState.AS_CRITERIA_STOPPED;
                        break;
                    }

                    // produce offspring
                    Schedule[] offspring;
                    offspring = new Schedule[_replaceByGeneration];
                    Random rand = new Random();
                    for (int j = 0; j < _replaceByGeneration; j++)
                    {
                        Schedule p1;
                        Schedule p2;
                        // selects parent randomly
                        lock (Locker1)
                        {
                            p1 = _chromosomes[(rand.Next() % _chromosomes.Length)].MakeCopy(false);
                        }
                        lock (Locker1)
                        {
                            p2 = _chromosomes[(rand.Next() % _chromosomes.Length)].MakeCopy(false);
                        }

                        offspring[j] = p1.Crossover(p2);
                        lock (Locker1)
                        {
                            offspring[j].Mutation();
                            offspring[j].CalculateFitness();
                        }
                    }

                    // replace chromosomes of current operation with offspring
                    for (int j = 0; j < _replaceByGeneration; j++)
                    {
                        int ci;
                        do
                        {
                            // select chromosome for replacement randomly
                            ci = rand.Next() % _chromosomes.Length;

                            // protect best chromosomes from replacement
                        } while (IsInBest(ci));

                        lock (Locker1)
                        {
                            // replace chromosomes
                            _chromosomes[ci] = null;
                            _chromosomes[ci] = offspring[j];
                        }
                        // try to add new chromosomes in best chromosome group
                        AddToBest_Parallel(ci);
                    }

                    // algorithm has found new best chromosome
                    if (best != GetBestChromosome())
                    // notify observer
                    {
                        lock (Locker1)
                        {
                            _observer.NewBestChromosome(GetBestChromosome(), ResultControls.ResultForm._setting.Display_RealTime);
                        }
                    }
                    _currentGeneration++;
                }

                // The GA job's is Complete!
                if (_observer != null)
                {
                    lock (Locker0)
                    {
                        // notify observer that execution of algorithm has changed it state
                        _observer.EvolutionStateChanged(_state);
                    }
                }
                Thread.CurrentThread.Abort();
                #endregion
            }
            else
            {
                #region GA for Mutex Off

                while (true) //------------------------------------------------------------------------
                {
                    // user has stopped execution?
                    if (_state == AlgorithmState.AS_CRITERIA_STOPPED || _state == AlgorithmState.AS_USER_STOPPED)
                    {
                        break;
                    }
                    else if (_state == AlgorithmState.AS_SUSPENDED)
                    {
                        if (Thread.CurrentThread.IsAlive)
                            Thread.CurrentThread.Suspend();
                    }

                    // Save a Elite Chromosome for protection in Mutation and etc.
                    Schedule best = GetBestChromosome();

                    // algorithm has reached criteria?
                    if (best.GetFitness() >= 1)
                    {
                        _state = AlgorithmState.AS_CRITERIA_STOPPED;
                        break;
                    }

                    // produce offspring
                    Schedule[] offspring;
                    offspring = new Schedule[_replaceByGeneration];
                    Random rand = new Random();
                    for (int j = 0; j < _replaceByGeneration; j++)
                    {
                        // selects parent randomly
                        Schedule p1 = _chromosomes[(rand.Next() % _chromosomes.Length)];
                        Schedule p2 = _chromosomes[(rand.Next() % _chromosomes.Length)];

                        offspring[j] = p1.Crossover(p2);
                        offspring[j].Mutation();
                        offspring[j].CalculateFitness();
                    }

                    // replace chromosomes of current operation with offspring
                    for (int j = 0; j < _replaceByGeneration; j++)
                    {
                        int ci;
                        do
                        {
                            // select chromosome for replacement randomly
                            ci = rand.Next() % _chromosomes.Length;

                            // protect best chromosomes from replacement
                        } while (IsInBest(ci));

                        // replace chromosomes
                        _chromosomes[ci] = null;
                        _chromosomes[ci] = offspring[j];

                        // try to add new chromosomes in best chromosome group
                        AddToBest_Sequence(ci);
                    }

                    // algorithm has found new best chromosome
                    if (best != GetBestChromosome())
                    // notify observer
                    {
                        _observer.NewBestChromosome(GetBestChromosome(), ResultControls.ResultForm._setting.Display_RealTime);
                    }
                    _currentGeneration++;
                }

                // The GA job's is Complete!
                if (_observer != null)
                {
                    // notify observer that execution of algorithm has changed it state
                    _observer.EvolutionStateChanged(_state);
                }

                Thread.CurrentThread.Abort();
                #endregion
            }
        }
        // Returns reference to global instance of algorithm
        public static Algorithm GetInstance()
        {
            // global instance doesn't exist?
            if (_instance == null)
            {
                // make prototype of chromosomes
                Schedule prototype = new Schedule(5, 5, 90, 10);

                // make new global instance of algorithm using chromosome prototype
                _instance = new Algorithm(1000, 180, 50, prototype, new Schedule.ScheduleObserver());
            }

            return _instance;
        }
        private void Save(Schedule schedule)
        {
            int numberOfRooms = Configuration.GetInstance.GetNumberOfRooms();
            int daySize = schedule.day_Hours * numberOfRooms;
            var db = new LINQDataContext();
            db.Classroom_TimeDeleteAll();
            foreach (KeyValuePair<CourseClass, int> it in schedule.GetClasses().ToList())
            {
                // coordinate of time-space slot
                int pos = it.Value; // int pos of _slot array
                int day = pos / daySize;
                int time = pos % daySize; // this is not time now!
                int room = time / schedule.day_Hours;
                time = time % schedule.day_Hours;  // this is a time now!
                int dur = it.Key.GetDuration;

                CourseClass cc = it.Key;
                Algorithm.Room r = Configuration.GetInstance.GetRoomById(room);
                //
                // Save Classroom_Time
                //

                db.Classroom_TimeSave(r.Origin_ID_inDB, cc.Class_ID, cc.GetProfessor.GetId, time, dur, day);
                //
                // Save New_GroupsPerClassroom
                //
                foreach (var gs in cc.GetGroups)
                {
                    db.New_GroupsPerClassSave(r.Origin_ID_inDB, cc.Class_ID, time, day, gs.GetId);
                }
            }
        }
        private void ResultForm_Load(object sender, EventArgs e)
        {
            Configuration.GetInstance.ParseFile(new LINQDataContext());
            btnPause.Enabled = false;
            btnStop.Enabled = false;

            if (Configuration.GetInstance.GetNumberOfRooms() > 0)
            {
                create_GridView = new CreateDataGridViews(Configuration.GetInstance.Rooms, this);
                Schedule prototype = new Schedule(5, 5, 90, 10);
                Schedule.ScheduleObserver sso = new Schedule.ScheduleObserver();
                sso.SetWindow(create_GridView);

                AA = new MakeClassSchedule.Algorithm.Algorithm(1000, 180, 50, prototype, sso);

                state = ThreadState.Unstarted;
                timerWorkingSet.Start();
            }
            else
            {
                MessageBox.Show("Number of rooms is less than the limit!", "Number of Rooms Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                timerWorkingSet.Stop();
                AA = null;
                Dispose();
                return;
            }

            if (Configuration.GetInstance.GetNumberOfCourseClasses() <= 0)
            {
                btnStart.Enabled = false;
            }
        }
        public void SetSchedule(Schedule schedule, bool showGraphical)
        {
            _schedule = schedule.MakeCopy(false);
            if (Monitor.TryEnter(Locker, 500))
            {
                //_resultWindow.Controls["lblFitness"].Text = schedule.GetFitness().ToString();
                SetText("Fitness: " + schedule.GetFitness().ToString());
                Monitor.Exit(Locker);
            }
            else return;
            if (showGraphical)
            {
                //
                // ReSet to New DataGridView
                //
                foreach (KeyValuePair<int, DataGridView> it in dgvList)
                {
                    ClearDataGridView(it.Value);
                }
                //
                int numberOfRooms = Configuration.GetInstance.GetNumberOfRooms();
                int daySize = schedule.day_Hours * numberOfRooms;
                Random rand = new Random();
                foreach (KeyValuePair<CourseClass, int> it in schedule.GetClasses().ToList())
                {
                    // coordinate of time-space slot
                    int pos = it.Value; // int pos of _slot array
                    int day = pos / daySize;
                    int time = pos % daySize; // this is not time now!
                    int room = time / schedule.day_Hours;
                    time = time % schedule.day_Hours;  // this is a time now!

                    int dur = it.Key.GetDuration;

                    CourseClass cc = it.Key;
                    Room r = Configuration.GetInstance.GetRoomById(room);
                    string groups_Name = "";
                    foreach (var gs in cc.GetGroups)
                    {
                        groups_Name += gs.GetName + "\r\n";
                    }
                    groups_Name = groups_Name.Trim();

                    ((DataGridViewTextBoxCellEx)dgvList[r.GetId][day + 1, time]).RowSpan = cc.GetDuration;
                    dgvList[r.GetId][day + 1, time].Style.BackColor =
                                Color.FromArgb(rand.Next(70, 250), rand.Next(70, 250), rand.Next(70, 250));

                    dgvList[r.GetId][day + 1, time].Value = string.Format(CultureInfo.CurrentCulture,
                        "{0}\r\n{1}\r\n{2}\r\n{3}", cc.GetCourse.GetName, cc.GetProfessor.GetName, groups_Name, cc.Lab);

                        //(cc.GetCourse.GetName + Environment.NewLine +
                        // cc.GetProfessor.GetName + Environment.NewLine +
                        // groups_Name + Environment.NewLine + cc.Lab);
                }
            }
        }
 // Handles event that is raised when algorithm finds new best chromosome
 public void NewBestChromosome(Schedule newChromosome, bool showGraphical)
 {
     if (_window.DgvList.Count > 0)
         _window.SetSchedule(newChromosome, showGraphical);
 }
        // Makes new chromosome with same setup but with randomly chosen code
        public Schedule MakeNewFromPrototype()
        {
            // number of time-space slots
            int size = _slots.Length;

            // make new chromosome, copy chromosome setup
            Schedule newChromosome = new Schedule(this, true);

            // place classes at random position
            List<CourseClass> cc = Configuration.GetInstance.GetCourseClasses();
            foreach (CourseClass it in cc)
            {
                // determine random position of class
                int num_rooms = Configuration.GetInstance.GetNumberOfRooms();
                int dur = it.GetDuration;
                Random rand = new Random();
                int day = rand.Next() % DAYS_NUM;
                int room = rand.Next() % num_rooms;
                int time = rand.Next() % (DAY_HOURS + 1 - dur);
                int pos = (day * num_rooms * DAY_HOURS) + (room * DAY_HOURS + time); // (Base) + (offset) time's

                // fill time-space slots, for each hour of class
                for (int i = dur - 1; i >= 0; i--)
                    newChromosome._slots[pos + i].Add(it);

                // insert in class table of chromosome
                newChromosome._classes.Add(it, pos);
            }

            newChromosome.CalculateFitness();

            // return smart pointer
            return newChromosome;
        }
        // Performed crossover operation using to chromosomes
        // and returns pointer to offspring
        public Schedule Crossover(Schedule parent2)
        {
            Random rand = new Random();

            // check probability of crossover operation
            if (rand.Next() % 100 > _crossoverProbability)
                // no crossover, just copy first parent
                return new Schedule(this, false);

            // new chromosome object, copy chromosome setup
            Schedule n = new Schedule(this, true);

            // number of classes
            int size = _classes.Count;

            bool[] cp = new bool[size];

            // determine crossover point (randomly)
            for (int i = _numberOfCrossoverPoints; i > 0; i--)
            {
                while (true)
                {
                    int p = rand.Next() % size;
                    if (!cp[p])
                    {
                        cp[p] = true;
                        break;
                    }
                }
            }

            //Dictionary<CourseClass, int> it1 = _classes;
            List<KeyValuePair<CourseClass, int>> it1 = _classes.ToList<KeyValuePair<CourseClass, int>>();

            //Dictionary<CourseClass, int> it2 = parent2._classes;
            List<KeyValuePair<CourseClass, int>> it2 = parent2._classes.ToList<KeyValuePair<CourseClass, int>>();

            // make new code by combining parent codes
            bool first = (rand.Next() % 2 == 0);
            //
            for (int i = 0; i < size; i++)
            {
                if (first)
                {
                    // insert class from first parent into new chromosome's class table
                    n._classes.Add(it1[i].Key, it1[i].Value);
                    // all time-space slots of class are copied
                    for (int j = it1[i].Key.GetDuration - 1; j >= 0; j--)
                        n._slots[it1[i].Value + j].Add(it1[i].Key);
                }
                else
                {
                    // insert class from second parent into new chromosome's class table
                    n._classes.Add(it2[i].Key, it2[i].Value);
                    // all time-space slots of class are copied
                    for (int j = it2[i].Key.GetDuration - 1; j >= 0; j--)
                        n._slots[it2[i].Value + j].Add(it2[i].Key);
                }

                // crossover point
                if (cp[i])
                    // change source chromosome
                    first = !first;
            }

            n.CalculateFitness();

            // return smart pointer to offspring
            return n;
        }