This software uses a Quadratic Integer Programming (QIP) formulation to produce an optimal conference schedule given reviewers' bidding preferences. The QIP formulation was derived by Jakob Weissteiner (University of Zurich), Sven Seuken (Univeristy of Zurich), and Ilya Segal (Stanford University). This software was used to create the official Conference schedule (150 papers) for the 23rd ACM Conference on Economics and Computation (EC'22).
- Python 3.8
- CPLEX 20.01.0
First prepare your python environment myenv (conda
, virtualenv
, etc.).
Next install CPLEX 20.01.0. Once CPLEX is installed, install the CPLEX python API. For this first activate your environment myenv
$ source ~/myenv/bin/activate
and then navigate to the file setup.py located in ...\IBM\ILOG\CPLEX_Studio201\python and run
$ python3 setup.py install
In the following, we describe the QIP.
Parameter | Explanation | Example | Type |
---|---|---|---|
Session indices | [1,2] | list | |
Track indices | [1,2,3,4] | list | |
Author indices | [1,...,20] | list | |
Paper indices | [1,...,32] | list | |
Bidder indices | [1,...,20] | list | |
Topic indices | [1,...,10] | list | |
Bidders' utilities map U, i.e., |
{(1,12): 23.45, (1,14): 22.7, (7,4): 9.3,...} | dict | |
Paper-author map M, i.e., |
{(1,3): 1, (1,6):1, (3,4):1,...} | dict | |
Paper-session map |
{(5,1): 1, (14,1): 1, (7,2): 1,...} | dict | |
Paper-topic map |
{(1,2): 1, (1,7):1, (26,4):1,...} | dict | |
Map between paperID and paper title. | {1: 'Paper Title 1', 2: 'Paper Title 2', 3: 'Paper Title3',...} | dict | |
Map between paperID and all authors of the corresponding paper. | {1: ['Author1','Author2'], 2: ['Author5'], 3: ['Author2', 'Author4', 'Author8'] ,...} | dict(list) | |
Map between paperID and all topics of the corresponding paper. | {1: ['Topic1','Topic2'], 2: ['Topic5'], 3: ['Topic2', 'Topic4', 'Topic8'] ,...} | dict(list) |
Parameter | Explanation | Example | Type |
---|---|---|---|
Capacity per subsession, i.e. session-track tuple. | 4 | int | |
Cost for a bidder attending a subsession, i.e. session-track tuple. | 5 | int | |
Cost for a "topic"-bidder attending a subsession, i.e. session-track tuple. | 25 | int | |
Constant utility (constant analogue to |
100 | int |
The decision variable
The decision variable
The decision variable
The decision variable
In this section, we present the QIP objective and its constraints.
The QIP maximizes the following objective
where the interpretation of each of the four objective terms is given as
(obj1): sum of bidders' utilities.
(obj2): sum of bidders' costs for attending a subsession (i.,e, session-track tuple) using a constant bidder-cost
(obj3): sum of topics' utilities when using a constant topic utility
(obj4): sum topics' costs for beeing present in a subsession (i.e., session-track tuple) using a constant topic-cost
- For all
$p \in paper\_ids: \, \sum_{j \in session\_ids} \sum_{k \in track\_ids} x_{p,j,k} = 1\quad$ (Each paper appears exactly once) - For all
$j \in session\_ids$ , for all$k \in track\_ids: \, \sum_{p \in paper\_ids} x_{p,j,k} = track\_session\_capacity\quad$ (Each track has exactly$track\_session\_capacity$ papers) - For all
$\{(j,p): T(j,p)==1\}$ and for all$k \in track\_ids: \, x_{p,j,k} = 0$ (Time conflicts)
- For all
$b \in bidder\_ids$ and for all$j \in session\_ids: \, \sum_{k \in track\_ids} y_{b,j,k} <= 1\quad$ (A bidder cannot be in more than one track per session)
- For all
$\{(a,p): M(a,p)==1\}$ , for all$j \in session\_ids$ and for all$k \in track\_ids: \, z_{a,j,k} >= x_{p,j,k}\quad$ (An author needs to attend a specific subsession, i.e., session-track tuple, if her paper is allocated to that subsession) - For all
$a \in author\_ids$ and for all$j \in session\_ids: \, \sum_{k \in track\_ids} z_{a,j,k} <= 1\quad$ (An author cannot be in more than one track per session)
- For all
$t \in topic\_ids$ and for all$j \in session\_ids: \, \sum_{k \in track\_ids} q_{t,j,k} <= 1\quad$ (A "topic"-bidder cannot be in more than one track per session)
First you need to prepare your raw data and create all the data input objects described in Section 3.1.1 Data Input and save them in the folder /data_prepared.
Note that for testing purposes, we provide random data input files in the folder data_prepared (if you wish to create new different random data input, then you can go to the file create_random_instance.py and make your desired changes accordingly, e.g., increasing the number of papers).
Next, open the file create_schedule.py:
# %% Path
save_data_path = os.path.join(os.getcwd(),'data_prepared')
#create_random_instance(seed=1,save_data_path=save_data_path)
If you already created your data input (either real-world data or our random data input) then you can leave the line create_random_instance(seed=1,save_data_path=save_data_path) commented. Otherwise, if you want to create new random data input then you have to uncomment this line.
Next, set the input parameters:
# %% Set Input Parameters
track_session_capacity = 4
paper_distribution = 'exact' # 'exact' or 'upper_bound'
bidder_cost = 5
topic_cost = 25
topic_utility = 100
# QIP parameters
QIP_parameters = {'log_output': False,
'time_limit': 60, # in seconds
'mip_relative_gap': 0.01,
'integrality_tol': None,
'feasibility_tol': None,
}
Specifically, the parameter paper_distribution determines if a
Once you set the input parameters first the data input is loaded from the folder data_prepared:
# %% Load Data Input
# U MAPPING: U(b,p)= scaled preference of bidder_id:b for paper_id:p
U = pkl.load(open(os.path.join(save_data_path,'U.pkl'), 'rb'))
# M MAPPING: M(a,p)==1 iff author_id: a is an author of paper_id:p
M = pkl.load(open(os.path.join(save_data_path,'M.pkl'), 'rb'))
# T MAPPING: T(j,p)==1 iff paper_id:p CANNOT be presented in session:j
T = pkl.load(open(os.path.join(save_data_path,'T.pkl'), 'rb'))
# Q MAPPING: Q(p,t)==1 iff paper_id:p has topic ID:t
Q = pkl.load(open(os.path.join(save_data_path,'Q.pkl'), 'rb'))
# session_ids
session_ids = pkl.load(open(os.path.join(save_data_path,'session_ids.pkl'), 'rb'))
# track_ids
track_ids = pkl.load(open(os.path.join(save_data_path,'track_ids.pkl'), 'rb'))
# paper_ids
paper_ids = pkl.load(open(os.path.join(save_data_path,'paper_ids.pkl'), 'rb'))
# bidder_ids
bidder_ids = pkl.load(open(os.path.join(save_data_path,'bidder_ids.pkl'), 'rb'))
# author_ids
author_ids = pkl.load(open(os.path.join(save_data_path,'author_ids.pkl'), 'rb'))
# author_ids
topic_ids = pkl.load(open(os.path.join(save_data_path,'topic_ids.pkl'), 'rb'))
# paper_title_dict
paper_title_dict = pkl.load(open(os.path.join(save_data_path,'paper_title_dict.pkl'), 'rb'))
# paper_author_dict
paper_author_dict = pkl.load(open(os.path.join(save_data_path,'paper_author_dict.pkl'), 'rb'))
# paper_topic_dict
paper_topic_dict = pkl.load(open(os.path.join(save_data_path,'paper_topic_dict.pkl'), 'rb'))
and finally the QIP is instantiated, solved and an output folder QIP_RESULTS_<day_month_year>_ is created.
# %% QIP
# INSTNATIATE AND BUILD QIP
QIP_instance = QIP(session_ids=session_ids,
track_ids=track_ids,
paper_ids=paper_ids,
bidder_ids=bidder_ids,
author_ids=author_ids,
topic_ids = topic_ids,
track_session_capacity=track_session_capacity,
paper_distribution=paper_distribution,
U=U,
M=M,
T=T,
Q=Q,
bidder_cost = bidder_cost,
topic_cost = topic_cost,
topic_utility = topic_utility,
QIP_parameters = QIP_parameters,
save_results=True,
savefolder='QIP_RESULTS')
QIP_instance.build()
# SOLVE QIP
QIP_instance.solve()
QIP_instance.summary()
# TRANSFORM QIP_instance.schedule to nice format and create output folder
QIP_instance.create_schedule(filename = 'schedule',
paper_author_dict = paper_author_dict,
paper_title_dict = paper_title_dict,
paper_topic_dict = paper_topic_dict,
)
Once you set all input parameters and prepared the input data you can create a conference schedule by running
$ python create_schedule.py
Note that we already provide an output folder QIP_RESULTS_17_06_2022_15-47-37 that corresponds to our random data input.
Each output folder QIP_RESULTS_<day_month_year>_ (of a successful QIP run) contains the following files:
Filename | Explanation |
---|---|
qip_constraints_<day_month_year>_.txt | QIP constraints |
qip_objective_<day_month_year>_.txt | QIP objective |
qip_logs_<day_month_year>_.log | Log file when running create_schedule.py |
qip_solution_<day_month_year>_.json | CPLEX solution file |
qip_solve_details_<day_month_year>_.json | CPLEX solve details |
qip_schedule_<day_month_year>_.pkl | QIP final schedule saved as pickle file; An OrderedDict with key-value pairs as follows: (session_id,track_id): list of paper_id's which are allocated |
schedule_<day_month_year>_.xlsx | QIP final schedule nicely formatted as .xlsx file. |
The final schedule schedule_<day_month_year>_.xlsx contains for each session-track tuple
Union of topics of papers allocated to that subsession and *ATTENDANCE* measure calculated as |
||
ID: Title: Authors: |
||
... | ... | ... |
ID: Title: Authors: |
If you want to add specific "hard" paper constraints in your QIP formulation you can implement them via the method def _add_specific_paper_constraints(self) in the class-file qip.py as follows:
def _add_specific_paper_constraints(self):
# PAPER SPECIFIC CONSTRAINTS
for j,k in self.session_track_tuple_ids:
self.QIP.add_constraint(ct=(self.x[(14, j, k)]==self.x[(20, j, k)]),
ctname=f'SPECIAL_CT_PAPERIDs_14-20-21-29_SESSION{j}_TRACK{k}')
self.QIP.add_constraint(ct=(self.x[(20, j, k)]==self.x[(21, j, k)]),
ctname=f'SPECIAL_CT_PAPERIDs_14-20-21-29_SESSION{j}_TRACK{k}')
self.QIP.add_constraint(ct=(self.x[(21, j, k)]==self.x[(29, j, k)]),
ctname=f'SPECIAL_CT_PAPERIDs_14-20-21-29_SESSION{j}_TRACK{k}')
The example above ensures that paper ids 14, 20, 21, and 29 are all alllocated to the same subsession (i.e., session-track tuple). You can use such paper specific constraints for example to make sure that papers with similar topics are allocated to the same subsession (i.e., session-track tuple). Note that for the random data input we used the above defined paper specific constraints (see Session 1 Track 4 in schedule_17_06_2022_15-47-37.xlsx).
Maintained by: Jakob Weissteiner (weissteiner)
Website: www.jakobweissteiner.com
E-mail: [email protected]