Skip to content

Commit

Permalink
2.5.92
Browse files Browse the repository at this point in the history
  • Loading branch information
vlkong committed Mar 12, 2018
1 parent 535d213 commit 8cf1ca2
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 140 deletions.
82 changes: 8 additions & 74 deletions examples/mp/docplexcloud/diet_pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,6 @@
from docplex.mp.model import Model
from docplex.util.environment import get_environment

# We need a lock so that we can make write_all_outputs
# atomic. All output operation (update of the ``outputs`` dict or write) should
# lock this Lock to ensure that the output is not in an unfinished state when
# the job is aborted.
# We also need a stop callback that will lock until this Lock is released
# to make sure that any write operation finishes.
output_lock = threading.Lock()


def set_stop_callback(cb):
env = get_environment()
try:
env.set_stop_callback(cb)
except AttributeError:
# env.set_stop_callback does not exists -> older version of docplex
# use work around
try:
import docplex.worker.solvehook as worker_env
hook = worker_env.get_solve_hook()
if hook:
hook.set_stop_callback(cb)
finally:
# ignore errors
pass


def get_all_inputs():
'''Utility method to read a list of files and return a tuple with all
Expand All @@ -55,49 +30,14 @@ def get_all_inputs():
result = {}
env = get_environment()
for iname in [f for f in os.listdir('.') if splitext(f)[1] == '.csv']:
with env.get_input_stream(iname) as in_stream:
df = pandas.read_csv(in_stream)
datasetname, _ = splitext(iname)
result[datasetname] = df
df = env.read_df(iname, index_col=None)
datasetname, _ = splitext(iname)
result[datasetname] = df
return result

def callonce(f):
@wraps(f)
def wrapper(*args, **kwargs):
if not wrapper.called:
wrapper.called = True
return f(*args, **kwargs)
print('Function already called once.')
wrapper.called = False
return wrapper

@callonce
def write_all_outputs(outputs):
'''Write all dataframes in ``outputs`` as .csv.
Args:
outputs: The map of outputs 'outputname' -> 'output df'
'''
global output_lock
with output_lock:
for (name, df) in iteritems(outputs):
csv_file = '%s.csv' % name
with get_environment().get_output_stream(csv_file) as fp:
fp.write(df.to_csv(index=False))
if len(outputs) == 0:
print("Warning: no outputs written")





def wait_and_save_all_cb(outputs):
global output_lock
# just wait for the output_lock to be available
with output_lock:
pass
# write outputs
write_all_outputs(outputs)
get_environment().store_solution(outputs)


def mp_solution_to_df(solution):
Expand Down Expand Up @@ -157,7 +97,8 @@ def build_diet_model(inputs, **kwargs):
inputs = get_all_inputs()
outputs = {}

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

mdl = build_diet_model(inputs)

Expand All @@ -170,12 +111,5 @@ def build_diet_model(inputs, **kwargs):
mdl.report_kpis()
# Save the CPLEX solution as 'solution.csv' program output
solution_df = mp_solution_to_df(mdl.solution)

with output_lock:
# makes sure the solution is fully assigned before we quit
outputs['solution'] = solution_df

# This allows the solution to be saved if this script
# is not aborted. If the script is aborted, the `wait_and_save_all_cb`
# takes care of the writing
write_all_outputs(outputs)
outputs['solution'] = solution_df
get_environment().store_solution(outputs)
140 changes: 93 additions & 47 deletions examples/mp/jupyter/sktrans/transformers.ipynb

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions examples/mp/jupyter/tutorials/Beyond_Linear_Programming.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Rounding a fractional solution\n",
"### Rouding a fractional solution\n",
"\n",
"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",
"\n",
Expand Down Expand Up @@ -1146,7 +1146,7 @@
"\n",
"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",
"\n",
"### Uses of portfolio optimization\n",
"### Potfolio optimization: what use?\n",
"\n",
"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",
"\n",
Expand Down
32 changes: 17 additions & 15 deletions examples/mp/modeling/nurses.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,16 @@ def day_to_day_week(day):
("Emergency", "monday", 18, 2, 3, 7),
("Consultation", "monday", 8, 12, 10, 13),
("Consultation", "monday", 12, 18, 8, 12),
("Cardiac Care", "monday", 8, 12, 10, 13),
("Cardiac Care", "monday", 12, 18, 8, 12),
("Cardiac_Care", "monday", 8, 12, 10, 13),
("Cardiac_Care", "monday", 12, 18, 8, 12),
("Emergency", "tuesday", 8, 12, 4, 7),
("Emergency", "tuesday", 12, 18, 2, 5),
("Emergency", "tuesday", 18, 2, 3, 7),
("Consultation", "tuesday", 8, 12, 10, 13),
("Consultation", "tuesday", 12, 18, 8, 12),
("Cardiac Care", "tuesday", 8, 12, 4, 7),
("Cardiac Care", "tuesday", 12, 18, 2, 5),
("Cardiac Care", "tuesday", 18, 2, 3, 7),
("Cardiac_Care", "tuesday", 8, 12, 4, 7),
("Cardiac_Care", "tuesday", 12, 18, 2, 5),
("Cardiac_Care", "tuesday", 18, 2, 3, 7),
("Emergency", "wednesday", 2, 8, 3, 5),
("Emergency", "wednesday", 8, 12, 4, 7),
("Emergency", "wednesday", 12, 18, 2, 5),
Expand Down Expand Up @@ -105,18 +105,18 @@ def day_to_day_week(day):
("Geriatrics", "sunday", 8, 10, 2, 5)]

NURSE_SKILLS = {"Anne": ["Anaesthesiology", "Oncology", "Pediatrics"],
"Betsy": ["Cardiac Care"],
"Betsy": ["Cardiac_Care"],
"Cathy": ["Anaesthesiology"],
"Cecilia": ["Anaesthesiology", "Oncology", "Pediatrics"],
"Chris": ["Cardiac Care", "Oncology", "Geriatrics"],
"Gloria": ["Pediatrics"], "Jemma": ["Cardiac Care"],
"Chris": ["Cardiac_Care", "Oncology", "Geriatrics"],
"Gloria": ["Pediatrics"], "Jemma": ["Cardiac_Care"],
"Joyce": ["Anaesthesiology", "Pediatrics"],
"Julie": ["Geriatrics"], "Juliet": ["Pediatrics"],
"Kate": ["Pediatrics"], "Nancy": ["Cardiac Care"],
"Kate": ["Pediatrics"], "Nancy": ["Cardiac_Care"],
"Nathalie": ["Anaesthesiology", "Geriatrics"],
"Patrick": ["Oncology"], "Suzanne": ["Pediatrics"],
"Wendie": ["Geriatrics"],
"Zoe": ["Cardiac Care"]
"Zoe": ["Cardiac_Care"]
}

VACATIONS = [("Anne", "friday"),
Expand Down Expand Up @@ -195,7 +195,7 @@ def day_to_day_week(day):
("Joan", "Anne")
]

SKILL_REQUIREMENTS = [("Emergency", "Cardiac Care", 1)]
SKILL_REQUIREMENTS = [("Emergency", "Cardiac_Care", 1)]

DEFAULT_WORK_RULES = TWorkRules(40)

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



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


print('#nurses: {0}'.format(len(model.nurses)))
print('#shifts: {0}'.format(len(model.shifts)))
print('#vacations: {0}'.format(len(model.vacations)))
Expand Down Expand Up @@ -370,7 +372,7 @@ def setup_constraints(model):
v += 1
model.add_constraint(nurse_assigned[vac_n, shift] == 0,
"medium_vacations_{0!s}_{1!s}_{2!s}".format(vac_n, vac_day, shift))
print('#vacation cts: {0}'.format(v))
#print('#vacation cts: {0}'.format(v))

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

for s in all_shifts:
demand_min = s.min_requirement
Expand Down Expand Up @@ -441,7 +443,7 @@ def setup_constraints(model):
def setup_objective(model):
model.add_kpi(model.total_salary_cost, "Total salary cost")
model.add_kpi(model.total_number_of_assignments, "Total number of assignments")
model.add_kpi(model.average_nurse_work_time)
model.add_kpi(model.average_nurse_work_time, "average work time")

total_over_average_worktime = model.sum(model.nurse_over_average_time_vars[n] for n in model.nurses)
total_under_average_worktime = model.sum(model.nurse_under_average_time_vars[n] for n in model.nurses)
Expand Down
6 changes: 4 additions & 2 deletions examples/mp/modeling/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ def build_production_problem(products, resources, consumptions, **kwargs):
"""
mdl = Model(name='production', **kwargs)
# --- decision variables ---
mdl.inside_vars = mdl.continuous_var_dict(products, name='inside')
mdl.outside_vars = mdl.continuous_var_dict(products, name='outside')
mdl.inside_vars = mdl.continuous_var_dict(products, name=lambda p: 'inside_%s' % p[0])
mdl.outside_vars = mdl.continuous_var_dict(products, name=lambda p: 'outside_%s' % p[0])

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

# --- objective ---
mdl.total_inside_cost = mdl.sum(mdl.inside_vars[p] * p[2] for p in products)
mdl.add_kpi(mdl.total_inside_cost, "inside cost")
mdl.total_outside_cost = mdl.sum(mdl.outside_vars[p] * p[3] for p in products)
mdl.add_kpi(mdl.total_outside_cost, "outside cost")
mdl.minimize(mdl.total_inside_cost + mdl.total_outside_cost)
return mdl

Expand Down

0 comments on commit 8cf1ca2

Please sign in to comment.