Skip to content

Commit 8cf1ca2

Browse files
committed
2.5.92
1 parent 535d213 commit 8cf1ca2

File tree

5 files changed

+124
-140
lines changed

5 files changed

+124
-140
lines changed

examples/mp/docplexcloud/diet_pandas.py

Lines changed: 8 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,6 @@
1919
from docplex.mp.model import Model
2020
from docplex.util.environment import get_environment
2121

22-
# We need a lock so that we can make write_all_outputs
23-
# atomic. All output operation (update of the ``outputs`` dict or write) should
24-
# lock this Lock to ensure that the output is not in an unfinished state when
25-
# the job is aborted.
26-
# We also need a stop callback that will lock until this Lock is released
27-
# to make sure that any write operation finishes.
28-
output_lock = threading.Lock()
29-
30-
31-
def set_stop_callback(cb):
32-
env = get_environment()
33-
try:
34-
env.set_stop_callback(cb)
35-
except AttributeError:
36-
# env.set_stop_callback does not exists -> older version of docplex
37-
# use work around
38-
try:
39-
import docplex.worker.solvehook as worker_env
40-
hook = worker_env.get_solve_hook()
41-
if hook:
42-
hook.set_stop_callback(cb)
43-
finally:
44-
# ignore errors
45-
pass
46-
4722

4823
def get_all_inputs():
4924
'''Utility method to read a list of files and return a tuple with all
@@ -55,49 +30,14 @@ def get_all_inputs():
5530
result = {}
5631
env = get_environment()
5732
for iname in [f for f in os.listdir('.') if splitext(f)[1] == '.csv']:
58-
with env.get_input_stream(iname) as in_stream:
59-
df = pandas.read_csv(in_stream)
60-
datasetname, _ = splitext(iname)
61-
result[datasetname] = df
33+
df = env.read_df(iname, index_col=None)
34+
datasetname, _ = splitext(iname)
35+
result[datasetname] = df
6236
return result
6337

64-
def callonce(f):
65-
@wraps(f)
66-
def wrapper(*args, **kwargs):
67-
if not wrapper.called:
68-
wrapper.called = True
69-
return f(*args, **kwargs)
70-
print('Function already called once.')
71-
wrapper.called = False
72-
return wrapper
73-
74-
@callonce
75-
def write_all_outputs(outputs):
76-
'''Write all dataframes in ``outputs`` as .csv.
77-
78-
Args:
79-
outputs: The map of outputs 'outputname' -> 'output df'
80-
'''
81-
global output_lock
82-
with output_lock:
83-
for (name, df) in iteritems(outputs):
84-
csv_file = '%s.csv' % name
85-
with get_environment().get_output_stream(csv_file) as fp:
86-
fp.write(df.to_csv(index=False))
87-
if len(outputs) == 0:
88-
print("Warning: no outputs written")
89-
90-
91-
92-
9338

9439
def wait_and_save_all_cb(outputs):
95-
global output_lock
96-
# just wait for the output_lock to be available
97-
with output_lock:
98-
pass
99-
# write outputs
100-
write_all_outputs(outputs)
40+
get_environment().store_solution(outputs)
10141

10242

10343
def mp_solution_to_df(solution):
@@ -157,7 +97,8 @@ def build_diet_model(inputs, **kwargs):
15797
inputs = get_all_inputs()
15898
outputs = {}
15999

160-
set_stop_callback(partial(wait_and_save_all_cb, outputs))
100+
# The abort callbacks are called when the docplexcloud job is aborted
101+
get_environment().abort_callbacks += [partial(wait_and_save_all_cb, outputs)]
161102

162103
mdl = build_diet_model(inputs)
163104

@@ -170,12 +111,5 @@ def build_diet_model(inputs, **kwargs):
170111
mdl.report_kpis()
171112
# Save the CPLEX solution as 'solution.csv' program output
172113
solution_df = mp_solution_to_df(mdl.solution)
173-
174-
with output_lock:
175-
# makes sure the solution is fully assigned before we quit
176-
outputs['solution'] = solution_df
177-
178-
# This allows the solution to be saved if this script
179-
# is not aborted. If the script is aborted, the `wait_and_save_all_cb`
180-
# takes care of the writing
181-
write_all_outputs(outputs)
114+
outputs['solution'] = solution_df
115+
get_environment().store_solution(outputs)

examples/mp/jupyter/sktrans/transformers.ipynb

Lines changed: 93 additions & 47 deletions
Large diffs are not rendered by default.

examples/mp/jupyter/tutorials/Beyond_Linear_Programming.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@
813813
"cell_type": "markdown",
814814
"metadata": {},
815815
"source": [
816-
"### Rounding a fractional solution\n",
816+
"### Rouding a fractional solution\n",
817817
"\n",
818818
"An idea that often comes up to deal with fractional solutions is to solve an LP and then round the fractional numbers in order to find an integer solution. However, because the optimal solution is always on the edge of the feasible region, rounding can lead to an infeasible solution, that is, a solution that lies outside the feasible region. In the case of the telephone problem, rounding would produce infeasible results for both types of phones. \n",
819819
"\n",
@@ -1146,7 +1146,7 @@
11461146
"\n",
11471147
"To optimize a portfolio in terms of risk and return, an investor will evaluate the sum of expected returns of the securities, the total variances of the securities, and the covariances of the securities. A portfolio that contains a large number of positively covariant securities is more risky (and potentially more rewarding) than one that contains a mix of positively and negatively covariant securities. \n",
11481148
"\n",
1149-
"### Uses of portfolio optimization\n",
1149+
"### Potfolio optimization: what use?\n",
11501150
"\n",
11511151
"Portfolio optimization is used to select securities to maximize the rate of return, while managing the volatility of the portfolio and remaining within the investment budget. \n",
11521152
"\n",

examples/mp/modeling/nurses.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,16 @@ def day_to_day_week(day):
6868
("Emergency", "monday", 18, 2, 3, 7),
6969
("Consultation", "monday", 8, 12, 10, 13),
7070
("Consultation", "monday", 12, 18, 8, 12),
71-
("Cardiac Care", "monday", 8, 12, 10, 13),
72-
("Cardiac Care", "monday", 12, 18, 8, 12),
71+
("Cardiac_Care", "monday", 8, 12, 10, 13),
72+
("Cardiac_Care", "monday", 12, 18, 8, 12),
7373
("Emergency", "tuesday", 8, 12, 4, 7),
7474
("Emergency", "tuesday", 12, 18, 2, 5),
7575
("Emergency", "tuesday", 18, 2, 3, 7),
7676
("Consultation", "tuesday", 8, 12, 10, 13),
7777
("Consultation", "tuesday", 12, 18, 8, 12),
78-
("Cardiac Care", "tuesday", 8, 12, 4, 7),
79-
("Cardiac Care", "tuesday", 12, 18, 2, 5),
80-
("Cardiac Care", "tuesday", 18, 2, 3, 7),
78+
("Cardiac_Care", "tuesday", 8, 12, 4, 7),
79+
("Cardiac_Care", "tuesday", 12, 18, 2, 5),
80+
("Cardiac_Care", "tuesday", 18, 2, 3, 7),
8181
("Emergency", "wednesday", 2, 8, 3, 5),
8282
("Emergency", "wednesday", 8, 12, 4, 7),
8383
("Emergency", "wednesday", 12, 18, 2, 5),
@@ -105,18 +105,18 @@ def day_to_day_week(day):
105105
("Geriatrics", "sunday", 8, 10, 2, 5)]
106106

107107
NURSE_SKILLS = {"Anne": ["Anaesthesiology", "Oncology", "Pediatrics"],
108-
"Betsy": ["Cardiac Care"],
108+
"Betsy": ["Cardiac_Care"],
109109
"Cathy": ["Anaesthesiology"],
110110
"Cecilia": ["Anaesthesiology", "Oncology", "Pediatrics"],
111-
"Chris": ["Cardiac Care", "Oncology", "Geriatrics"],
112-
"Gloria": ["Pediatrics"], "Jemma": ["Cardiac Care"],
111+
"Chris": ["Cardiac_Care", "Oncology", "Geriatrics"],
112+
"Gloria": ["Pediatrics"], "Jemma": ["Cardiac_Care"],
113113
"Joyce": ["Anaesthesiology", "Pediatrics"],
114114
"Julie": ["Geriatrics"], "Juliet": ["Pediatrics"],
115-
"Kate": ["Pediatrics"], "Nancy": ["Cardiac Care"],
115+
"Kate": ["Pediatrics"], "Nancy": ["Cardiac_Care"],
116116
"Nathalie": ["Anaesthesiology", "Geriatrics"],
117117
"Patrick": ["Oncology"], "Suzanne": ["Pediatrics"],
118118
"Wendie": ["Geriatrics"],
119-
"Zoe": ["Cardiac Care"]
119+
"Zoe": ["Cardiac_Care"]
120120
}
121121

122122
VACATIONS = [("Anne", "friday"),
@@ -195,7 +195,7 @@ def day_to_day_week(day):
195195
("Joan", "Anne")
196196
]
197197

198-
SKILL_REQUIREMENTS = [("Emergency", "Cardiac Care", 1)]
198+
SKILL_REQUIREMENTS = [("Emergency", "Cardiac_Care", 1)]
199199

200200
DEFAULT_WORK_RULES = TWorkRules(40)
201201

@@ -218,7 +218,8 @@ def __str__(self):
218218
dept2 = self.department[0:4].upper()
219219
# keep 3 days of weekday
220220
dayname = self.day[0:3]
221-
return '{}_{}_{:02d}'.format(dept2, dayname, self.start_time)
221+
return '{}_{}_{:02d}'.format(dept2, dayname, self.start_time).replace(" ", "_")
222+
222223

223224

224225
class ShiftActivity(object):
@@ -296,6 +297,7 @@ def load_data(model, shifts_, nurses_, nurse_skills, vacations_=None,
296297
# computed
297298
model.departments = set(sh.department for sh in model.shifts)
298299

300+
299301
print('#nurses: {0}'.format(len(model.nurses)))
300302
print('#shifts: {0}'.format(len(model.shifts)))
301303
print('#vacations: {0}'.format(len(model.vacations)))
@@ -370,7 +372,7 @@ def setup_constraints(model):
370372
v += 1
371373
model.add_constraint(nurse_assigned[vac_n, shift] == 0,
372374
"medium_vacations_{0!s}_{1!s}_{2!s}".format(vac_n, vac_day, shift))
373-
print('#vacation cts: {0}'.format(v))
375+
#print('#vacation cts: {0}'.format(v))
374376

375377
# a nurse cannot be assigned overlapping shifts
376378
# post only one constraint per couple(s1, s2)
@@ -385,7 +387,7 @@ def setup_constraints(model):
385387
for n in all_nurses:
386388
model.add_constraint(nurse_assigned[n, s1] + nurse_assigned[n, s2] <= 1,
387389
"high_overlapping_{0!s}_{1!s}_{2!s}".format(s1, s2, n))
388-
print('# overlapping cts: {0}'.format(number_of_overlaps))
390+
#print('# overlapping cts: {0}'.format(number_of_overlaps))
389391

390392
for s in all_shifts:
391393
demand_min = s.min_requirement
@@ -441,7 +443,7 @@ def setup_constraints(model):
441443
def setup_objective(model):
442444
model.add_kpi(model.total_salary_cost, "Total salary cost")
443445
model.add_kpi(model.total_number_of_assignments, "Total number of assignments")
444-
model.add_kpi(model.average_nurse_work_time)
446+
model.add_kpi(model.average_nurse_work_time, "average work time")
445447

446448
total_over_average_worktime = model.sum(model.nurse_over_average_time_vars[n] for n in model.nurses)
447449
total_under_average_worktime = model.sum(model.nurse_under_average_time_vars[n] for n in model.nurses)

examples/mp/modeling/production.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ def build_production_problem(products, resources, consumptions, **kwargs):
4747
"""
4848
mdl = Model(name='production', **kwargs)
4949
# --- decision variables ---
50-
mdl.inside_vars = mdl.continuous_var_dict(products, name='inside')
51-
mdl.outside_vars = mdl.continuous_var_dict(products, name='outside')
50+
mdl.inside_vars = mdl.continuous_var_dict(products, name=lambda p: 'inside_%s' % p[0])
51+
mdl.outside_vars = mdl.continuous_var_dict(products, name=lambda p: 'outside_%s' % p[0])
5252

5353
# --- constraints ---
5454
# demand satisfaction
@@ -60,7 +60,9 @@ def build_production_problem(products, resources, consumptions, **kwargs):
6060

6161
# --- objective ---
6262
mdl.total_inside_cost = mdl.sum(mdl.inside_vars[p] * p[2] for p in products)
63+
mdl.add_kpi(mdl.total_inside_cost, "inside cost")
6364
mdl.total_outside_cost = mdl.sum(mdl.outside_vars[p] * p[3] for p in products)
65+
mdl.add_kpi(mdl.total_outside_cost, "outside cost")
6466
mdl.minimize(mdl.total_inside_cost + mdl.total_outside_cost)
6567
return mdl
6668

0 commit comments

Comments
 (0)