import docplex.mp.model as cpx
from itertools import product
from collections import defaultdict
def create_model(papers, authors):
"""
Create the cplex model for a given optimization problem.
Parameters
----------
papers : dict
a dictionary with one entry for each paper.
The keys are the paper handles and the values are the scores of the paper, one for each author.
Format example: { '11390/1234567': {'1234': 1.0, '1235': 0.7}, ... }
authors : dict
a dictionary with one entry for each author.
The author id is the key, while his/her status according to
the different optimization criteria are the values (TODO: still to be considered)
Format example: { '1234': { 'young': True }, '1235': {'young': False } }
"""
with cpx.Model(name='VQR Optimization') as model:
x = defaultdict(lambda: dict()) # x variables are the decision variables from the viewpoint of papers (i.e., they are indexed [paper, author])
y = defaultdict(lambda: dict()) # y variables are the decision variables from the viewpoint of authors (i.e., they are indexed [author, paper])
c = defaultdict(lambda: defaultdict(lambda: 0.0)) # c are the coefficients of the paper, indexed as [paper, author]
d = defaultdict(lambda: defaultdict(lambda: 0.0)) # d are the coefficients of the author, indexed as [author, paper]
overall_sum_variables = []
overall_sum_coefficients = []
young_sum_variables = []
young_sum_coefficients = []
for paper, paper_authors in papers.items():
for author, score in paper_authors.items():
# score = score * 10
variable = model.binary_var(f'select[{paper}, {author}]')
x[paper][author] = variable
y[author][paper] = variable
c[paper][author] = score
d[author][paper] = score
overall_sum_variables.append(variable)
overall_sum_coefficients.append(score)
if authors[author].get('young', False):
young_sum_variables.append(variable)
young_sum_coefficients.append(score)
# each paper selected only once FIXME: just for testing
model.add_constraint(sum(x[paper].values()) <= 1)
# each author just one paper FIXME: just for testing
for author, variables in y.items():
model.add_constraint(sum(variables.values()) == 1)
overall = model.dot(overall_sum_variables, overall_sum_coefficients)
young = model.dot(young_sum_variables, young_sum_coefficients)
# optimization criterion
model.set_multi_objective('max', [overall, young], priorities=[2, 1], reltols=[0.1, 0.1], names=['overall', 'young'])
sol = model.solve(log_output=True)
if sol is None:
print('model is infeasible')
else:
print(sol)
print(sol.solve_status)
print(sol.get_value(overall), sol.get_value(young))
print(sol.get_objective_value())
print(model._objective_expr.is_discrete())
if __name__ == '__main__':
test_papers = { '11390/1234567': {'1234': 0.7, '1235': 0.7}, '11390/1234568': {'1234': 0.8, '1236': 0.9}, '11390/1234569': {'1235': 0.7, '1236': 0.7},}
test_authors = { '1234': { 'young': True }, '1235': {}, '1236': { 'young': False } }
create_model(test_papers, test_authors)