Sie sind auf Seite 1von 58

Examples for Discrete

Constraint Programming
Belaid MOA
UVIC, SHRINC Project

Examples

Map coloring Problem


Cryptarithmetic
N-queens problem
Magic sequence
Magic square
Zebra puzzle
Uzbekian puzzle
A tiny transportation problem
Knapsack problem
graceful labeling problem

Map Coloring Problem


(MCP)

Given a map and given a set of colors,


the problem is how to color the map so
that the regions sharing a boundary line
dont have the same color.

Map Coloring Problem


(MCP)

MCP can be viewed as a graph coloring


problem:
a
b

a
d
d

Modeling MCP

MCP can be Modeled as a CSP:


A set of variables representing the
color of each region
The domain of the variables is the set
of the colors used.
A set of constraints expressing the fact
that countries that share the same
boundary are not colored with the
same color.

Modeling (MCP)

Example - Australia
Variables = {a,b,c,d,e,f,g}
Domain = {red, blue, green}
Constraints:
a!=b, a!=c
b!=c, b!=d
c!=e, c!=f
e!=d, e!=f

b
d
a

c
e
f
g

Coding MCP

OPL studio - Ilog Solver: 54 solutions found

enum Country={a,b,c,d,e,f,g};
enum Color = {red, green, blue};
var Color color[Country];
solve{
color[a]<>color[b];color[a]<>color[c];
color[b]<>color[c];color[b]<>color[d];
color[c]<>color[e];color[c]<>color[f];
color[e]<>color[d];color[e]<>color[f];
color[b]<>color[c];color[b]<>color[d];
};

Coding MCP

Coding MCP

ECLiPSe

:- lib(fd).
coloured(Countries) :Countries=[A,B,C,D,E,F,G],
Countries :: [red,green,blue],
ne(A,B), ne(A,C),
ne(B,C), ne(B,D),
ne(C,E), ne(C,F),
ne(E,D), ne(E,F),
labeling(Countries).
ne(X,Y) :- X##Y.

Coding MCP

Cryptarithmetic

The problem is to find the digits


corresponding to the letters involved in the
following puzzle:
SEND
+
MORE
MONEY

Cryptarithmetic Modeling

A CSP model for Cryptarithmetic problem:


Variables={S,E,N,D,M,O,R,Y}
Domain={0,1,2,3,4,5,6,7,8,9}
Constraints

The variables are all different

S!=0, M!=0

S*103+E*102+N*10+D {SEND}
+ M*103+O*102+R*10+E {MORE}=
M*104+O*103+N*102+E*10+Y {MONEY}

Coding Cryptarithmetic

OPL Studio - ILog Solver

enum letter = {S,E,N,D,M,O,R,Y};


range Digit 0..9;
var Digit value[letter];
solve{
alldifferent(value);
value[S]<>0;
value[M] <>0;
value[S]*1000+value[E]*100+value[N]*10+value[D]+
value[M]*1000+value[O]*100+value[R]*10+value[E]
= value[M]*10000+value[O]*1000+value[N]*100+value[E]*10+value[Y]
};

Coding Cryptarithmetic

Coding Cryptarithmetic

ECLiPSe

:- lib(fd).
sendmore(Digits) :Digits = [S,E,N,D,M,O,R,Y],
Digits :: [0..9],
alldifferent(Digits),
S #\= 0,
M #\= 0,
1000*S + 100*E + 10*N + D
+ 1000*M + 100*O + 10*R + E
#= 10000*M + 1000*O + 100*N + 10*E + Y,
labeling(Digits).

Coding Cryptarithmetic

N-Queens Problem

The problem is to put N queens on a board of NxN


such that no queen attacks any other queen.

A queen moves vertically, horizontally and diagonally

Modeling N-Queens
Problem

The queens problem can be modeling via the


following CSP
Variables={Q ,Q ,Q ,Q ,...,Q }.
1
2
3
4
N

Domain={1,2,3,,N} represents the column


in which the variables can be.
Constraints

Queens not on the same row: already taken care


off by the good modeling of the variables.
Queens not on the same column: Qi != Qj
Queens not on the same diagonal: |Q i-Qj| != |i-j|

Coding N-Queens Problem

OPL Studio - ILog Solver


int n << "number of queens:";
range Domain 1..n;
var Domain queens[Domain];
solve {
alldifferent(queens);
forall(ordered i,j in Domain) {
abs(queens[i]-queens[j])<> abs(i-j) ;
};
};

Coding N-Queens Problem

Coding N-Queens Problem

ECLiPSe

:-lib(fd).
nqueens(N, Q):length(Q,N),
Q::1..N,
alldifferent(Q),
( fromto(Q, [Q1|Cols], Cols, []) do
( foreach(Q2, Cols), param(Q1), count(Dist,1,_) do
Q2 - Q1 #\= Dist, Q1 - Q2 #\= Dist
)
),
search(Q).
search([]).
search(Q):deleteff(Var,Q,R),
indomain(Var), search(R).

Coding N-Queens Problem

Magic sequence problem

Given a finite integer n, the problem consists of finding


a sequence S = (s0,s1,,sn), such that si represents the
number of occurrences of i in S.

Example:
(2, 0, 2, 0)
(1,2,1,0)

Modeling MSP

MSP can be modeled by the following CSP


variables: s ,s , ,s
0 1
n-1

Domain:{0,1,,n}
constraints:

number of occurences of i in (s0,s1, ,sn-1) is si.

Redundant constraints:

the sum of s0,s1, ,sn-1 is n

the sum of i*Si, i in [0..n-1] is n

Coding MSP

OPL - ILog Solver


int n << "Number of Variables:";
range Range 0..n-1;
range Domain 0..n;
int value[i in Range ] = i;
var Domain s[Range];
solve {
distribute(s,value,s); //global constraint s[i]=sum(j in Range)(s[j]=i)
sum(i in Range) s[i] = n; //redundant constraint
sum(i in Range) s[i]*i = n; //redundant constraint
};

Coding MSP

ECLiPSe
:- lib(fd).
:- lib(fd_global).
:- lib(fd_search).
solve(N, Sequence) :length(Sequence, N),
Sequence :: 0..N-1,
( for(I,0,N-1),
foreach(Xi, Sequence),
foreach(I, Range), param(Sequence) do
occurrences(I, Sequence, Xi)
),
N #= sum(Sequence), % two redundant constraints
N #= Sequence*Range,
search(Sequence, 0, first_fail, indomain, complete, []).%search procedure

Magic square problem

A magic square of size N is an NxN square


filled with the numbers from 1 to N2 such that
the sums of each row, each column and the
two main diagonals are equal.

Example:

Modeling Magic square pb

Magic square problem can be viewed as a CSP with the following properties:

Variables: the elements of the matrix representing the square

Domain: 1..N*N

Constraints:

magic sum = sum of the columns = sum of the rows = sum of the down diagonal = sum of
the up diagonal

Remove symmetries

Redundant constraint:

magic sum = N(N2+1)/2

Coding Magic square pb

OPL Studio:
int N << "The length of the square:";
range Dimension 1..N;
range Values 1..N*N;
int msum = N*(N*N+1)/2; //magic sum
var Values square[1..N,1..N];
solve {
//The elements of the square are all different
alldifferent(square);
//the sum of the diagonal is magic sum
msum = sum(i in Dimension)square[i,i];
//the sum of the up diagonal is magic sum

Coding Magic square pb


msum = sum(i in Dimension)square[i,N-i+1];
//the sum of the rows and columns are all magic sum
forall(i in Dimension){
msum = sum(j in Dimension)square[i,j];
msum = sum(k in Dimension)square[k,i];
};
//remove symmetric behavior of the square
square[N,1] < square[1,N];
square[1,1] < square[1,N];
square[1,1] < square[N,N];
square[1,1] < square[N,1];
};

Magic square problem

Coding Magic square pb

ECLiPSe:
:- lib(fd).
magic(N) :Max is N*N,
Magicsum is N*(Max+1)//2,
dim(Square, [N,N]),
Square[1..N,1..N] :: 1..Max,
Rows is Square[1..N,1..N],
flatten(Rows, Vars),
alldifferent(Vars),

Coding Magic square pb


%constraints on rows
(
for(I,1,N),
foreach(U,UpDiag),
foreach(D,DownDiag),
param(N,Square,Sum)
do
Magicsum #= sum(Square[I,1..N]),
Magicsum #= sum(Square[1..N,I]),
U is Square[I,I],
D is Square[I,N+1-I]
),
%constraints on diagonals
Magicsum #= sum(UpDiag),
Magicsum #= sum(DownDiag),

Coding Magic square pb


%remove symmetry
Square[1,1] #< Square[1,N],
Square[1,1] #< Square[N,N],
Square[1,1] #< Square[N,1],
Square[1,N] #< Square[N,1],
%search
labeling(Vars),
print(Square).

Unfortunately, ECLiPSe ran for a long time without


providing any answer. ECLiPSe had also the same
behavior for a similar code from ECLiPSe website.

A Tiny Transportation
problem

How much should be shipped from several


sources to several destinations

Supply
cpty

Source

a1

a2

2
:
m

:
am

Demand
Qty Shipped Destination Qty

x1n x12
x21
x22
x2n

x11

b1

2
:
n

b2
:
bn

A Tiny Transportation
problem

3 plants with known capacities, 4 clients with


known demands and transport costs per unit
between them.

500

200

300

2 Find qty shipped?

400

300

100

400

Modeling TTP

TTP can be modeled by a CSP with optimization


as follows:

Variables: A1,A2,A3,B1,B2,B3,C1, C2, C3,D1,D2,D3


Domain: 0.0..Inf
constraints:

Demand constraints:

A1+A2+A3=200; B1+B2+B3=400; C1+C2+C3=300; D1+D2+D3=100;

Capacity constraints:

A1+B1+C1+D1500; A2+B2+C2+D2300; A3+B3+C3+D3400;

Minimization of the objective function:


10*A1 + 7*A2 + 11*A3 + 8*B1 + 5*B2 + 10*B3 +
5*C1 + 5*C2 + 8*C3 + 9*D1 + 3*D2 + 7*D3

Coding TTP

OPL Studio - Cplex Solver


var float+ productA[Range];var float+ productB[Range];
var float+ productC[Range]; var float+ productD[Range];
minimize
10*productA[1] + 7*productA[2] + 11*productA[3] +
8*productB[1] + 5*productB[2] + 10*productB[3] +
5*productC[1] + 5*productC[2] + 8*productC[3] +
9*productD[1] + 3*productD[2] + 7*productD[3]
subject to {
productA[1] + productA[2] + productA[3] = 200;
productB[1] + productB[2] + productB[3] = 400;
productC[1] + productC[2] + productC[3] = 300;
productD[1] + productD[2] + productD[3] = 100;
productA[1] + productB[1] + productC[1] + productD[1]<=500
productA[2] + productB[2] + productC[2]+productC[2] <= 300;
productA[3] + productB[3] + productC[3] + productD[3] <= 400;
};

Coding TTP

OPL Studio - Cplex Solver: Solution found


Optimal Solution with Objective Value: 6200.0000
productA[1] = 100.0000
productA[2] = 0.0000
productA[3] = 100.0000
productB[1] = 100.0000
productB[2] = 300.0000
productB[3] = 0.0000
productC[1] = 300.0000
productC[2] = 0.0000
productC[3] = 0.0000
productD[1] = 0.0000
productD[2] = 100.0000
productD[3] = 0.0000

Coding TTP

ECLiPSe
:- lib(eplex_cplex).
main1(Cost, Vars) :Vars = [A1, A2, A3, B1, B2, B3, C1, C2, C3, D1, D2, D3],
Vars :: 0.0..inf,
A1 + A2 + A3 $= 200, B1 + B2 + B3 $= 400,
C1 + C2 + C3 $= 300, D1 + D2 + D3 $= 100,
A1 + B1 + C1 + D1 $=< 500, A2 + B2 + C2 + D2 $=< 300,
A3 + B3 + C3 + D3 $=< 400,
optimize(min(10*A1 + 7*A2 + 11*A3 + 8*B1 + 5*B2 + 10*B3 +
5*C1 + 5*C2 + 8*C3 +9*D1 + 3*D2 + 7*D3), Cost).

It didnt run!
calling an undefined procedure cplex_prob_init()

Zebra puzzle

Zebra is a well known puzzle in which five men with


different nationalities live in the first five house of a
street. They practice five distinct professions, and each
of them has a favorite animal and a favorite drink, all of
them different. The five houses are painted in different
colors. The puzzle is to find who owns Zebra.
Zebra puzzle has different statements. Well handle two.
This kind of Puzzle is usually treated as an instance of
the class of tabular constraint satisfaction problems in
which we express the problem using tables.
In this presentation we show how to solve it using CSP
languages: OPL studio and ECLiPSe.

Modeling Zebra puzzle

In crucial step in Modeling Zebra puzzle is finding the


decision variables. In our case, we consider:
variables: persons, colors, pets, drinks, tobaccos.
Domain: 1..5 (representing the five houses)
Constraints:
Expressed directly from the statement of the
puzzle.

Coding Zebra puzzle

OPL Studio - ILog Solver

enum people {Englishman, Spaniard, Ukrainian, Norwegian, Japanese};


enum drinks {coffee, tea, milk, orange, water};
enum pets {dog, fox, zebra, horse, snails};
enum tabacco {winston, kools, chesterfields, luckyStrike, parliaments };
enum colors {ivory, yellow, red , green, blue};
range houses 1..5;//{first, second, third, fourth, fifth};
var
var
var
var
var

houses
houses
houses
houses
houses

hseClr[colors];
hsePple[people];
hsePts[pets];
hseDrks[drinks];
hseTaba[tabacco];

Coding Zebra puzzle


solve{
hsePple[Englishman] = hseClr[red]; hsePple[Spaniard]=hsePts[dog];
hseDrks[coffee] = hseClr[green]; hsePple[Ukrainian] = hseDrks[tea];
hseClr[green] = hseClr[ivory]+1; hseTaba[winston] = hsePts[snails];
hseTaba[kools]=hseClr[yellow]; hseDrks[milk]=3;
hsePple[Norwegian] = 1;
hseTaba[chesterfields]=hsePts[fox]+1 \/ hseTaba[chesterfields]=hsePts[fox]-1;
hseTaba[kools] = hsePts[horse]+1 \/ hseTaba[kools] = hsePts[horse]-1 ;
hseTaba[ luckyStrike] = hseDrks[orange];
hsePple[ Japanese] = hseTaba[parliaments];
hsePple[Norwegian] = hseClr[blue]+1 \/ hsePple[Norwegian] = hseClr[blue]-1;
//slient constraints-Global constraint alldifferent
alldifferent(hsePple);//forall(ordered i,j in people) hsePple[i] <> hsePple[j];
alldifferent(hsePts);//forall(ordered i,j in pets) hsePts[i] <> hsePts[j];
alldifferent(hseClr);//forall(ordered i,j in colors) hseClr[i] <> hseClr[j];
alldifferent(hseDrks);//forall(ordered i,j in drinks) hseDrks[i] <> hseDrks[j];
alldifferent(hseTaba);//forall(ordered i,j in tabacco) hseTaba[i] <> hseTaba[j];
};

Coding Zebra puzzle


%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%

The Englishman lives in a red house.


The Spaniard owns a dog.
The Japanese is a painter.
The Italian drinks tea.
The Norwegian lives in the first house on the left.
The owner of the green house drinks coffee.
The green house is on the right of the white one.
The sculptor breeds snails.
The diplomat lives in the yellow house.
Milk is drunk in the middle house.
The Norwegian's house is next to the blue one.
The violinist drinks fruit juice.
The fox is in a house next to that of the doctor.
The horse is in a house next to that of the diplomat.
Who owns a Zebra, and who drinks water?

Coding Zebra puzzle


:- lib(fd).
zebra :% we use 5 lists of 5 variables each
Nat = [English, Spaniard, Japanese, Italian, Norwegian],
Color = [Red, Green, White, Yellow, Blue],
Profession = [Painter, Sculptor, Diplomat, Violinist, Doctor],
Pet = [Dog, Snails, Fox, Horse, Zebra],
Drink = [Tea, Coffee, Milk, Juice, Water],
% domains: all the variables range over house numbers 1 to 5
Nat :: 1..5,
Color :: 1..5,
Profession :: 1..5,
Pet :: 1..5,
Drink :: 1..5,

Coding Zebra puzzle


% the values in each list are exclusive
alldifferent(Nat),
alldifferent(Color),
alldifferent(Profession),
alldifferent(Pet),
alldifferent(Drink),
% and here follow the actual constraints
English = Red, Spaniard = Dog,
Japanese = Painter, Italian = Tea,
Norwegian = 1, Green = Coffee,
Green #= White + 1, Sculptor = Snails,
Diplomat = Yellow, Milk = 3,
Dist1 #= Norwegian - Blue, Dist1 :: [-1, 1],
Violinist = Juice,
Dist2 #= Fox - Doctor, Dist2 :: [-1, 1],
Dist3 #= Horse - Diplomat, Dist3 :: [-1, 1],

Coding Zebra puzzle


% put all the variables in a single list
flatten([Nat, Color, Profession, Pet, Drink], List),
% search: label all variables with values
labeling(List),
% print the answers: we need to do some decoding
NatNames = [English-english, Spaniard-spaniard, Japanese-japanese,
Italian-italian, Norwegian-norwegian],
memberchk(Zebra-ZebraNat, NatNames),
memberchk(Water-WaterNat, NatNames),
printf("The %w owns the zebra%n", [ZebraNat]),
printf("The %w drinks water%n", [WaterNat]).

Answer from ECLiPSe after 0.02s


The japanese owns the zebra
The norwegian drinks water

Uzbekian Puzzle
An uzbekian sales man met five traders who live in five
different cities. The five traders are:
{Abdulhamid, Kurban,Ruza, Sharaf, Usman}
The five cities are :
{Bukhara, Fergana, Kokand, Samarkand, Tashkent}
Find the order in which he visited the cities given the following
information:

He met Ruza before Sharaf after visiting Samarkand,


He reached Fergana after visiting Samarkand followed by other two cities,
The third trader he met was Tashkent,
Immediately after his visit to Bukhara, he met Abdulhamid
He reached Kokand after visiting the city of Kurban followed by other two
cities;

Modeling Uzbekian Puzzle

The uzbekian puzzle can formulated within the CSP framework


as follows:
Variables: order in which he visited each city and met each
trader
Domain:1..5
constraints:

He met Ruza before Sharaf after visiting Samarkand,


He reached Fergana after visiting Samarkand followed by other two
cities,
The third trader he met was Tashkent,
Immediately after his visit to Bukhara, he met Abdulhamid
He reached Kokand after visiting the city of Kurban followed by other
two cities;

Coding Uzbekian Puzzle in


OPL
enum cities {Bukhara, Fergana, Kokand, Samarkand, Tashkent};
enum traders {Abdulhamid, Kurban, Ruza, Sharaf, Usman};
range order 1..5;
var order mtTrader[traders];
var order vstCty[cities];
Solution [1]
solve{
mtTrader[Ruza] < mtTrader[Sharaf];
mtTrader[Abdulhamid] = 2
mtTrader[Ruza] > vstCty[Samarkand];
mtTrader[Kurban] = 3
vstCty[Fergana] = vstCty[Samarkand] + 2;
mtTrader[Ruza] = 4
vstCty[Tashkent] = 3;
mtTrader[Sharaf] = 5
mtTrader[Abdulhamid] = vstCty[Bukhara] + 1;
mtTrader[Usman] = 1
vstCty[Kokand] = mtTrader[Kurban] + 2;
alldifferent(mtTrader);
vstCty[Bukhara] = 1
alldifferent(vstCty);
vstCty[Fergana] = 4
};
vstCty[Kokand] = 5
vstCty[Samarkand] = 2
vstCty[Tashkent] = 3

Knapsack problem

We have a knapsack with a fixed capacity and a


number of items. Each item has a weight and a
value. The problem consists of filling the knapsack
without exceeding its capacity, while maximizing
the overall value of its contents.

Knapsack problem is an example of Mixed integer


programming.

Modeling Knapsack
problem

A CSP model for knapsack problem is given by:

Variables: For each item, we associate a variable that gives


the quantity of such an item we can put in the knapsack.
Domain: 0..Capacity of the knapsack
Constraints:
sum of the weights in the knapsack is less than the
capacity
Objective function to maximize:
sum of the values in the knapsack

Coding Knapsack Pb in
OPL
range items 1..10;
int MaxCapacity= 1000;
int value[items] = [29,30,25,27, 28,21,23,19,18,17];
int weight[items] =[30,32,33,31,34,40,45,44,39,35];
var int take[items] in 0..MaxCapacity;
maximize
sum(i in items) value[i] * take[i]
subject to
sum(i in items) weight[i] * take[i] <= MaxCapacity;

integer programming (CPLEX MIP)


displaying solution ...
take[1] = 28 take[2] = 5 take[i] = 0, i=3..10

Graceful labeling problem

Given a tree T with m+1 nodes, and m edges, find


the possible labels in {0,1,,m} for the nodes such
that the absolute value of the difference of the labels
of the nodes related to each edge are all different.
Formally, let f be a function from V ----> {0,,m},
where V is the set of the vertices of T.
f is said to be a graceful labeling of T iff
|f(v )-f(v )| are all different for any edge v v in T.
i
j
i j

Modeling Graceful labeling


Pb

Graceful labeling problem can be formulated into


the following CSP:
variables: labels to put on each node of T
Domain: 0..m
constraints:
the absolute value of the difference between
the labels of any edge are all different

Coding Graceful labeling


Pb

OPL program for graceful labeling problem


int nbreOfNodes = ...;
//set the range of the labels of the nodes
range nodes 0..nbreOfNodes-1; range indices 1..nbreOfNodes;
int adjacencyMatrix[indices, indices] = ...;
var nodes label[indices];
solve {
alldifferent(label);
forall(ordered i, j in indices){
if(adjacencyMatrix[i,j] <> 0) then
forall(ordered k, h in indices){
if(adjacencyMatrix[k,h] <> 0 & not(k=i & h=j)) then
abs(label[i]-label[j])<>abs(label[h]-label[k])
endif;
}
endif; };};

Coding Graceful labeling


Pb

Data file
nbreOfNodes = 7;
adjacencyMatrix = [[ 0, 1, 0, 0, 0, 0, 0],
[ 1, 0, 1, 0, 0, 0, 0 ],
[ 0, 1, 0, 1, 0, 1, 0 ],
[ 0, 0, 1, 0, 1, 0, 0 ],
[ 0, 0, 0, 1, 0, 0, 0 ],
5
[ 0, 0, 1, 0, 0, 0, 1 ],
[ 0, 0, 0, 0, 0, 1, 0 ]];
label[1] = 0
Solution Example:
label[2] = 6
label[3] = 1
label[4] = 3
label[5] = 4
label[6] = 5
label[7] = 2

Das könnte Ihnen auch gefallen