Skip to content

●  사용방법 · 시간표

학회 일정

발표를 시간대와 발표장에 배치합니다. 발표자가 가능한 시간을 지키고, 같은 주제가 한 시간대에 몰리지 않게 하며, 인기 발표는 큰 발표장에 배정합니다.

무엇을 정하나요

발표마다 시간대와 발표장을 정합니다.

최소 실행 예제

from optimaru import conference_scheduling as cs
from optimaru.conference_scheduling.models import (
    ConferenceScheduleModel, RoomModel, SpeakerModel, TalkModel, TimeslotModel,
)

problem = ConferenceScheduleModel(
    name="demo",
    talk_types=["Talk"],
    timeslots=[
        TimeslotModel(id="S1", start_minute=540, end_minute=585, talk_types=[0]),
        TimeslotModel(id="S2", start_minute=630, end_minute=675, talk_types=[0]),
    ],
    rooms=[
        RoomModel(id="R1", capacity=200, talk_types=[0]),
        RoomModel(id="R2", capacity=50, talk_types=[0]),
    ],
    speakers=[SpeakerModel(id="Ana"), SpeakerModel(id="Ben", unavailable_timeslots=[0])],
    talks=[
        TalkModel(code="T1", speakers=[0], theme_track_tags=["AI"], favorite_count=120),
        TalkModel(code="T2", speakers=[1], theme_track_tags=["AI"], favorite_count=40),
        TalkModel(code="T3", speakers=[0], theme_track_tags=["Ops"], favorite_count=10),
    ],
)

core = problem.to_core()
cs.solve(core, time_limit_seconds=2.0, random_seed=42)  # 그 자리에서 풉니다
solved = ConferenceScheduleModel.from_core(core)
print(solved.score_hard, solved.score_soft)
for talk in solved.talks:
    slot, room = divmod(talk.slot_room, len(solved.rooms))
    print(talk.code, solved.timeslots[slot].id, solved.rooms[room].id)

같은 유스케이스를 그림과 실행 결과가 담긴 Jupyter 노트북으로도 볼 수 있습니다. examples/conference-scheduling.ipynb ↗

입력 파라미터

TimeslotModel

필드 의미
id 필수 입력 시간대 id입니다. start_minute 필수 입력 공통 기준부터 센 시작 시각(분)입니다. 자정은 1440의 배수입니다. end_minute 필수 입력 종료 시각(분)입니다. talk_types 필수 입력 이 시간대가 받는 발표 유형의 talk_types 내 위치입니다. tags 발표와 발표자가 요구하거나 피할 수 있는 자유 태그입니다.

RoomModel

필드 의미
id 필수 입력 발표장 id입니다. capacity 좌석 수입니다. 인기 발표가 큰 발표장에 가도록 쓰입니다. talk_types 이 발표장이 받는 발표 유형의 talk_types 내 위치입니다. unavailable_timeslots 발표장이 닫혀 있는 시간대의 timeslots 내 위치입니다. tags 자유 태그입니다.

SpeakerModel

필드 의미
id 필수 입력 발표자 id입니다. unavailable_timeslots 발표자가 올 수 없는 시간대의 timeslots 내 위치입니다. required_timeslot_tagsprohibited_timeslot_tagsrequired_room_tagsprohibited_room_tags 시간대나 발표장에 반드시 있어야 하거나 없어야 하는 태그입니다. 필수 제약입니다. preferred_timeslot_tagsundesired_timeslot_tagspreferred_room_tagsundesired_room_tags 발표자가 원하거나 피하고 싶은 태그입니다. 선호 제약입니다.

TalkModel

필드 의미
code 필수 입력 발표 id입니다. talk_type talk_types 내 위치입니다. speakers speakers 내 위치입니다. theme_track_tags 주제 트랙입니다. 같은 트랙의 발표는 겹치지 않는 것이 좋습니다. sector_tags 대상 산업 분야입니다. 같은 분야의 발표는 겹치지 않는 것이 좋습니다. audience_types 청중 유형입니다. audience_level 청중 수준입니다. 다양성과 내용 흐름 판단에 씁니다. content_tags 내용 태그입니다. 내용이 같은 발표는 겹치지 않는 것이 좋습니다. language 발표 언어입니다. 기본값은 en입니다. required_timeslot_tagsprohibited_timeslot_tagsrequired_room_tagsprohibited_room_tags 시간대나 발표장에 반드시 있어야 하거나 없어야 하는 태그입니다. 필수 제약입니다. preferred_timeslot_tagsundesired_timeslot_tagspreferred_room_tagsundesired_room_tags 발표가 원하거나 피하고 싶은 태그입니다. 선호 제약입니다. mutually_exclusive_talks_tags 이 태그를 공유하는 발표는 겹치면 안 됩니다. prerequisite_talks 먼저 열려야 하는 발표의 talks 내 위치입니다. favorite_count 인기도입니다. 인기 발표가 큰 발표장에 가도록 쓰입니다. crowd_control_risk 0보다 크면 사람이 몰리는 발표로 봅니다. pinned 이 발표의 slot_room을 고정합니다.

ConferenceScheduleModel

필드 의미
name 필수 입력 일정 이름입니다. talk_types 필수 입력 발표 유형 이름 목록입니다. timeslots 필수 입력 시간대 목록입니다. rooms 필수 입력 발표장 목록입니다. speakers 발표자 목록입니다. talks 발표 목록입니다. minimum_consecutive_talks_pause_in_minutes 한 발표자의 연속 발표 사이 최소 간격(분)입니다. 기본값은 30입니다.

풀이 파라미터

풀이를 호출할 때 넘기는 값입니다. 시간 제한, 시드, 병렬 수가 여기에 있습니다.

파라미터 기본값 의미
time_limit_seconds None 탐색 시간(초)이며, 0부터 1e9까지 줄 수 있습니다. 지정하지 않으면 설정의 spent_limit_seconds를 쓰며, 기본값은 30입니다.
random_seed None 탐색에 쓰는 난수 시드입니다. 지정하지 않으면 설정값을 쓰며, 기본값은 0입니다.
parallel_solver_count None 독립적으로 동시에 돌리는 탐색 수입니다. 탐색마다 시드가 다르고 시간은 똑같이 쓰며, 가장 좋은 결과를 고릅니다. 지정하지 않으면 설정값을 쓰며, 기본값은 1입니다.
stop_at_first_feasible False 필수 점수가 0이 되는 즉시 멈춥니다.
on_new_best None 새 최고 해를 찾을 때마다 부르는 콜백입니다. 콜백이 예외를 내면 풀이를 멈추고 그 예외를 그대로 냅니다.
config None 기본으로 쓸 SolverConfig입니다. 여기서 준 키워드 인자는 이번 풀이에만 이 값을 덮어쓰며, 넘긴 객체 자체는 바뀌지 않습니다.
constraints None 점수에 넣을 제약과 그 설정입니다. 지정하지 않으면 기본 제약을 씁니다.
탐색 옵션 전체 (26)

SolverConfig에 값을 넣어 config=로 넘기세요.

파라미터 기본값 의미
best_score_limit — 최고 점수가 이 값에 닿으면 일찍 멈춥니다. 기본값으로는 작동하지 않습니다.
change_move_weight 0.75 변경 이동의 상대적 비중입니다. 0이면 쓰지 않습니다.
compatible_value_probability 0.9 변경 이동이 발표 유형을 받는 칸만 고를 확률입니다. 0이면 쓰지 않습니다.
descent_weight 0.0 최선 개선 하강의 비중입니다. 0이면 끕니다.
full_assert False 증분 점수를 전체 재계산과 매번 비교합니다. 느리므로 디버깅할 때만 씁니다.
hot_talk_probability 0.0 필수 위반이 있는 발표를 옮길 확률입니다. 0이면 쓰지 않습니다.
late_acceptance_size 0 늦은 수락(late acceptance) 기록의 길이입니다. 0이면 문제 크기에 맞춰 정합니다.
on_new_best None 새 최고 해를 찾을 때마다 부르는 콜백입니다. 콜백이 예외를 내면 풀이를 멈추고 그 예외를 그대로 냅니다.
parallel_solver_count 1 독립적으로 동시에 돌리는 탐색 수입니다. 탐색마다 시드가 다르고 시간은 똑같이 쓰며, 가장 좋은 결과를 고릅니다.
random_seed 0 탐색에 쓰는 난수 시드입니다.
restart_segments 8 시간 제한을 나눠 쓰는 연속 로컬 서치 횟수입니다. 1이면 한 번만 돕니다.
ruin_recreate True 탐색이 정체되면 적응형 파괴·재구성을 실행합니다.
ruin_recreate_as_move_max_ruin 12 그 작은 파괴로 제거할 최대 항목 수입니다.
ruin_recreate_as_move_weight -1.0 한 걸음을 작은 파괴·복구로 쓰고 일반 이동처럼 판단할 확률입니다. 음수는 지원하는 유스케이스에서 자동 선택이고, 0이면 끕니다.
ruin_recreate_max_ruin_count 60 한 번에 제거하는 항목 수의 절대 상한입니다.
ruin_recreate_max_ruin_fraction 0.3 한 번에 제거하는 해의 최대 비율입니다.
ruin_recreate_min_ruin_fraction 0.1 한 번에 제거하는 해의 최소 비율입니다.
ruin_recreate_operator_decay 0.8 연산자 가중치가 적응하는 속도입니다.
ruin_recreate_polish_steps 5000 실행 후 다듬는 언덕 오르기 이동 수입니다. step_count_limit에는 세지 않습니다.
ruin_recreate_rewards [33.0, 9.0, 3.0, 0.0] 새 최고, 개선, 수락, 거절 결과에 주는 연산자 보상입니다.
ruin_recreate_unimproved_step_trigger 5000 파괴·재구성을 실행하기까지 새 최고 해 없이 지나는 걸음 수입니다.
spent_limit_seconds 30.0 탐색 시간(초)이며, 0부터 1e9까지 줄 수 있습니다.
step_count_limit 0 이 걸음 수에 도달하면 멈춥니다. 0이면 제한이 없습니다.
swap_move_weight 0.25 교환 이동의 상대적 비중입니다. 0이면 쓰지 않습니다.
unimproved_spent_limit_seconds 0.0 새 최고 해 없이 이 시간(초)이 지나면 멈춥니다. 0이면 제한이 없습니다.
unimproved_step_count_limit 0 새 최고 해 없이 이 걸음 수가 지나면 멈춥니다. 0이면 제한이 없습니다.

돌아오는 결과

solve는 엔진 객체를 받아 그 자리에서 풀고 돌려줍니다. 결과는 from_core로 변환해 읽습니다.

TalkModel

필드 의미
slot_room timeslot_index * room_count + room_index로 만든 합성 값입니다. -1이면 미배정입니다.

ConferenceScheduleModel

필드 의미
score_hard 필수 점수입니다. 0이면 가능한 해입니다. score_soft 선호 점수입니다. 보상에서 벌점을 뺀 값입니다.

제약

optimaru.conference_scheduling.constraints에서 클래스를 가져와 TalkTypeIncompatibilityCost()처럼 호출해서 넘깁니다. 넘긴 제약만 점수에 들어가고, 아무것도 넘기지 않으면 기본 제약을 씁니다. 목록에 같은 제약을 여러 번 넣을 수 있으며, 넣은 것마다 따로 점수에 들어갑니다. 제약마다 다음 파라미터를 받습니다.

파라미터 기본값 의미
weight None 제약 비용에 곱하는 값이며, 적용되는 수준의 단위로 셉니다. 지정하지 않으면 아래 기본 가중치를 씁니다. 기본 가중치가 0인 제약은 가중치를 줘야 작동합니다.
level None "hard"면 필수, "soft"면 선호로 바꿉니다. Level.HARD, Level.SOFT도 됩니다. 지정하지 않으면 아래 수준을 그대로 씁니다. 이 유스케이스에는 중간 수준이 없어서 "medium"을 주면 ValueError가 납니다. 보상에 "hard"를 주거나 수준이 고정된 제약의 수준을 바꾸려 해도 ValueError가 납니다.
exponent 1.0 부호를 유지한 채 비용에 거듭제곱을 적용하며, 0보다 커야 합니다. offset을 반영한 뒤에 적용합니다. 2.0이면 제곱이라 한곳에 몰린 위반의 비용이 크게 늘어납니다. 차량이나 날짜 같은 단위마다 적용하고, 합계 하나로 계산하는 제약에는 그 합계에 적용합니다.
offset 0.0 거듭제곱 전에 비용 x에서 빼는 값입니다. exponent처럼 단위마다, 합계로 계산하는 제약은 그 합계에 적용하며, 비용과 같은 척도(초, 분, 개수 등)로 셉니다. 부호와 상관없이 유한한 수면 되고, 키워드로만 줄 수 있습니다. 이 값 아래에서 어떻게 계산할지는 clip이 정합니다.
clip True True면 offset을 문턱값으로 씁니다. 넘은 부분만 계산하므로(max(0, x - offset) ** exponent) 그 이하의 비용은 아무것도 더하지 않습니다. False면 부호를 유지한 채 (x - offset) ** exponent를 그대로 계산하므로, 오프셋보다 작은 단위는 비용이 0이어도 음수, 곧 보상으로 들어갑니다. 하드 점수에 들어가는 수준에서는 clip=False에 0이 아닌 오프셋을 주면 ValueError가 납니다. 하드 0이 위반 없음이라는 뜻을 지키기 위해서입니다. 키워드로만 줄 수 있습니다.

audience_type_diversity_cost, audience_level_diversity_cost, language_diversity_cost는 비용이 음수인 보상입니다. 가중치를 올리면 점수가 올라가고, level="hard"를 주면 ValueError가 납니다. 나머지는 모두 벌점입니다.

위의 최소 실행 예제에 이어서 실행합니다.

from optimaru.conference_scheduling.constraints import (
    ContentConflictCost, RoomConflictCost, SpeakerConflictCost, get_constraints,
)

picked = get_constraints([RoomConflictCost(), SpeakerConflictCost(), ContentConflictCost(weight=500)])
custom = problem.to_core()
cs.solve(custom, time_limit_seconds=2.0, random_seed=42, constraints=picked)
print(custom.score)
이름 수준 기본 가중치 하는 일
talk_type_incompatibility_cost 필수 100000 발표 유형을 받지 않는 시간대나 발표장에 놓이면 벌점을 줍니다.
room_unavailability_cost 필수 100000 닫혀 있는 시간대의 발표장에 놓이면 벌점을 줍니다.
room_conflict_cost 필수 1000 시간이 겹치는 두 발표가 같은 발표장을 쓰면 겹친 시간(분)만큼 벌점을 줍니다.
speaker_unavailability_cost 필수 100 발표자가 올 수 없는 시간대에 놓이면 벌점을 줍니다.
speaker_conflict_cost 필수 10 시간이 겹치는 두 발표가 발표자를 공유하면 발표자별로 겹친 시간(분)만큼 벌점을 줍니다.
talk_prerequisite_talks_cost 필수 10 선행 발표보다 먼저 열리거나 겹치면 벌점을 줍니다.
talk_mutually_exclusive_talks_tags_cost 필수 1 서로 배타적인 태그를 공유하는 두 발표가 겹치면 벌점을 줍니다.
consecutive_talks_pause_cost 필수 1 한 발표자의 연속 발표 사이에 최소 간격이 없으면 벌점을 줍니다.
crowd_control_risk_cost 필수 1 사람이 몰리는 발표가 같은 시간대에 그런 발표 둘 이상과 겹치면 벌점을 줍니다.
speaker_required_timeslot_tags_cost 필수 1 발표자가 요구한 태그가 시간대에 없으면 벌점을 줍니다.
speaker_prohibited_timeslot_tags_cost 필수 1 발표자가 금지한 태그가 시간대에 있으면 벌점을 줍니다.
talk_required_timeslot_tags_cost 필수 1 발표가 요구한 태그가 시간대에 없으면 벌점을 줍니다.
talk_prohibited_timeslot_tags_cost 필수 1 발표가 금지한 태그가 시간대에 있으면 벌점을 줍니다.
speaker_required_room_tags_cost 필수 1 발표자가 요구한 태그가 발표장에 없으면 벌점을 줍니다.
speaker_prohibited_room_tags_cost 필수 1 발표자가 금지한 태그가 발표장에 있으면 벌점을 줍니다.
talk_required_room_tags_cost 필수 1 발표가 요구한 태그가 발표장에 없으면 벌점을 줍니다.
talk_prohibited_room_tags_cost 필수 1 발표가 금지한 태그가 발표장에 있으면 벌점을 줍니다.
theme_track_conflict_cost 선호 10 주제 트랙이 같은 두 발표가 겹치면 벌점을 줍니다.
theme_track_room_change_cost 선호 10 같은 날 같은 트랙의 두 발표가 다른 발표장에서 열리면 벌점을 줍니다.
sector_conflict_cost 선호 10 대상 분야가 같은 두 발표가 겹치면 벌점을 줍니다.
audience_type_theme_track_conflict_cost 선호 1 주제 트랙과 청중 유형이 모두 같은 두 발표가 겹치면 벌점을 줍니다.
content_audience_level_flow_violation_cost 선호 10 내용이 같은 입문 발표가 심화 발표보다 늦거나 겹치면 벌점을 줍니다.
content_conflict_cost 선호 100 내용이 같은 두 발표가 겹치면 벌점을 줍니다. 선호 규칙 중 가장 무겁습니다.
different_day_talks_cost 선호 10 내용이나 트랙이 같은 두 발표가 다른 날에 열리면 벌점을 줍니다.
popular_talks_room_size_cost 선호 10 덜 인기 있는 발표가 더 인기 있는 발표보다 큰 발표장을 쓰면 벌점을 줍니다.
speaker_preferred_timeslot_tags_cost 선호 20 발표자가 원하는 태그가 시간대에 없으면 벌점을 줍니다.
speaker_undesired_timeslot_tags_cost 선호 20 발표자가 피하고 싶은 태그가 시간대에 있으면 벌점을 줍니다.
talk_preferred_timeslot_tags_cost 선호 20 발표가 원하는 태그가 시간대에 없으면 벌점을 줍니다.
talk_undesired_timeslot_tags_cost 선호 20 발표가 피하고 싶은 태그가 시간대에 있으면 벌점을 줍니다.
speaker_preferred_room_tags_cost 선호 20 발표자가 원하는 태그가 발표장에 없으면 벌점을 줍니다.
speaker_undesired_room_tags_cost 선호 20 발표자가 피하고 싶은 태그가 발표장에 있으면 벌점을 줍니다.
talk_preferred_room_tags_cost 선호 20 발표가 원하는 태그가 발표장에 없으면 벌점을 줍니다.
talk_undesired_room_tags_cost 선호 20 발표가 피하고 싶은 태그가 발표장에 있으면 벌점을 줍니다.
speaker_makespan_cost 선호 20 발표자의 발표가 이틀을 넘겨 흩어지면 벌점을 줍니다.
audience_type_diversity_cost 선호 보상 1 한 시간대에 여러 청중 유형을 다루면 보상을 줍니다.
audience_level_diversity_cost 선호 보상 1 한 시간대에 여러 청중 수준이 섞이면 보상을 줍니다.
language_diversity_cost 선호 보상 10 한 시간대에 여러 언어의 발표가 열리면 보상을 줍니다.

제약 사용법 →

기존 해에서 시작하기

최신 버전이 필요합니다. pip install -U optimaru로 올려 주세요.

with_initial_solution(problem, solution)은 solution에서 탐색을 시작하는 problem의 복사본을 돌려줍니다. solution은 풀린 ConferenceScheduleModel이나 그 JSON 딕셔너리입니다. solve는 엔진 객체를 받으므로 to_core()로 변환해 넘깁니다.

위의 최소 실행 예제에 이어서 실행합니다.

restart = cs.with_initial_solution(problem, solved).to_core()
cs.solve(restart, time_limit_seconds=2.0, random_seed=43)
print(restart.score)
  • 발표는 code로 맞춥니다.
  • 완전한 해를 넣으면 구성 단계를 건너뛰고 그 해에서 바로 탐색을 시작합니다. 일부만 넣으면 넣은 부분은 그대로 두고, 빠진 발표만 새로 구성합니다.
  • time_limit_seconds=0을 주면 바로 멈추므로 완전한 해는 넣은 그대로 돌아옵니다. step_count_limit = 0은 제한이 없다는 뜻이므로, 바로 멈추려면 시간 제한을 쓰세요.
  • 고정된 발표는 해의 내용과 상관없이 problem에 있는 값을 유지합니다.
  • slot_room은 시간대와 발표장 목록의 위치로 만든 값입니다. 그래서 해의 목록이 다르거나 순서만 달라도 ValueError가 납니다. 모르는 코드와 범위를 벗어난 값도 마찬가지입니다.

예외와 제한

  • 탐색은 시간대×발표장 격자 하나에서 이루어집니다. 발표를 맞는 칸에 두는 일은 talk_type_incompatibility_cost가 맡으므로, 이 규칙을 없앨 생각이 아니면 켜 두세요.
  • 발표자, 선행 발표, 발표 유형, 불가능한 시간대는 id가 아니라 목록 안의 위치로 적습니다.