Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > bd5c3d824c3db63ffd9226c15941e6ad > files > 1207

mozart-1.4.0-1mdv2010.0.i586.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>7.3 Example: Magic Squares</TITLE><LINK href="ozdoc.css" rel="stylesheet" type="text/css"></HEAD><BODY><TABLE align="center" border="0" cellpadding="6" cellspacing="6" class="nav"><TR bgcolor="#DDDDDD"><TD><A href="node32.html#section.propagators.pythagoras">&lt;&lt; Prev</A></TD><TD><A href="node30.html">- Up -</A></TD><TD><A href="node34.html#section.propagators.exercises">Next &gt;&gt;</A></TD></TR></TABLE><DIV id="section.propagators.squares"><H2><A name="section.propagators.squares">7.3 Example: Magic Squares</A></H2><P>This example shows a smart representation of a matrix and a concomitant defined constraint of higher order. The model will eliminate symmetries by imposing order constraints. Propagation will be drastically improved by exploiting a redundant constraint. </P><DIV class="unnumbered"><H3><A name="label96">Problem Specification</A></H3><P>The Magic Square Puzzle consists in finding for given <IMG alt="N" src="latex4.png"> an <IMG alt="N\times N" src="latex113.png">-matrix such that: </P><UL><LI><P>Every field of the matrix is an integer between 1 and <IMG alt="N^2" src="latex150.png">.</P></LI><LI><P>The fields of the matrix are pairwise distinct.</P></LI><LI><P>The sums of the rows, columns, and the two main diagonals are all equal.</P></LI></UL><P> A magic square for <IMG alt="N=3" src="latex151.png"> looks as follows: </P><BLOCKQUOTE><P><IMG alt="\begin{array}{ccc}
2&7&6\\
9&5&1\\
4&3&8
\end{array}" src="latex152.png"></P></BLOCKQUOTE><P> p&gt; The Magic Square Puzzle is extremely hard for large <IMG alt="N" src="latex4.png">. Even for <IMG alt="{N=5}" src="latex153.png">, our script will have to explore almost 8000 nodes to find a solution. </P></DIV><DIV class="unnumbered"><H3><A name="label97">Model</A></H3><P>We model the problem by having a variable <IMG alt="F_{ij}" src="latex154.png"> for every field <IMG alt="(i,j)" src="latex155.png"> of the matrix. Moreover, we have one additional variable <IMG alt="S" src="latex7.png"> and require that the sum of every row, column, and main diagonal equals <IMG alt="S" src="latex7.png">.</P><P>Without loss of generality, we can impose the following order constraints eliminating symmetries: </P><BLOCKQUOTE><P><IMG alt="F_{11}<F_{NN},
\qquad
F_{N1}<F_{1N},
\qquad
F_{11}<F_{N1}." src="latex156.png"></P></BLOCKQUOTE><P></P><P>Since the sum of the sums of the rows must equal the sum of all fields, we have the redundant constraint </P><BLOCKQUOTE><P><IMG alt="{N^2\over 2}\cdot(N^2+1) = N\cdot S" src="latex157.png"></P></BLOCKQUOTE><P> To see this, note that sum of all fields equals </P><BLOCKQUOTE><P><IMG alt="1+2+\ldots+N^2 = {N^2\over 2}\cdot(N^2+1)" src="latex158.png"></P></BLOCKQUOTE><P></P><P>and that the sum of each of the <IMG alt="N" src="latex4.png"> rows must be <IMG alt="S" src="latex7.png">. </P></DIV><DIV class="unnumbered"><H3><A name="label98">Distribution Strategy</A></H3><P>We distribute on the variables <IMG alt="F_{11},\ldots,
F_{NN}" src="latex159.png"> with a first-fail strategy splitting the domain of the selected variable and trying the lower half first. </P><DIV class="figure" id="progmagicsquare"><HR><P><A name="progmagicsquare"></A></P></DIV><DL class="anonymous"><DD class="code"><CODE><SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">MagicSquare</SPAN>&nbsp;N}<BR>&nbsp;&nbsp;&nbsp;NN&nbsp;&nbsp;=&nbsp;N<SPAN class="keyword">*</SPAN>N<BR>&nbsp;&nbsp;&nbsp;L1N&nbsp;=&nbsp;{List<SPAN class="keyword">.</SPAN>number&nbsp;1&nbsp;N&nbsp;1}&nbsp;&nbsp;%&nbsp;<SPAN class="comment">[1&nbsp;2&nbsp;3&nbsp;...&nbsp;N]<BR></SPAN><SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;Square}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Field</SPAN>&nbsp;I&nbsp;J}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Square<SPAN class="keyword">.</SPAN>((I<SPAN class="keyword">-</SPAN>1)<SPAN class="keyword">*</SPAN>N&nbsp;<SPAN class="keyword">+</SPAN>&nbsp;J)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Assert</SPAN>&nbsp;F}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%&nbsp;<SPAN class="comment">{F&nbsp;1}&nbsp;+&nbsp;{F&nbsp;2}&nbsp;+&nbsp;...&nbsp;+&nbsp;{F&nbsp;N}&nbsp;=:&nbsp;Sum<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{FD<SPAN class="keyword">.</SPAN>sum&nbsp;{Map&nbsp;L1N&nbsp;F}&nbsp;<SPAN class="string">'=:'</SPAN>&nbsp;Sum}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sum&nbsp;=&nbsp;{FD<SPAN class="keyword">.</SPAN>decl}<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{FD<SPAN class="keyword">.</SPAN>tuple&nbsp;square&nbsp;NN&nbsp;1<SPAN class="keyword">#</SPAN>NN&nbsp;Square}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{FD<SPAN class="keyword">.</SPAN>distinct&nbsp;Square}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%%&nbsp;<SPAN class="comment">Diagonals<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Assert&nbsp;<SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;I}&nbsp;{Field&nbsp;I&nbsp;I}&nbsp;<SPAN class="keyword">end</SPAN>}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Assert&nbsp;<SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;I}&nbsp;{Field&nbsp;I&nbsp;N<SPAN class="keyword">+</SPAN>1<SPAN class="keyword">-</SPAN>I}&nbsp;<SPAN class="keyword">end</SPAN>}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%%&nbsp;<SPAN class="comment">Columns<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{For&nbsp;1&nbsp;N&nbsp;1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;I}&nbsp;{Assert&nbsp;<SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;J}&nbsp;{Field&nbsp;I&nbsp;J}&nbsp;<SPAN class="keyword">end</SPAN>}&nbsp;<SPAN class="keyword">end</SPAN>}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%%&nbsp;<SPAN class="comment">Rows<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{For&nbsp;1&nbsp;N&nbsp;1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;J}&nbsp;{Assert&nbsp;<SPAN class="keyword">fun</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">$</SPAN>&nbsp;I}&nbsp;{Field&nbsp;I&nbsp;J}&nbsp;<SPAN class="keyword">end</SPAN>}&nbsp;<SPAN class="keyword">end</SPAN>}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%%&nbsp;<SPAN class="comment">Eliminate&nbsp;symmetries<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Field&nbsp;1&nbsp;1}&nbsp;<SPAN class="keyword">&lt;:</SPAN>&nbsp;{Field&nbsp;N&nbsp;N}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Field&nbsp;N&nbsp;1}&nbsp;<SPAN class="keyword">&lt;:</SPAN>&nbsp;{Field&nbsp;1&nbsp;N}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Field&nbsp;1&nbsp;1}&nbsp;<SPAN class="keyword">&lt;:</SPAN>&nbsp;{Field&nbsp;N&nbsp;1}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%%&nbsp;<SPAN class="comment">Redundant:&nbsp;sum&nbsp;of&nbsp;all&nbsp;fields&nbsp;=&nbsp;(number&nbsp;rows)&nbsp;*&nbsp;Sum<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NN<SPAN class="keyword">*</SPAN>(NN<SPAN class="keyword">+</SPAN>1)&nbsp;<SPAN class="keyword">div</SPAN>&nbsp;2&nbsp;<SPAN class="keyword">=:</SPAN>&nbsp;N<SPAN class="keyword">*</SPAN>Sum<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;%%<SPAN class="comment">&nbsp;<BR></SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{FD<SPAN class="keyword">.</SPAN>distribute&nbsp;split&nbsp;Square}<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR><SPAN class="keyword">end</SPAN></CODE></DD></DL><DIV class="figure"><P class="caption"><STRONG>Figure&nbsp;7.3:</STRONG> A script for the Magic Square Puzzle.</P><HR></DIV><P> </P></DIV><DIV class="unnumbered"><H3><A name="label99">Script</A></H3><P><A href="node33.html#progmagicsquare">Figure&nbsp;7.3</A> shows a script realizing the model and distribution strategy just discussed. The actual script is created by a procedure <CODE>MagicSquare</CODE> taking <CODE>N</CODE> as parameter.</P><P>The script represents the matrix as a tuple with <IMG alt="N^2" src="latex150.png"> elements. The tuple is the value of the root variable <CODE>Square</CODE>. The function </P><BLOCKQUOTE class="code"><CODE>{Field&nbsp;I&nbsp;J}</CODE></BLOCKQUOTE><P> returns the component of <CODE>Square</CODE> that represents the field at position <CODE>(I<SPAN class="keyword">,</SPAN>J)</CODE>. The variable <CODE>Sum</CODE> takes the sum of the rows, columns, and main diagonals as value. The procedure </P><BLOCKQUOTE class="code"><CODE>{Assert&nbsp;</CODE><I>F</I><CODE>}</CODE></BLOCKQUOTE><P> takes a function <I>F</I> and posts the constraint </P><BLOCKQUOTE class="code"><CODE>{</CODE><I>F</I><CODE>&nbsp;1}&nbsp;<SPAN class="keyword">+</SPAN>&nbsp;{</CODE><I>F</I><CODE>&nbsp;2}&nbsp;<SPAN class="keyword">+</SPAN>&nbsp;<SPAN class="keyword">...</SPAN>&nbsp;<SPAN class="keyword">+</SPAN>&nbsp;{</CODE><I>F</I><CODE>&nbsp;N}&nbsp;=&nbsp;Sum</CODE></BLOCKQUOTE><P> Obviously, <CODE>{Assert&nbsp;F}</CODE> is a defined constraint of higher order. With the help of this defined constraint it is straightforward to state that the sums of the rows, columns, and main diagonals are all equal to <CODE>Sum</CODE>. </P><P>With the Explorer you can find out that for <CODE>N=3</CODE> there is exactly one magic square satisfying the ordering constraints of our model. Without the ordering constraints there are 8 different solutions. Omitting the propagator for the redundant constraint will increase the search tree by an order of magnitude.</P><P></P></DIV></DIV><TABLE align="center" border="0" cellpadding="6" cellspacing="6" class="nav"><TR bgcolor="#DDDDDD"><TD><A href="node32.html#section.propagators.pythagoras">&lt;&lt; Prev</A></TD><TD><A href="node30.html">- Up -</A></TD><TD><A href="node34.html#section.propagators.exercises">Next &gt;&gt;</A></TD></TR></TABLE><HR><ADDRESS><A href="http://www.ps.uni-sb.de/~schulte/">Christian&nbsp;Schulte</A> and&nbsp;<A href="http://www.ps.uni-sb.de/~smolka/">Gert&nbsp;Smolka</A><BR><SPAN class="version">Version 1.4.0 (20090610)</SPAN></ADDRESS></BODY></HTML>