Skip to content

Commit

Permalink
1.0.572
Browse files Browse the repository at this point in the history
  • Loading branch information
vlkong committed Jun 30, 2016
1 parent 526afc0 commit 15fc50f
Show file tree
Hide file tree
Showing 15 changed files with 630 additions and 71 deletions.
287 changes: 287 additions & 0 deletions examples/cp/basic/data/plant_location.data

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions examples/cp/basic/golomb_ruler_all_solutions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# --------------------------------------------------------------------------
# Source file provided under Apache License, Version 2.0, January 2004,
# http://www.apache.org/licenses/
# (c) Copyright IBM Corp. 2015, 2016
# --------------------------------------------------------------------------

"""
In mathematics, a Golomb ruler is a set of marks at integer positions along
an imaginary ruler such that no two pairs of marks are the same distance apart.
The number of marks on the ruler is its order, and the largest distance
between two of its marks is its length.
This implementation differs from the 'basic' implementation, given in the
examp;e module golomb_ruler.py, because it calls the solver twice:
* First time to know the minimal size of the ruler for the required order,
* A second time to list all possible rulers for this optimal size
See https://en.wikipedia.org/wiki/Golomb_ruler for more information.
For order 5: 2 solutions: 0 1 4 9 11
0 2 7 8 11
For order 7: 6 solutions: 0 1 4 10 18 23 25
0 1 7 11 20 23 25
0 1 11 16 19 23 25
0 2 3 10 16 21 25
0 2 7 13 21 22 25
Please refer to documentation for appropriate setup of solving configuration.
"""


from docplex.cp.model import *
from sys import stdout

# Set model parameters
ORDER = 7 # Number of marks
MAX_LENGTH = (ORDER - 1) ** 2 # Max rule length

# Create model
mdl = CpoModel()

# Create array of variables corresponding to position rule marks
marks = integer_var_list(ORDER, 0, MAX_LENGTH, "M")

# Create marks distances that should be all different
dist = [marks[i] - marks[j] for i in range(1, ORDER) for j in range(0, i)]
mdl.add(all_diff(dist))

# Avoid symmetric solutions by ordering marks
mdl.add(marks[0] == 0)
for i in range(1, ORDER):
mdl.add(marks[i] > marks[i - 1])

# Avoid mirror solution
mdl.add((marks[1] - marks[0]) < (marks[ORDER - 1] - marks[ORDER - 2]))

# Minimize ruler size (position of the last mark)
minexpr = minimize(marks[ORDER - 1])
mdl.add(minexpr)

# First solve the model to find the smallest ruler length
msol = mdl.solve()
if not msol:
print("No Golomb ruler available for order " + str(ORDER))
else:
rsize = msol[marks[ORDER - 1]]
print("Shortest ruler for order " + str(ORDER) + " has length " + str(rsize))
# Remove minimization from the model
mdl.remove(minexpr)
# Force position of last mark
mdl.add(marks[ORDER - 1] == rsize)

# Request all solutions
print("List of all possible rulers for length {}:".format(rsize))
solver = CpoSolver(mdl, SearchType='DepthFirst', Workers=1) # Parameters needed to avoid duplicate solutions
try:
for i, msol in enumerate(solver):
stdout.write(str(i + 1) + ": ")
for v in marks:
stdout.write(" " + str(msol[v]))
stdout.write("\n")
except CpoNotSupportedException:
print("This instance of the solver does not support solution iteration.")
117 changes: 117 additions & 0 deletions examples/cp/basic/plant_location_with_starting_point.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# --------------------------------------------------------------------------
# Source file provided under Apache License, Version 2.0, January 2004,
# http://www.apache.org/licenses/
# (c) Copyright IBM Corp. 2015, 2016
# --------------------------------------------------------------------------

"""
A ship-building company has a certain number of customers. Each customer is supplied
by exactly one plant. In turn, a plant can supply several customers. The problem is
to decide where to set up the plants in order to supply every customer while minimizing
the cost of building each plant and the transportation cost of supplying the customers.
For each possible plant location there is a fixed cost and a production capacity.
Both take into account the country and the geographical conditions.
For every customer, there is a demand and a transportation cost with respect to
each plant location.
While a first solution of this problem can be found easily by CP Optimizer, it can take
quite some time to improve it to a very good one. We illustrate the warm start capabilities
of CP Optimizer by giving a good starting point solution that CP Optimizer will try to improve.
This solution could be one from an expert or the result of another optimization engine
applied to the problem.
In the solution we only give a value to the variables that determine which plant delivers
a customer. This is sufficient to define a complete solution on all model variables.
CP Optimizer first extends the solution to all variables and then starts to improve it.
Please refer to documentation for appropriate setup of solving configuration.
"""

from docplex.cp.model import *
from collections import deque

##############################################################################
# Initialize model data
##############################################################################

# Read data from file
filename = os.path.dirname(os.path.abspath(__file__)) + "/data/plant_location.data"
data = deque()
with open(filename, "r") as file:
for val in file.read().split():
data.append(int(val))

# Initialize main dimensions
nbCustomer = data.popleft()
nbLocation = data.popleft()

# Initialize cost. cost[c][p] = cost to deliver customer c from plant p
cost = list([list([data.popleft() for l in range(nbLocation)]) for c in range(nbCustomer)])

# Initialize demand of each customer
demand = list([data.popleft() for c in range(nbCustomer)])

# Initialize fixed cost of each location
fixedCost = list([data.popleft() for p in range(nbLocation)])

# Initialize capacity of each location
capacity = list([data.popleft() for p in range(nbLocation)])


##############################################################################
# Create the model
##############################################################################

mdl = CpoModel()

# Create variables identifying which location serves each customer
cust = integer_var_list(nbCustomer, 0, nbLocation - 1, "CustomerLocation")

# Create variables indicating which plant location is open
open = integer_var_list(nbLocation, 0, 1, "OpenLocation")

# Create variables indicating load of each plant
load = [integer_var(0, capacity[p], "PlantLoad_" + str(p)) for p in range(nbLocation)]

# Associate plant openness to its load
for p in range(nbLocation):
mdl.add(open[p] == (load[p] > 0))

# Add constraints
mdl.add(pack(load, cust, demand))

# Add objective
obj = scal_prod(fixedCost, open)
for c in range(nbCustomer):
obj += element(cust[c], cost[c])
mdl.add(minimize(obj))


##############################################################################
# Solve the model
##############################################################################

# Solve without starting point
print("Solve the model with no starting point")
msol = mdl.solve(TimeLimit=10)
print(" Objective value: " + str(msol.get_objective_values()[0]))

# Solve with starting point
print("Solve the model with starting point")
custValues = [19, 0, 11, 8, 29, 9, 29, 28, 17, 15, 7, 9, 18, 15, 1, 17, 25, 18, 17, 27,
22, 1, 26, 3, 22, 2, 20, 27, 2, 16, 1, 16, 12, 28, 19, 2, 20, 14, 13, 27,
3, 9, 18, 0, 13, 19, 27, 14, 12, 1, 15, 14, 17, 0, 7, 12, 11, 0, 25, 16,
22, 13, 16, 8, 18, 27, 19, 23, 26, 13, 11, 11, 19, 22, 28, 26, 23, 3, 18, 23,
26, 14, 29, 18, 9, 7, 12, 27, 8, 20]
sp = CpoModelSolution()
for c in range(nbCustomer):
sp.add_integer_var_solution(cust[c], custValues[c])
mdl.set_starting_point(sp)

try:
msol = mdl.solve(TimeLimit=10)
print(" Objective value: " + str(msol.get_objective_values()[0]))
except:
print(" Starting point is available only with CPO 13 and later.")
3 changes: 2 additions & 1 deletion examples/cp/jupyter/_utils_visu.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
LIBRARIES_PRESENT = False

from docplex.cp.function import CpoFunction
from docplex.cp.expression import CpoTransitionMatrix
from docplex.cp.solution import *
import docplex.cp.config as config

Expand Down Expand Up @@ -1588,7 +1589,7 @@ def show(object=None, name=None, origin=None, horizon=None):
"""
if config.context.visu_enabled:
if object is not None:
if isinstance(object, CpoModelSolution):
if isinstance(object, CpoSolveResult):
# use default display for an instance of CPOSolution
_define_solution(object, name)
elif isinstance(object, CpoTransitionMatrix):
Expand Down
11 changes: 6 additions & 5 deletions examples/cp/visu/_utils_visu.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
LIBRARIES_PRESENT = False

from docplex.cp.function import CpoFunction
from docplex.cp.expression import CpoTransitionMatrix
from docplex.cp.solution import *
import docplex.cp.config as config

Expand Down Expand Up @@ -970,11 +971,11 @@ def show(self):

_visu = _Visu()

"""
This section depends on CPO classes and defines the default display of some classes
like CpoSolution and CpoTransitionMatrix
"""

##############################################################################
# This section depends on CPO classes and defines the default display of some
# classes like CpoSolution and CpoTransitionMatrix
##############################################################################

def _canonical_interval(*args):
"""
Expand Down Expand Up @@ -1588,7 +1589,7 @@ def show(object=None, name=None, origin=None, horizon=None):
"""
if config.context.visu_enabled:
if object is not None:
if isinstance(object, CpoModelSolution):
if isinstance(object, CpoSolveResult):
# use default display for an instance of CPOSolution
_define_solution(object, name)
elif isinstance(object, CpoTransitionMatrix):
Expand Down
8 changes: 4 additions & 4 deletions examples/cp/visu/sched_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
place before others and these requirements are expressed through
precedence constraints.
There are two workers and each task requires a specific worker. The
worker has a calendar of days off that must be taken into account. The
objective is to minimize the overall completion date.
There are two workers and each task requires a specific worker.
The worker has a calendar of days off that must be taken into account.
The objective is to minimize the overall completion date.
Please refer to documentation for appropriate setup of solving configuration.
"""
Expand Down Expand Up @@ -154,7 +154,7 @@ def make_house(loc):
##############################################################################

# Trace model
# mdl.export_as_cpo()
# mdl.export_as_cpo()

# Solve model
print("Solving model....")
Expand Down
10 changes: 5 additions & 5 deletions examples/mp/jupyter/mining_pandas.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,17 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
"collapsed": false
},
"outputs": [],
"source": [
"import pip\n",
"REQUIRED_MINIMUM_PANDAS_VERSION = '0.17.1'\n",
"d = {pkg.key : pkg.version for pkg in pip.get_installed_distributions()}\n",
"try:\n",
" assert d['pandas'] >= REQUIRED_MINIMUM_PANDAS_VERSION\n",
" import pandas as pd\n",
" assert pd.__version__ >= REQUIRED_MINIMUM_PANDAS_VERSION\n",
"except:\n",
" raise Exception(\"Version \" + REQUIRED_MINIMUM_PANDAS_VERSION + \" or above of Pandas is required to run this notebook\")"
" raise Exception(\"Version %s or above of Pandas is required to run this notebook\" % REQUIRED_MINIMUM_PANDAS_VERSION)"
]
},
{
Expand Down Expand Up @@ -942,7 +942,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.10"
"version": "2.7.11"
}
},
"nbformat": 4,
Expand Down
8 changes: 4 additions & 4 deletions examples/mp/jupyter/nurses_pandas.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@
"source": [
"import pip\n",
"REQUIRED_MINIMUM_PANDAS_VERSION = '0.17.1'\n",
"d = {pkg.key : pkg.version for pkg in pip.get_installed_distributions()}\n",
"try:\n",
" assert d['pandas'] >= REQUIRED_MINIMUM_PANDAS_VERSION\n",
" import pandas as pd\n",
" assert pd.__version__ >= REQUIRED_MINIMUM_PANDAS_VERSION\n",
"except:\n",
" raise Exception(\"Version \" + REQUIRED_MINIMUM_PANDAS_VERSION + \" or above of Pandas is required to run this notebook\")"
" raise Exception(\"Version %s or above of Pandas is required to run this notebook\" % REQUIRED_MINIMUM_PANDAS_VERSION)"
]
},
{
Expand Down Expand Up @@ -1353,7 +1353,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.10"
"version": "2.7.11"
}
},
"nbformat": 4,
Expand Down
9 changes: 7 additions & 2 deletions examples/mp/modeling/diet.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from collections import namedtuple

from docplex.mp.model import Model
from docplex.util.environment import get_environment

FOODS = [
("Roasted Chicken", 0.84, 0, 10),
Expand Down Expand Up @@ -47,7 +48,7 @@
]


def build_diet_model(context=None):
def build_diet_model(**kwargs):
# Create tuples with named fields for foods and nutrients
Food = namedtuple("Food", ["name", "unit_cost", "qmin", "qmax"])
food = [Food(*f) for f in FOODS]
Expand All @@ -59,7 +60,7 @@ def build_diet_model(context=None):
fn[1 + n] for fn in FOOD_NUTRIENTS for n in range(len(NUTRIENTS))}

# Model
mdl = Model("diet", context=context)
mdl = Model("diet", **kwargs)

# Decision variables, limited to be >= Food.qmin and <= Food.qmax
qty = dict((f, mdl.continuous_var(f.qmin, f.qmax, f.name)) for f in food)
Expand Down Expand Up @@ -107,3 +108,7 @@ def build_diet_model(context=None):
print("* model solved as function:")
mdl.print_solution()
mdl.report_kpis()
# Save the CPLEX solution as "solution.json" program output
with get_environment().get_output_stream("solution.json") as fp:
mdl.solution.export(fp, "json")

12 changes: 9 additions & 3 deletions examples/mp/modeling/nurses.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from collections import namedtuple

from docplex.mp.model import Model
from docplex.util.environment import get_environment



# utility to convert a weekday string to an index in 0..6
Expand Down Expand Up @@ -243,13 +245,13 @@ def setup_constraints(model):
ctname = 'medium_ct_nurse_incompat_{0!s}_{1!s}_{2:d}'.format(nurse_id1, nurse_id2, c)
model.add_constraint(nurse_assigned[nurse1, s] + nurse_assigned[nurse2, s] <= 1, ctname)

model.total_number_of_assignments = model.sum(nurse_assigned[n,s] for n in all_nurses for s in all_shifts)
#model.total_salary_cost = model.sum(nurse_work_time[n] * n.pay_rate for n in all_nurses)
model.total_number_of_assignments = model.sum(nurse_assigned[n, s] for n in all_nurses for s in all_shifts)
model.nurse_costs = [model.nurse_assignment_vars[n, s] * n.pay_rate * model.shift_activities[s].duration for n in
model.nurses
for s in model.shifts]
model.total_salary_cost = model.sum(model.nurse_costs)


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")
Expand Down Expand Up @@ -518,4 +520,8 @@ def build(context=None, **kwargs):

# Solve the model. If a key has been specified above, the solve
# will use IBM Decision Optimization on cloud.
status = solve(model, url=url, key=key)
solve(model, url=url, key=key)

# Save the CPLEX solution as "solution.json" program output
with get_environment().get_output_stream("solution.json") as fp:
model.solution.export(fp, "json")
Loading

0 comments on commit 15fc50f

Please sign in to comment.