Added organize_day.py marathon2.py olympic.py lectures.py p_median.py mr_smith.py
This commit is contained in:
133
python/lectures.py
Normal file
133
python/lectures.py
Normal file
@@ -0,0 +1,133 @@
|
||||
# Copyright 2010 Hakan Kjellerstrand hakank@bonetmail.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
|
||||
Lectures problem in Google CP Solver.
|
||||
|
||||
Biggs: Discrete Mathematics (2nd ed), page 187.
|
||||
'''
|
||||
Suppose we wish to schedule six one-hour lectures, v1, v2, v3, v4, v5, v6.
|
||||
Among the the potential audience there are people who wish to hear both
|
||||
|
||||
- v1 and v2
|
||||
- v1 and v4
|
||||
- v3 and v5
|
||||
- v2 and v6
|
||||
- v4 and v5
|
||||
- v5 and v6
|
||||
- v1 and v6
|
||||
|
||||
How many hours are necessary in order that the lectures can be given
|
||||
without clashes?
|
||||
'''
|
||||
|
||||
Compare with the following models:
|
||||
* MiniZinc: http://www.hakank.org/minizinc/lectures.mzn
|
||||
* SICstus: http://hakank.org/sicstus/lectures.pl
|
||||
* ECLiPSe: http://hakank.org/eclipse/lectures.ecl
|
||||
* Gecode: http://hakank.org/gecode/lectures.cpp
|
||||
|
||||
|
||||
This model was created by Hakan Kjellerstrand (hakank@bonetmail.com)
|
||||
Also see my other Google CP Solver models: http://www.hakank.org/google_or_tools/
|
||||
"""
|
||||
|
||||
import sys
|
||||
from constraint_solver import pywrapcp
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# Create the solver.
|
||||
solver = pywrapcp.Solver('Lectures')
|
||||
|
||||
#
|
||||
# data
|
||||
#
|
||||
|
||||
#
|
||||
# The schedule requirements:
|
||||
# lecture a cannot be held at the same time as b
|
||||
# Note: 1-based
|
||||
g = [
|
||||
[1, 2],
|
||||
[1, 4],
|
||||
[3, 5],
|
||||
[2, 6],
|
||||
[4, 5],
|
||||
[5, 6],
|
||||
[1, 6]
|
||||
]
|
||||
|
||||
# number of nodes
|
||||
n = 6
|
||||
|
||||
# number of edges
|
||||
edges = len(g)
|
||||
|
||||
#
|
||||
# declare variables
|
||||
#
|
||||
v = [solver.IntVar(0, n-1, 'v[%i]' % i) for i in range(n)]
|
||||
|
||||
# maximum color, to minimize
|
||||
# Note: since Python is 0-based, the
|
||||
# number of colors is +1
|
||||
max_c = solver.IntVar(0, n-1, 'max_c')
|
||||
|
||||
|
||||
#
|
||||
# constraints
|
||||
#
|
||||
solver.Add(max_c == solver.Max(v))
|
||||
|
||||
# ensure that there are no clashes
|
||||
# also, adjust to 0-base
|
||||
for i in range(edges):
|
||||
solver.Add(v[g[i][0]-1] != v[g[i][1]-1])
|
||||
|
||||
# symmetry breaking:
|
||||
# - v0 has the color 0,
|
||||
# - v1 has either color 0 or 1
|
||||
solver.Add(v[0] == 0)
|
||||
solver.Add(v[1] <= 1)
|
||||
|
||||
# objective
|
||||
objective = solver.Minimize(max_c, 1)
|
||||
|
||||
#
|
||||
# solution and search
|
||||
#
|
||||
db = solver.Phase(v,
|
||||
solver.CHOOSE_MIN_SIZE_LOWEST_MIN,
|
||||
solver.ASSIGN_CENTER_VALUE)
|
||||
|
||||
solver.NewSearch(db, [objective])
|
||||
|
||||
num_solutions = 0
|
||||
while solver.NextSolution():
|
||||
num_solutions += 1
|
||||
print 'max_c:', max_c.Value()+1, 'colors'
|
||||
print 'v:', [v[i].Value() for i in range(n)]
|
||||
print
|
||||
|
||||
print 'num_solutions:', num_solutions
|
||||
print 'failures:', solver.failures()
|
||||
print 'branches:', solver.branches()
|
||||
print 'wall_time:', solver.wall_time(), 'ms'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
138
python/marathon2.py
Normal file
138
python/marathon2.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# Copyright 2010 Hakan Kjellerstrand hakank@bonetmail.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
|
||||
Marathon puzzle in Google CP Solver.
|
||||
|
||||
From Xpress example
|
||||
http://www.dashoptimization.com/home/cgi-bin/example.pl?id=mosel_puzzle_5_3
|
||||
'''
|
||||
Dominique, Ignace, Naren, Olivier, Philippe, and Pascal
|
||||
have arrived as the first six at the Paris marathon.
|
||||
Reconstruct their arrival order from the following
|
||||
information:
|
||||
a) Olivier has not arrived last
|
||||
b) Dominique, Pascal and Ignace have arrived before Naren
|
||||
and Olivier
|
||||
c) Dominique who was third last year has improved this year.
|
||||
d) Philippe is among the first four.
|
||||
e) Ignace has arrived neither in second nor third position.
|
||||
f) Pascal has beaten Naren by three positions.
|
||||
g) Neither Ignace nor Dominique are on the fourth position.
|
||||
|
||||
(c) 2002 Dash Associates
|
||||
author: S. Heipcke, Mar. 2002
|
||||
'''
|
||||
|
||||
Compare with the following models:
|
||||
* MiniZinc: http://www.hakank.org/minizinc/marathon2.mzn
|
||||
* SICStus Prolog: http://www.hakank.org/sicstus/marathon2.pl
|
||||
* ECLiPSe: http://hakank.org/eclipse/marathon2.ecl
|
||||
* Gecode: http://hakank.org/gecode/marathon2.cpp
|
||||
|
||||
|
||||
This model was created by Hakan Kjellerstrand (hakank@bonetmail.com)
|
||||
Also see my other Google CP Solver models: http://www.hakank.org/google_or_tools/
|
||||
"""
|
||||
|
||||
import sys
|
||||
from constraint_solver import pywrapcp
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# Create the solver.
|
||||
solver = pywrapcp.Solver('Marathon')
|
||||
|
||||
#
|
||||
# data
|
||||
#
|
||||
n = 6
|
||||
|
||||
runners_str = ['Dominique', 'Ignace', 'Naren',
|
||||
'Olivier', 'Philippe', 'Pascal']
|
||||
|
||||
#
|
||||
# declare variables
|
||||
#
|
||||
runners = [solver.IntVar(1, n, 'runners[%i]' % i) for i in range(n)]
|
||||
Dominique, Ignace, Naren, Olivier, Philippe, Pascal = runners
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# constraints
|
||||
#
|
||||
solver.Add(solver.AllDifferent(runners, True))
|
||||
|
||||
# a: Olivier not last
|
||||
solver.Add(Olivier != n)
|
||||
|
||||
# b: Dominique, Pascal and Ignace before Naren and Olivier
|
||||
solver.Add(Dominique < Naren)
|
||||
solver.Add(Dominique < Olivier)
|
||||
solver.Add(Pascal < Naren)
|
||||
solver.Add(Pascal < Olivier)
|
||||
solver.Add(Ignace < Naren)
|
||||
solver.Add(Ignace < Olivier)
|
||||
|
||||
# c: Dominique better than third
|
||||
solver.Add(Dominique < 3)
|
||||
|
||||
# d: Philippe is among the first four
|
||||
solver.Add(Philippe <= 4)
|
||||
|
||||
# e: Ignace neither second nor third
|
||||
solver.Add(Ignace != 2)
|
||||
solver.Add(Ignace != 3)
|
||||
|
||||
# f: Pascal three places earlier than Naren
|
||||
solver.Add(Pascal + 3 == Naren)
|
||||
|
||||
# g: Neither Ignace nor Dominique on fourth position
|
||||
solver.Add(Ignace != 4)
|
||||
solver.Add(Dominique != 4)
|
||||
|
||||
|
||||
#
|
||||
# solution and search
|
||||
#
|
||||
db = solver.Phase(runners,
|
||||
solver.CHOOSE_MIN_SIZE_LOWEST_MIN,
|
||||
solver.ASSIGN_CENTER_VALUE)
|
||||
|
||||
solver.NewSearch(db)
|
||||
|
||||
num_solutions = 0
|
||||
while solver.NextSolution():
|
||||
num_solutions += 1
|
||||
runners_val = [runners[i].Value() for i in range(n)]
|
||||
print 'runners:', runners_val
|
||||
print "Places:"
|
||||
for i in range(1, n+1):
|
||||
for j in range(n):
|
||||
if runners_val[j] == i:
|
||||
print "%i: %s" % (i, runners_str[j])
|
||||
print
|
||||
|
||||
print 'num_solutions:', num_solutions
|
||||
print 'failures:', solver.failures()
|
||||
print 'branches:', solver.branches()
|
||||
print 'wall_time:', solver.wall_time(), 'ms'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
125
python/mr_smith.py
Normal file
125
python/mr_smith.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# Copyright 2010 Hakan Kjellerstrand hakank@bonetmail.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
|
||||
Mr Smith in Google CP Solver.
|
||||
|
||||
From an IF Prolog example (http://www.ifcomputer.de/)
|
||||
'''
|
||||
The Smith family and their three children want to pay a visit but they
|
||||
do not all have the time to do so. Following are few hints who will go
|
||||
and who will not:
|
||||
o If Mr Smith comes, his wife will come too.
|
||||
o At least one of their two sons Matt and John will come.
|
||||
o Either Mrs Smith or Tim will come, but not both.
|
||||
o Either Tim and John will come, or neither will come.
|
||||
o If Matt comes, then John and his father will
|
||||
also come.
|
||||
'''
|
||||
|
||||
The answer should be:
|
||||
Mr_Smith_comes = 0
|
||||
Mrs_Smith_comes = 0
|
||||
Matt_comes = 0
|
||||
John_comes = 1
|
||||
Tim_comes = 1
|
||||
|
||||
Compare with the following models:
|
||||
* ECLiPSe: http://www.hakank.org/eclipse/mr_smith.ecl
|
||||
* SICStus Prolog: http://www.hakank.org/sicstus/mr_smith.pl
|
||||
* Gecode: http://www.hakank.org/gecode/mr_smith.cpp
|
||||
* MiniZinc: http://www.hakank.org/minizinc/mr_smith.mzn
|
||||
|
||||
|
||||
This model was created by Hakan Kjellerstrand (hakank@bonetmail.com)
|
||||
Also see my other Google CP Solver models: http://www.hakank.org/google_or_tools/
|
||||
"""
|
||||
|
||||
import sys
|
||||
from constraint_solver import pywrapcp
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# Create the solver.
|
||||
solver = pywrapcp.Solver('Mr Smith problem')
|
||||
|
||||
#
|
||||
# data
|
||||
#
|
||||
n = 5
|
||||
|
||||
|
||||
#
|
||||
# declare variables
|
||||
#
|
||||
x = [solver.IntVar(0, 1, 'x[%i]' % i) for i in range(n)]
|
||||
Mr_Smith, Mrs_Smith, Matt, John, Tim = x
|
||||
|
||||
|
||||
#
|
||||
# constraints
|
||||
#
|
||||
|
||||
#
|
||||
# I've kept the MiniZinc constraints for clarity
|
||||
# and debugging.
|
||||
#
|
||||
|
||||
# If Mr Smith comes then his wife will come too.
|
||||
# (Mr_Smith -> Mrs_Smith)
|
||||
solver.Add(Mr_Smith-Mrs_Smith <= 0)
|
||||
|
||||
# At least one of their two sons Matt and John will come.
|
||||
# (Matt \/ John)
|
||||
solver.Add(Matt+John >= 1)
|
||||
|
||||
# Either Mrs Smith or Tim will come but not both.
|
||||
# bool2int(Mrs_Smith) + bool2int(Tim) = 1 /\
|
||||
# (Mrs_Smith xor Tim)
|
||||
solver.Add(Mrs_Smith + Tim == 1)
|
||||
|
||||
# Either Tim and John will come or neither will come.
|
||||
# (Tim = John)
|
||||
solver.Add(Tim == John)
|
||||
|
||||
# If Matt comes /\ then John and his father will also come.
|
||||
# (Matt -> (John /\ Mr_Smith))
|
||||
solver.Add(Matt - (John*Mr_Smith) <= 0)
|
||||
|
||||
|
||||
#
|
||||
# solution and search
|
||||
#
|
||||
db = solver.Phase(x,
|
||||
solver.INT_VAR_DEFAULT,
|
||||
solver.INT_VALUE_DEFAULT)
|
||||
|
||||
solver.NewSearch(db)
|
||||
|
||||
num_solutions = 0
|
||||
while solver.NextSolution():
|
||||
num_solutions += 1
|
||||
print 'x:', [x[i].Value() for i in range(n)]
|
||||
|
||||
print
|
||||
print 'num_solutions:', num_solutions
|
||||
print 'failures:', solver.failures()
|
||||
print 'branches:', solver.branches()
|
||||
print 'wall_time:', solver.wall_time(), 'ms'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
116
python/olympic.py
Normal file
116
python/olympic.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# Copyright 2010 Hakan Kjellerstrand hakank@bonetmail.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
|
||||
Olympic puzzle in Google CP Solver.
|
||||
|
||||
Benchmark for Prolog (BProlog)
|
||||
'''
|
||||
File : olympic.pl
|
||||
Author : Neng-Fa ZHOU
|
||||
Date : 1993
|
||||
|
||||
Purpose: solve a puzzle taken from Olympic Arithmetic Contest
|
||||
|
||||
Given ten variables with the following configuration:
|
||||
|
||||
X7 X8 X9 X10
|
||||
|
||||
X4 X5 X6
|
||||
|
||||
X2 X3
|
||||
|
||||
X1
|
||||
|
||||
We already know that X1 is equal to 3 and want to assign each variable
|
||||
with a different integer from {1,2,...,10} such that for any three
|
||||
variables
|
||||
Xi Xj
|
||||
|
||||
Xk
|
||||
the following constraint is satisfied:
|
||||
|
||||
|Xi-Xj| = Xk
|
||||
'''
|
||||
|
||||
Compare with the following models:
|
||||
* MiniZinc: http://www.hakank.org/minizinc/olympic.mzn
|
||||
* SICStus Prolog: http://www.hakank.org/sicstus/olympic.pl
|
||||
* ECLiPSe: http://hakank.org/eclipse/olympic.ecl
|
||||
* Gecode: http://hakank.org/gecode/olympic.cpp
|
||||
|
||||
|
||||
This model was created by Hakan Kjellerstrand (hakank@bonetmail.com)
|
||||
Also see my other Google CP Solver models: http://www.hakank.org/google_or_tools/
|
||||
"""
|
||||
|
||||
import sys
|
||||
from constraint_solver import pywrapcp
|
||||
|
||||
def minus(solver, x, y, z):
|
||||
solver.Add(z == abs(x - y))
|
||||
|
||||
def main():
|
||||
|
||||
# Create the solver.
|
||||
solver = pywrapcp.Solver('Olympic')
|
||||
|
||||
#
|
||||
# data
|
||||
#
|
||||
n = 10
|
||||
|
||||
#
|
||||
# declare variables
|
||||
#
|
||||
Vars = [solver.IntVar(1, n, 'Vars[%i]' % i) for i in range(n)]
|
||||
X1,X2,X3,X4,X5,X6,X7,X8,X9,X10 = Vars
|
||||
|
||||
#
|
||||
# constraints
|
||||
#
|
||||
solver.Add(solver.AllDifferent(Vars, True))
|
||||
|
||||
solver.Add(X1 == 3)
|
||||
minus(solver, X2, X3, X1)
|
||||
minus(solver, X4, X5, X2)
|
||||
minus(solver, X5, X6, X3)
|
||||
minus(solver, X7, X8, X4)
|
||||
minus(solver, X8, X9, X5)
|
||||
minus(solver, X9, X10, X6)
|
||||
|
||||
#
|
||||
# solution and search
|
||||
#
|
||||
db = solver.Phase(Vars,
|
||||
solver.INT_VAR_SIMPLE,
|
||||
solver.INT_VALUE_DEFAULT)
|
||||
|
||||
solver.NewSearch(db)
|
||||
|
||||
num_solutions = 0
|
||||
while solver.NextSolution():
|
||||
num_solutions += 1
|
||||
print 'Vars:', [Vars[i].Value() for i in range(n)]
|
||||
|
||||
print
|
||||
print 'num_solutions:', num_solutions
|
||||
print 'failures:', solver.failures()
|
||||
print 'branches:', solver.branches()
|
||||
print 'wall_time:', solver.wall_time(), 'ms'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
120
python/organize_day.py
Normal file
120
python/organize_day.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# Copyright 2010 Hakan Kjellerstrand hakank@bonetmail.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
|
||||
Organizing a day in Google CP Solver.
|
||||
|
||||
Simple scheduling problem.
|
||||
|
||||
Problem formulation from ECLiPSe:
|
||||
Slides on (Finite Domain) Constraint Logic Programming, page 38f
|
||||
http://eclipse-clp.org/reports/eclipse.ppt
|
||||
|
||||
|
||||
Compare with the following models:
|
||||
* MiniZinc: http://www.hakank.org/minizinc/organize_day.mzn
|
||||
* Comet: http://www.hakank.org/comet/organize_day.co
|
||||
* Gecode: http://hakank.org/gecode/organize_day.cpp
|
||||
|
||||
This model was created by Hakan Kjellerstrand (hakank@bonetmail.com)
|
||||
Also see my other Google CP Solver models: http://www.hakank.org/google_or_tools/
|
||||
"""
|
||||
|
||||
import sys
|
||||
from constraint_solver import pywrapcp
|
||||
|
||||
#
|
||||
# No overlapping of tasks s1 and s2
|
||||
#
|
||||
def no_overlap(solver, s1, d1, s2, d2):
|
||||
b1 = solver.MakeIsLessOrEqualVar(s1 + d1, s2) # s1 + d1 <= s2
|
||||
b2 = solver.MakeIsLessOrEqualVar(s2 + d2, s1) # s2 + d2 <= s1
|
||||
solver.Add(b1 + b2 >= 1)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# Create the solver.
|
||||
solver = pywrapcp.Solver('Organizing a day')
|
||||
|
||||
#
|
||||
# data
|
||||
#
|
||||
n = 4
|
||||
|
||||
tasks = range(n)
|
||||
work, mail, shop, bank = tasks
|
||||
durations = [4,1,2,1]
|
||||
|
||||
# task [i,0] must be finished before task [i,1]
|
||||
before_tasks = [
|
||||
[bank, shop],
|
||||
[mail, work]
|
||||
]
|
||||
|
||||
# the valid times of the day
|
||||
begin = 9
|
||||
end = 17
|
||||
|
||||
#
|
||||
# declare variables
|
||||
#
|
||||
begins = [solver.IntVar(begin, end, 'begins[%i]% % i') for i in tasks]
|
||||
ends = [solver.IntVar(begin, end, 'ends[%i]% % i') for i in tasks]
|
||||
|
||||
#
|
||||
# constraints
|
||||
#
|
||||
for i in tasks:
|
||||
solver.Add(ends[i] == begins[i] + durations[i])
|
||||
|
||||
for i in tasks:
|
||||
for j in tasks:
|
||||
if i < j:
|
||||
no_overlap(solver,
|
||||
begins[i], durations[i],
|
||||
begins[j], durations[j])
|
||||
|
||||
# specific constraints
|
||||
for (before, after) in before_tasks:
|
||||
solver.Add(ends[before] <= begins[after])
|
||||
|
||||
solver.Add(begins[work] >= 11)
|
||||
|
||||
|
||||
#
|
||||
# solution and search
|
||||
#
|
||||
db = solver.Phase(begins + ends,
|
||||
solver.INT_VAR_DEFAULT,
|
||||
solver.INT_VALUE_DEFAULT)
|
||||
|
||||
solver.NewSearch(db)
|
||||
|
||||
num_solutions = 0
|
||||
while solver.NextSolution():
|
||||
num_solutions += 1
|
||||
print 'begins:', [begins[i].Value() for i in tasks]
|
||||
print 'ends:', [ends[i].Value() for i in tasks]
|
||||
print
|
||||
|
||||
print 'num_solutions:', num_solutions
|
||||
print 'failures:', solver.failures()
|
||||
print 'branches:', solver.branches()
|
||||
print 'wall_time:', solver.wall_time(), 'ms'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
130
python/p_median.py
Normal file
130
python/p_median.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# Copyright 2010 Hakan Kjellerstrand hakank@bonetmail.com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
|
||||
P-median problem in Google CP Solver.
|
||||
|
||||
Model and data from the OPL Manual, which describes the problem:
|
||||
'''
|
||||
The P-Median problem is a well known problem in Operations Research.
|
||||
The problem can be stated very simply, like this: given a set of customers
|
||||
with known amounts of demand, a set of candidate locations for warehouses,
|
||||
and the distance between each pair of customer-warehouse, choose P
|
||||
warehouses to open that minimize the demand-weighted distance of serving
|
||||
all customers from those P warehouses.
|
||||
'''
|
||||
|
||||
Compare with the following models:
|
||||
* MiniZinc: http://hakank.org/minizinc/p_median.mzn
|
||||
* Comet: http://hakank.org/comet/p_median.co
|
||||
|
||||
This model was created by Hakan Kjellerstrand (hakank@bonetmail.com)
|
||||
Also see my other Google CP Solver models: http://www.hakank.org/google_or_tools/
|
||||
"""
|
||||
|
||||
import sys
|
||||
from constraint_solver import pywrapcp
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
# Create the solver.
|
||||
solver = pywrapcp.Solver('P-median problem')
|
||||
|
||||
#
|
||||
# data
|
||||
#
|
||||
p = 2
|
||||
|
||||
num_customers = 4
|
||||
customers = range(num_customers)
|
||||
Albert, Bob, Chris, Daniel = customers
|
||||
num_warehouses = 3
|
||||
warehouses = range(num_warehouses)
|
||||
Santa_Clara, San_Jose, Berkeley = warehouses
|
||||
|
||||
demand = [100,80,80,70]
|
||||
distance = [
|
||||
[ 2, 10, 50],
|
||||
[ 2, 10, 52],
|
||||
[50, 60, 3],
|
||||
[40, 60, 1]
|
||||
]
|
||||
|
||||
#
|
||||
# declare variables
|
||||
#
|
||||
open = [solver.IntVar(warehouses, 'open[%i]% % i')
|
||||
for w in warehouses]
|
||||
ship = {}
|
||||
for c in customers:
|
||||
for w in warehouses:
|
||||
ship[c,w] = solver.IntVar(0, 1,'ship[%i,%i]' % (c,w))
|
||||
ship_flat = [ship[c,w]
|
||||
for c in customers
|
||||
for w in warehouses]
|
||||
|
||||
z = solver.IntVar(0, 1000, 'z')
|
||||
|
||||
#
|
||||
# constraints
|
||||
#
|
||||
z_sum = solver.Sum([demand[c]*distance[c][w]*ship[c,w]
|
||||
for c in customers
|
||||
for w in warehouses])
|
||||
solver.Add(z == z_sum)
|
||||
|
||||
for c in customers:
|
||||
s = solver.Sum([ship[c,w]
|
||||
for w in warehouses])
|
||||
solver.Add(s == 1)
|
||||
|
||||
solver.Add(solver.Sum(open) == p)
|
||||
|
||||
for c in customers:
|
||||
for w in warehouses:
|
||||
solver.Add(ship[c,w] <= open[w])
|
||||
|
||||
# objective
|
||||
objective = solver.Minimize(z, 1)
|
||||
|
||||
#
|
||||
# solution and search
|
||||
#
|
||||
db = solver.Phase(open + ship_flat,
|
||||
solver.INT_VAR_DEFAULT,
|
||||
solver.INT_VALUE_DEFAULT)
|
||||
|
||||
solver.NewSearch(db, [objective])
|
||||
|
||||
num_solutions = 0
|
||||
while solver.NextSolution():
|
||||
num_solutions += 1
|
||||
print "z:", z.Value()
|
||||
print 'open:', [open[w].Value() for w in warehouses]
|
||||
for c in customers:
|
||||
for w in warehouses:
|
||||
print ship[c,w].Value(),
|
||||
print
|
||||
print
|
||||
|
||||
print 'num_solutions:', num_solutions
|
||||
print 'failures:', solver.failures()
|
||||
print 'branches:', solver.branches()
|
||||
print 'wall_time:', solver.wall_time(), 'ms'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user