Question

I have a project which creates a schedule and makes an optimization to it. The project has the Schedule class:

Schedule.h:

#pragma once
#ifndef SCHEDULE_H
#define SCHEDULE_H

#include "Course.h"
#include "Prof.h"
#include "Room.h"
#include "TimeBlock.h"
#include "Weekdays.h"
#include "ScoreCalculator.h"
#include <map>
#include <vector>
/**
 * This class represents a schedule for all courses.
 */
class Schedule {
public:
    Schedule(std::vector < Room >, std::vector < Prof >, std::vector < Course > );
    Schedule(const Schedule& schedule);
    std::map < Room, std::vector < std::vector < Course > > > getSchedule();
    bool setCourse(const Course&, const Room&, Weekdays, TimeBlock, int);
    Course getCourse(const Room&, Weekdays, TimeBlock);
    std::vector < Course > getCoursesAt(Weekdays, TimeBlock);
    std::vector < Weekdays > getWeekdaysFor(const Course&);
    TimeBlock getTimeFor(const Course&);
    Room getRoomFor(const Course&);
    void swapCourses(Room, Weekdays, TimeBlock, Room, Weekdays, TimeBlock);
    void setScore (double score){ _score = score; }
    double getScore() { return _score; }
    Prof getProf(string);
    Prof getProf(Course);
    std::vector<Course> getCoursesTaughtBy(Prof&);
    std::vector<Course> getCoursesOnGivenDayTaughtBy(Prof&, Weekdays);
    std::vector<Room> getRooms();
    std::map<string, Prof> getProfs();
    void setSchedule(std::map < Room, std::vector < std::vector <Course> > >);
private:
    std::map < Room, std::vector < std::vector < Course > > > _schedule;
    std::map < std::string, Prof > _professors;
    std::map < std::string, Course > _courses;
    std::vector<Room> _rooms;
    std::vector<Prof> _profs;
    std::vector<Course> _coursesVector;
    double _score;
};

#endif // SCHEDULE_H

Schedule.cpp:

#include "../include/Schedule.h"
#include "../include/Prof.h"
#include <vector>
#include <set>
#include <string>

using namespace std;

/**
 * Constructor for the schedule. Creates the empty schedule
 */
Schedule::Schedule(vector < Room > rooms, vector < Prof > prof, vector < Course > courses){
    _rooms = rooms;
    _profs = prof;
    _coursesVector = courses;
    for(unsigned int i = 0; i < prof.size(); i++){
            _professors.insert(make_pair(prof.at(i).getId(), prof.at(i)));
    }
    for (unsigned int i = 0; i < courses.size(); i++){
        _courses.insert(make_pair(courses.at(i).getId(), courses.at(i)));
    }
    _score = -1;
    for (unsigned int i = 0; i < _rooms.size(); i++){
        vector < vector < Course > > dayVector;
        dayVector.resize(WEEKDAYS_SIZE);
        for (unsigned int j = 0; j < dayVector.size(); j++){
            dayVector.at(j).resize(TIMEBLOCK_SIZE);
        }
        _schedule.insert(make_pair(_rooms.at(i), dayVector));
    }
}

bool Schedule::setCourse(const Course& course, const Room& room, Weekdays firstMeeting, TimeBlock timeBlock, int numberOfMeetings){
    if (course.getEnrolled() > room.getCapacity()){
        return false;
    }
    _schedule.at(room).at(firstMeeting).at(timeBlock) = course;

    switch (numberOfMeetings){
    case 2:
        _schedule.at(room).at((TimeBlock)(firstMeeting + 2)).at(timeBlock) = course;
        break;
    }
    return true;
}

Course Schedule::getCourse(const Room& room, Weekdays day, TimeBlock timeBlock){
    //returns course
}

vector < Course > Schedule::getCoursesAt(Weekdays day, TimeBlock timeBlock){
    //returns course at the given time
}

TimeBlock Schedule::getTimeFor(const Course& course){
    //returns time for the course
}

Room Schedule::getRoomFor(const Course& course){
    //returns room for the course
}

vector < Weekdays > Schedule::getWeekdaysFor(const Course& course){
    //returns weekdays for the course
}

// returns true if swap was successful, false otherwise
void Schedule::swapCourses(Room room1, Weekdays weekdays1, TimeBlock timeBlock1, Room room2, Weekdays weekdays2, TimeBlock timeBlock2){
    Course c1, c2;
    c1 = getCourse(room1, weekdays1, timeBlock1);
    c2 = getCourse(room2, weekdays2, timeBlock2);
    setCourse(c2, room1, weekdays1, timeBlock1, 2);
    setCourse(c1, room2, weekdays2, timeBlock2, 2);
}

Prof Schedule::getProf(string id){
    return _professors.at(id);
}

Prof Schedule::getProf(Course c){
    return _professors.at(c.getProfId());
}


void Schedule::setSchedule(map < Room, vector < vector < Course > > > schedule){
    _schedule = schedule;
}

map < Room, vector < vector < Course > > > Schedule::getSchedule(){
    return _schedule;
}

vector<Room> Schedule::getRooms(){
    return _rooms;
}

map <string, Prof> Schedule::getProfs(){
    return _professors;
}

vector <Course> Schedule::getCoursesTaughtBy(Prof& prof){
    //returns courses taught by
}

Schedule& Schedule::operator=(const Schedule& rhs){
    _rooms = rhs._rooms;
    _courses = rhs._courses;
    _coursesVector = rhs._coursesVector;
    _professors = rhs._professors;
    _profs = rhs._profs;
    _schedule = rhs._schedule;
    return *this;
}

It has a class which handles the optimization by swapping two random courses and deciding, which schedule is better:

GeneticScheduleGenerator.h:

#pragma once
#ifndef GENETICSCHEDULEGENERATOR_H
#define GENETICSCHEDULEGENERATOR_H

#include "ScheduleGenerator.h"
#include "ScoreCalculator.h"
#include "Schedule.h"
#include <map>
#include <string>
using namespace std;

class GeneticScheduleGenerator : public ScheduleGenerator {
public:
  GeneticScheduleGenerator(ScoreCalculator&, Schedule*, long);
  Schedule* getSchedule(void);
  Schedule* _schedule;
  map < Room, vector < vector < Course > > > getScheduleMap();
private:
    double calculateScore(map < string, Prof >, Schedule*);
  void optimize ();
  std::map<string, ProfInfo> profInfoMap;
  ScoreCalculator& _sc;
  map<string, double> _scores;
  map<Room, vector< vector< Course> > > _scheduleMap;


};

#endif // GENETICSCHEDULEGENERATOR_H

GeneticScheduleGenerator.cpp:

#include "../include/GeneticScheduleGenerator.h"
#include <cstdlib>
#include <time.h>
#include <algorithm>
#include "../include/Weekdays.h"
#include "../include/TimeBlock.h"
#include <iostream>

GeneticScheduleGenerator::GeneticScheduleGenerator(ScoreCalculator& sc, Schedule* schedule, long timeout )
    : ScheduleGenerator(timeout) , _sc(sc) {
        _schedule = schedule;
}

double GeneticScheduleGenerator::calculateScore(map<string, Prof> professors, Schedule* schedule){
    double score = 0;
    //does some calculations
    return score;
}

Schedule* GeneticScheduleGenerator::getSchedule(){
    Schedule* bestSchedule = _schedule;
    Schedule _changedSc = *_schedule;
    Schedule *_changedSchedule = &_changedSc;
    map<string, Prof> professors = bestSchedule->getProfs();

    bestSchedule->setScore(calculateScore(professors, bestSchedule));

    srand(time(NULL));
    vector<Room> rooms = _schedule->getRooms();
    int numberOfRooms = rooms.size();
    Room room1, room2;
    Weekdays day1, day2;
    TimeBlock time1, time2;

    long endTime = time(0) + getTimeout();
    int counter = 0;
    do{
        counter++;
        room1 = rooms.at(rand() % numberOfRooms);
        room2 = rooms.at(rand() % numberOfRooms);
        day1 = (Weekdays)(rand() % WED);
        day2 = (Weekdays)(rand() % WED);
        time1 = (TimeBlock)(rand() % TIMEBLOCK_SIZE);
        time2 = (TimeBlock)(rand() % TIMEBLOCK_SIZE);
        if (_changedSchedule->getCourse(room1, day1, time1).getEnrolled() > room2.getCapacity() ||
            _changedSchedule->getCourse(room2, day2, time2).getEnrolled() > room1.getCapacity() ||
            _changedSchedule->getCourse(room2, day2, time2) == _changedSchedule->getCourse(room1, day1, time1))
        {
            continue;
        }
        else
        {
            bestSchedule = _schedule;


            _changedSchedule->swapCourses(room1, day1, time1, room2, day2, time2);
            double newScore = calculateScore(professors, _changedSchedule);

            if (bestSchedule->getScore() > newScore){
                _schedule = _changedSchedule;
                _schedule->setScore(newScore);
            }
        }

    } while (time(0) < endTime);
    std::cout << "counter: " << counter << endl;
    _scheduleMap = _schedule->getSchedule();
    /*map<string, Prof> tempProf = _schedule->getProfs();
    map<string, Course> tempCorse = _schedule->getCourses();*/

    return _schedule;
}

map < Room, vector < vector < Course > > > GeneticScheduleGenerator::getScheduleMap(){
    return _scheduleMap;
}

The ScheduleGeneratorClass is not yet fully functioning(it does not test for class conflicts, i.e. same professor can't teach 2 classes at the same time), but it swaps classes and calculates the score for the schedule. The problem is, that before the return _schedule; part _schedule contains the valid schedule:

enter image description here

But when the caller gets it, the object holds only the score part. Everything else seems to be erased:

enter image description here

I have been trying to solve that for last couple of days and had no luck. Can anyone help? If you need the other code or more info, just ask. Thank you.

Was it helpful?

Solution

In getSchedule these lines of code:

Schedule _changedSc = *_schedule;
Schedule *_changedSchedule = &_changedSc;

creates a local instance of Schedule on the stack and a pointer to that local instance.

This line of code:

_schedule = _changedSchedule;

means that _schedule now points to that local variable.

When your method returns, the local variable goes out of scope, so your _schedule pointer is now invalid.

The reason the vector sizes change back to zero is probably due to the vector destructor, but there is nothing stopping the program reusing that memory for something else and you would then get a segfault if you tried to use the vectors.

One way to fix it is to have a more permanent place to store the changed Schedule, e.g. in the class itself. Another is to pass in a Schedule object to be filled in. Yet another way is to pass back the Schedule as an object, rather than a pointer.

OTHER TIPS

Use the new operator where you know that object will not be used within the initialised scope. For example:

Schedule *_changedSchedule = &_changedSc;

when _changedSc goes out of scope, it will not be in the stack anymore. You need to be able to store that in the heap by using the new operator.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top