1 | #!/usr/bin/env python |
---|
2 | # |
---|
3 | # Problem definition: |
---|
4 | # Example in google/or-tools |
---|
5 | # https://github.com/google/or-tools/blob/master/examples/python/olympic.py |
---|
6 | # with Copyright 2010 Hakan Kjellerstrand hakank@bonetmail.com |
---|
7 | # and disclamer as stated at the above reference link. |
---|
8 | # |
---|
9 | # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) |
---|
10 | # Copyright (c) 1997-2016 California Institute of Technology. |
---|
11 | # License: 3-clause BSD. The full license text is available at: |
---|
12 | # - http://mmckerns.github.io/project/mystic/browser/mystic/LICENSE |
---|
13 | """ |
---|
14 | Olympic puzzle in Google CP Solver. |
---|
15 | |
---|
16 | Prolog benchmark problem |
---|
17 | ''' |
---|
18 | Name : olympic.pl |
---|
19 | Author : Neng-Fa |
---|
20 | Date : 1993 |
---|
21 | |
---|
22 | Purpose: solve a puzzle taken from Olympic Arithmetic Contest |
---|
23 | |
---|
24 | Given ten variables with the following configuration: |
---|
25 | |
---|
26 | X7 X8 X9 X10 |
---|
27 | |
---|
28 | X4 X5 X6 |
---|
29 | |
---|
30 | X2 X3 |
---|
31 | |
---|
32 | X1 |
---|
33 | |
---|
34 | We already know that X1 is equal to 3 and want to assign each variable |
---|
35 | with a different integer from {1,2,...,10} such that for any three |
---|
36 | variables |
---|
37 | Xi Xj |
---|
38 | |
---|
39 | Xk |
---|
40 | the following constraint is satisfied: |
---|
41 | |
---|
42 | |Xi-Xj| = Xk |
---|
43 | ''' |
---|
44 | """ |
---|
45 | |
---|
46 | def objective(x): |
---|
47 | return 0.0 |
---|
48 | |
---|
49 | n = 10 |
---|
50 | |
---|
51 | bounds = [(1,n)]*n |
---|
52 | # with penalty='penalty' applied, solution is: |
---|
53 | xs = [[3, 7, 4, 2, 9, 5, 8, 10, 1, 6], |
---|
54 | [3, 7, 4, 2, 8, 5, 10, 9, 1, 6], |
---|
55 | [3, 2, 5, 7, 9, 4, 8, 1, 10, 6], |
---|
56 | [3, 5, 2, 4, 9, 7, 6, 10, 1, 8], |
---|
57 | [3, 4, 7, 5, 1, 8, 6, 10, 9, 2], |
---|
58 | [3, 4, 7, 5, 8, 1, 6, 2, 10, 9], |
---|
59 | [3, 4, 7, 5, 9, 2, 6, 1, 10, 8]] |
---|
60 | ys = 0.0 |
---|
61 | |
---|
62 | # constraints |
---|
63 | def penalty1(x): # == 0 |
---|
64 | return x[0] - 3 |
---|
65 | |
---|
66 | def penalty2(x): # == 0 |
---|
67 | return abs(x[1] - x[2]) - x[0] |
---|
68 | |
---|
69 | def penalty3(x): # == 0 |
---|
70 | return abs(x[3] - x[4]) - x[1] |
---|
71 | |
---|
72 | def penalty4(x): # == 0 |
---|
73 | return abs(x[4] - x[5]) - x[2] |
---|
74 | |
---|
75 | def penalty5(x): # == 0 |
---|
76 | return abs(x[6] - x[7]) - x[3] |
---|
77 | |
---|
78 | def penalty6(x): # == 0 |
---|
79 | return abs(x[7] - x[8]) - x[4] |
---|
80 | |
---|
81 | def penalty7(x): # == 0 |
---|
82 | return abs(x[8] - x[9]) - x[5] |
---|
83 | |
---|
84 | |
---|
85 | from mystic.penalty import quadratic_equality |
---|
86 | from mystic.constraints import as_constraint |
---|
87 | |
---|
88 | @quadratic_equality(penalty1) |
---|
89 | @quadratic_equality(penalty2) |
---|
90 | @quadratic_equality(penalty3) |
---|
91 | @quadratic_equality(penalty4) |
---|
92 | @quadratic_equality(penalty5) |
---|
93 | @quadratic_equality(penalty6) |
---|
94 | @quadratic_equality(penalty7) |
---|
95 | def penalty(x): |
---|
96 | return 0.0 |
---|
97 | |
---|
98 | solver = as_constraint(penalty) |
---|
99 | |
---|
100 | |
---|
101 | from mystic.constraints import unique |
---|
102 | |
---|
103 | from numpy import round, hstack, clip |
---|
104 | def constraint(x): |
---|
105 | x = round(x).astype(int) # force round and convert type to int |
---|
106 | x = clip(x, 1,n) #XXX: impose bounds |
---|
107 | x = unique(x, range(1,n+1)) |
---|
108 | return x |
---|
109 | |
---|
110 | |
---|
111 | if __name__ == '__main__': |
---|
112 | |
---|
113 | from mystic.solvers import diffev2 |
---|
114 | from mystic.math import almostEqual |
---|
115 | from mystic.monitors import Monitor, VerboseMonitor |
---|
116 | mon = VerboseMonitor(10)#,10) |
---|
117 | |
---|
118 | result = diffev2(objective, x0=bounds, bounds=bounds, penalty=penalty, constraints=constraint, npop=50, ftol=1e-8, gtol=200, disp=True, full_output=True, cross=0.1, scale=0.9, itermon=mon) |
---|
119 | |
---|
120 | print result[0] |
---|
121 | assert almostEqual(result[0], xs[0], tol=1e-8) \ |
---|
122 | or almostEqual(result[0], xs[1], tol=1e-8) \ |
---|
123 | or almostEqual(result[0], xs[2], tol=1e-8) \ |
---|
124 | or almostEqual(result[0], xs[3], tol=1e-8) \ |
---|
125 | or almostEqual(result[0], xs[4], tol=1e-8) \ |
---|
126 | or almostEqual(result[0], xs[-1], tol=1e-8) |
---|
127 | assert almostEqual(result[1], ys, tol=1e-4) |
---|
128 | |
---|
129 | |
---|
130 | # EOF |
---|