diff --git a/rr.py b/rr.py index 53b44f9..30c2f8d 100644 --- a/rr.py +++ b/rr.py @@ -6,6 +6,8 @@ def __init__(self, process_input_list, cpu_count, quantum): super().__init__(process_input_list, cpu_count) self.quantum = quantum + + def run(self): cur_time = 0 finish_processes_count = 0 diff --git a/show.py b/show.py index e88a82e..f7702f4 100644 --- a/show.py +++ b/show.py @@ -115,9 +115,9 @@ def init_ui(self): # Proc_List에 프로세스 목록을 추가 및 화면 내용을 리셋하는 버튼 self.add_button = QPushButton("Add", self) - self.add_button.clicked.connect(self.add) + # self.add_button.clicked.connect(self.add) # 수정 : 디버깅용 test를 add 버튼에 일시적으로 연결 (test 누르면 자동으로 값 입력됨) - # self.add_button.clicked.connect(self.test) + self.add_button.clicked.connect(self.test) reset_button = QPushButton("Reset", self) reset_button.clicked.connect(self.reset) @@ -256,17 +256,17 @@ def test(self): Process("p9", 1, 4, 9), ] # ---------------------------- - self.proc_list = [ - Subject("알고리즘", 4, 8, 0, 0), - Subject("웹프", 3, 7, 1, 0), - Subject("직능훈", 2, 4, 2, 0), - # Subject("알고리즘", 4, 5, 3, 1), - Subject("C++", 4, 4, 4, 1), - # Subject("웹프", 3, 3, 5, 1), - # Subject("알고리즘", 4, 4, 6, 2), - # Subject("데베설", 3, 5, 7, 2), - # Subject("운영체제", 2, 6, 8, 2), - ] + # self.proc_list = [ + # Subject("알고리즘", 4, 8, 0, 0), + # Subject("웹프", 3, 7, 1, 0), + # Subject("직능훈", 2, 4, 2, 0), + # # Subject("알고리즘", 4, 5, 3, 1), + # Subject("C++", 4, 4, 4, 1), + # # Subject("웹프", 3, 3, 5, 1), + # # Subject("알고리즘", 4, 4, 6, 2), + # # Subject("데베설", 3, 5, 7, 2), + # # Subject("운영체제", 2, 6, 8, 2), + # ] # ------------------------------- print("[self.proc_list]") diff --git a/srtn.py b/srtn.py index 8e52cb3..29fb8a6 100644 --- a/srtn.py +++ b/srtn.py @@ -44,7 +44,6 @@ def run(self): cpu_list = [] for cpu in self.cpus: cpu_list.append(cpu) - cpu_list.sort(key=lambda x: x.process.remain_bt) # 오름차순으로 정렬 (+한번만해도 괜찮을듯) max_idx = min(self.cpu_count, len(self.ready_queue)) # 인덱스 에러 안 뜨게 diff --git a/student.py b/student.py index 1c1f5d0..fae6d48 100644 --- a/student.py +++ b/student.py @@ -9,26 +9,41 @@ class Student(CPU): def __init__(self, student_name): # student_name는 학생 이름, class_list는 학생이 듣는 수업 super().__init__(student_name) self.subject_list = [] - # [DEBUG] 이게 평균학점 0점으로 초기화해서 최대 0점일 때 체크가 잘 안되었음 + # 0~ 24 시간에서 각 시간에따른 -------------------- + # 이 학생의 최고 평균 학점 self.best_solo_avg_grades = [-1 for _ in range(25)] + # 이 학생의 최고의 각 과목별 공부 투자 시간 self.best_solo_subject_study_cases = defaultdict(list) + # 이 학생의 최고의 각 과목별 학점 self.best_solo_subjects_grades = defaultdict(list) + # ------------------------------------------------- + # 최종적으로 제일 좋은 ------------------------------------- self.best_solo_total_study_time = 0 # 개인 공부 투자 시간 - self.best_solo_subject_study_case = [] # 각 과목 공부 투자시간 순서대로 - self.best_solo_subjects_grade = [] # 각 과목 학점 순서대로 + self.best_solo_subject_study_case = [] # 각 과목 공부별 투자시간 순서대로 + self.best_solo_subjects_grade = [] # 각 과목별 학점 순서대로 self.best_each_team_play_time = 0 # 개인의 팀플 투자시간 self.best_team_play_grade = 0 # 팀플 학점 self.best_avg_grade = 0 # 최종적인 개인 학점(개인 공부 학점과 팀플 학점의 평균) - + # ------------------------------------------------------------ self.total_credits = 3 # 총 학점 21 학점같은 - 기본 운영체제 팀플 3학점을 듣기 때문에 def add_subject_list(self, subject): + """ + 학생에게 과목을 추가하면서, 총학점도 같이 구함 + """ self.subject_list.append(subject) self.total_credits += subject.credit # max_solo_study_time 이걸로 best 시간 구하고 이걸로 구해도 똑같은 값이 나올거 같은데? def calculate_best_case(self, best_team_play_case, max_team_play_time): + """ + 최종적으로 구한 best_team_play_case와 처음에 설정해준 목표 팀플 실행 시간을 통해서 + 학생의 최종적인 각 과목의 실제 공부 시간, 총 공부 시간,각 과목들의 학점, + 이 학생이 투자한 팀플 시간, 이 팀의 팀플 학점 + 이 학생의 최종 평균 학점을 + 계산하여 설정한다. + """ best_each_team_play_time = best_team_play_case[0][self.id] total_team_play_time = sum(best_team_play_case[0]) max_solo_study_time = 24 - best_each_team_play_time @@ -47,26 +62,52 @@ def calculate_best_case(self, best_team_play_case, max_team_play_time): print("self.best_avg_grade", self.best_avg_grade) def get_team_play_grade(self, total_team_play_time, max_team_play_time): + """ + 팀플 학점을 구한다(팀 전체가 투자한 총 팀플시간과 목표 팀플시간을 통해서) + """ team_play_score = 100 * (total_team_play_time / max_team_play_time) team_play_grade = self.convert_score_to_grade(team_play_score) return team_play_grade def get_final_student_grade(self, each_solo_study_time, total_team_play_time, max_team_play_time): + """ + 개인 공부시간에 따른 학점, 팀플에서 받은 학점의 평균을 통해 개인 최종 평균 학점을 구한다. + 개인 공부 학점 - 개인 공부시간(each_solo_study_time)에 따라서 구함 + 팀플 학점 - 팀 전체가 투자한 팀플레이 시간, 목표 팀플레이시간을 통해 구함 + """ team_play_grade = self.get_team_play_grade(total_team_play_time, max_team_play_time) * 3 # 운영체제는 3학점임 solo_study_grade = self.best_solo_avg_grades[each_solo_study_time] * (self.total_credits - 3) return (team_play_grade + solo_study_grade) / self.total_credits def set_best_solo_cases(self): + """ + 공부시간에 따른 + 이 학생의 최고 평균 학점 + 이 학생의 최고의 각 과목별 공부 투자 시간 + 이 학생의 최고의 각 과목별 학점 + 을 구하는 함수이다. + """ all_study_cases = self.get_all_study_cases() - if len(all_study_cases) > 1: + if len(all_study_cases) > 1: # 과목을 아무것도 할당받지 못하면 all_study_cases = for study_time in range(25): # 모든 과목 공부시간(BT)을 다 합쳐도 시간이 남아서 현재 study_time에 대한 경우가 없을 때 + # ex) 알고리즘 7시간, 컴구조 4시간 일때 최대 공부시간은 11시간이다. + # 12, 13 ...시간인 경우는 존재하지 않는다. + # 이때 개인 평균 학점을 4.5로 설정해주고 + # 각 과목의 공부 투자시간을 목표 시간과 똑같이 설정해준다.(다 공부할 수 있으므로) + # 그리고 각 과목별 학점 4.5이다. if study_time not in all_study_cases: # print("all_study_cases =", study_time) self.best_solo_avg_grades[study_time] = 4.5 self.best_solo_subject_study_cases[study_time] = [subject.bt for subject in self.subject_list] self.best_solo_subjects_grades[study_time] = [4.5 for subject in self.subject_list] continue + # 각 공부시간에 따른 과목별 투자 시간의 경우의 수를 돌면서 + # ex) 알고리즘 7시간, 컴구조 4시간 일때 + # study_case는 (0, 0), (3,2), (7,4) 등이 되는데 + # 이때의 각 과목별 투자시간에 따른 점수와 학점 및 평균 학점을 구한다. + # 경우의 수를 돌면서 구한 평균학점이 높으면 갱신해주어서 + # 제일 높은 평균 학점을 받았을 때의 평균 학점, 과목별 투자시간, 과목별 학점을 저장한다. for study_case in all_study_cases[study_time]: grade_list = [] total_grade_sum = 0 @@ -76,13 +117,15 @@ def set_best_solo_cases(self): grade_list.append(grade) total_grade_sum += grade * self.subject_list[subject_idx].credit avg_grade = total_grade_sum / (self.total_credits - 3) - if self.best_solo_avg_grades[study_time] <= avg_grade: - if self.best_solo_avg_grades[study_time] < avg_grade: - self.best_solo_avg_grades[study_time] = avg_grade - self.best_solo_subject_study_cases[study_time] = study_case[:] - self.best_solo_subjects_grades[study_time] = grade_list[:] + if self.best_solo_avg_grades[study_time] < avg_grade: + self.best_solo_avg_grades[study_time] = avg_grade + self.best_solo_subject_study_cases[study_time] = study_case[:] + self.best_solo_subjects_grades[study_time] = grade_list[:] def get_all_study_cases(self): + """ + 중복 순열을 통해서 0 ~ 24시간까지의 모든 과목별 공부 투자 경우의 수를 구함 + """ all_study_cases = defaultdict(list) for study_subject_time_case in product(*[range(subject.bt + 1) for subject in self.subject_list]): @@ -92,12 +135,24 @@ def get_all_study_cases(self): return all_study_cases def make_student_real_subject_list(self): + """ + 학생에게 주어진 과목의 실제 공부 시간을 계산하는 함수 + + :desc + 학생 A - 알고리즘 7시간, 컴구조 4시간 + self.best_solo_subject_study_case는 학생이 best 학점을 받기 위해 주어진 과목을 공부하는 시간의 경우이다. + ex) [7, 4] or [0, 2](시간이 부족해서 컴구조 2시간 공부가 최선인 경우) 등 + 여기서 [0, 2] 인 경우는 주어진 과목 공부 7, 4시간이지만 실제 공부시간은 0,2시간이다. + 실제 공부시간으로 스케줄링을 돌리기 위해서 주어진 과목들을 각각 복사하며 + 주어진 공부시간(bt, remain_bt)를 실제 최적 공부시간(best_subject_study_time)으로 변환해서 + real_subject_list로 만들어준다. + """ real_subject_list = [] for idx, best_subject_study_time in enumerate(self.best_solo_subject_study_case): if best_subject_study_time > 0: real_subject = copy.deepcopy(self.subject_list[idx]) real_subject.bt = best_subject_study_time - real_subject.remain_bt = real_subject.bt + real_subject.remain_bt = best_subject_study_time real_subject_list.append(real_subject) if self.best_each_team_play_time > 0: real_subject_list.append( diff --git a/yosa.py b/yosa.py index 770becb..435ccbf 100644 --- a/yosa.py +++ b/yosa.py @@ -18,7 +18,60 @@ def __init__(self, subject_input_list, student_count, max_team_play_time): self.each_student_history_list = [] self.allocate_subject_to_student() + def create_students(self): + return [Student(idx) for idx in range(self.student_count)] + + def allocate_subject_to_student(self): + # 과목 리스트를 돌면서 + for subject in self.subjects: + # 그 과목을 할당받은 학생을 찾으면 할당해줌 + for student in self.students: + if subject.student_id == student.id: + student.add_subject_list(subject) + break + + def run(self): + """ + best_team_play_case_list의 한 case에는 + [0] 최적의 팀플 공부시간 ex)[7,4] (0번 학생 7시간, 1번 학생 4시간) + [1] 이때의 각 학생의 학점 ex) [4.0, 3.5] + [2] 이때의 팀 최종 평균 + """ + best_team_play_case = self.find_best_team_play_case() + self.team_avg_grade = best_team_play_case[2] + print("team_avg = ", self.team_avg_grade) + for student in self.students: + # 1.학생의 best인 경우 정보를 설정해줌 + student.calculate_best_case(best_team_play_case, self.max_team_play_time) + # 현재 나온 학생들을 기준으로 각각 1개짜리로 돌려서 + # history를 모은 each_student_history_list를 만들어서 돌린다. + # 2. 학생의 실제 공부 시간 계산 + student_real_subject_list = student.make_student_real_subject_list() + # 3. 이 정보를 가지고 스케줄링을 돌림 + if random.choice([True, False]): + scheduler = SPN(student_real_subject_list, 1) + else: + scheduler = RR(student_real_subject_list, 1, random.randrange(1, 4)) + scheduler.run() + # 학생이 4명이면 4개의 히스토리를 저장함 + self.each_student_history_list.append(scheduler.history) + def find_best_team_play_case(self): + """ + 1. 각 학생들의 각 개인 공부시간에 따른 + best_case(평균 학점, 과목별 투자시간, 과목별 학점)를 구해서 각 학생들에게 저장해놓는다. + 2. 각 학생들의 모든 팀플 투자 하는 경우의 수를 구한다. + 3. 팀플 투자 경우의 수에 따른 + 각 학생의 팀플 투자시간과 따른 개인공부시간(24 - each_team_play_time)을 통해서 + 최종 학점을 구한다. + 4. 각 학생의 최종 학점을 통해 팀 전체의 평균 학점을 구한다. + 5. 기존에 구한 최고 평균학점과 비교하며 팀 전체의 평균 학점이 제일 높은 경우들을 찾는다 + 6. 팀 전체의 평균 학점이 제일 높은 경우중에 + 팀원들의 팀플 투자시간이 합이 제일 적고 표준편차가 제일 작은 경우를 구해서 + 최종적으로 반환해준다. + """ + # @<1> 각 학생들의 각 개인 공부시간에 따른 + # best_case(평균 학점, 과목별 투자시간, 과목별 학점)를 구한다. for student in self.students: student.set_best_solo_cases() # print(student.best_solo_avg_grades) @@ -28,11 +81,15 @@ def find_best_team_play_case(self): # final_grade = [] # team_play_time_case = ex) [0,0,0,0] or [0,4,5,7] or [24,24,24,24] # [1, 7, 2, 4] 팀플에 학생1은 1시간, 학생2는 7시간, 학생3는 2시간, 학생4는 4시간 투자 + # @<2>각 학생들의 모든 팀플 투자 하는 경우의 수를 구한다. for team_play_time_case in product(*[range(25) for each_student_case in range(self.student_count)]): + # 목표 팀플시간이 20시간인데 40시간을 투자할 수는 없다. if sum(team_play_time_case) <= self.max_team_play_time: final_student_grade_list = [] final_average_team_grade = 0 + # @<3>각 학생의 팀플 투자시간과 따른 개인공부시간(24 - each_team_play_time)을 통해서 + # 최종 학점을 구한다. for student_idx, each_team_play_time in enumerate(team_play_time_case): final_student_grade_list.append( self.students[student_idx].get_final_student_grade( @@ -40,53 +97,29 @@ def find_best_team_play_case(self): ) ) # final_grade.append(final_student_grade_list) + # @<4> 각 학생의 최종 학점을 통해 팀 전체의 평균 학점을 구한다. final_average_team_grade = sum(final_student_grade_list) / len(final_student_grade_list) - # 이거 원래 > 이렇게 되어야 함 + # @<5>팀 전체의 평균 학점이 제일 높은 경우들을 찾는다 if final_average_team_grade >= best_average_team_grade: if final_average_team_grade > best_average_team_grade: best_average_team_grade = final_average_team_grade best_team_play_case_list = [] + """ + best_team_play_case_list의 한 case에는 + [0] 최적의 팀플 공부시간 ex)[7,4] (0번 학생 7시간, 1번 학생 4시간) + [1] 이때의 각 학생의 학점 ex) [4.0, 3.5] + [2] 이때의 팀 최종 평균 + """ best_team_play_case_list.append( (team_play_time_case[:], final_student_grade_list[:], final_average_team_grade) ) - # print("final_grade by 1", sorted(final_grade, key=lambda x: x[0], reverse=True)[:20]) - # print("final_grade by 2", sorted(final_grade, key=lambda x: x[1], reverse=True)[:20]) - # print("best_average_team_grade", best_average_team_grade) - # print("best_team_play_case_grade_list", best_team_play_case_grade_list) print("==========================================================================") print("MAX_TEAM_PLAY_TIME", self.max_team_play_time) print("best_team_play_case_list", best_team_play_case_list) - # best는 합이 제일 적고 표준편차가 제일 작은 경우 + # @ <6>팀 전체의 평균 학점이 제일 높은 경우중에 + # 팀원들의 팀플 투자시간이 합이 제일 적고 표준편차가 제일 작은 경우를 구해서 + # 최종적으로 반환해준다. best_team_play_case = sorted(best_team_play_case_list, key=lambda x: (sum(x[0]), std(x[0])))[0] print("best_team_play_case", best_team_play_case) return best_team_play_case - - def create_students(self): - return [Student(idx) for idx in range(self.student_count)] - - # best_team_play_case 의 학생들의 평균 학점하고, 팀 전체 평균 학점이 같은지 확인 - def run(self): - best_team_play_case = self.find_best_team_play_case() - self.team_avg_grade = best_team_play_case[2] - print("team_avg = ", self.team_avg_grade) - for student in self.students: - student.calculate_best_case(best_team_play_case, self.max_team_play_time) - # 현재 나온 학생들을 기준으로 각각 1개짜리로 돌려서 - # history를 모은 each_student_history_list를 만들어서 돌린다. - student_real_subject_list = student.make_student_real_subject_list() - if random.choice([True, False]): - scheduler = SPN(student_real_subject_list, 1) - else: - scheduler = RR(student_real_subject_list, 1, random.randrange(1, 4)) - scheduler.run() - self.each_student_history_list.append(scheduler.history) - - def allocate_subject_to_student(self): - # 과목 리스트를 돌면서 - for subject in self.subjects: - # 그 과목을 할당받은 학생을 찾으면 할당해줌 - for student in self.students: - if subject.student_id == student.id: - student.add_subject_list(subject) - break