<?xml version="1.0" encoding="ISO-8859-1"?><article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<front>
<journal-meta>
<journal-id>1683-0789</journal-id>
<journal-title><![CDATA[Acta Nova]]></journal-title>
<abbrev-journal-title><![CDATA[RevActaNova.]]></abbrev-journal-title>
<issn>1683-0789</issn>
<publisher>
<publisher-name><![CDATA[Universidad Católica Boliviana]]></publisher-name>
</publisher>
</journal-meta>
<article-meta>
<article-id>S1683-07892011000100004</article-id>
<title-group>
<article-title xml:lang="es"><![CDATA[Programando con restricciones]]></article-title>
</title-group>
<contrib-group>
<contrib contrib-type="author">
<name>
<surname><![CDATA[Gumucio Escobar]]></surname>
<given-names><![CDATA[Rodrigo Ronald]]></given-names>
</name>
</contrib>
</contrib-group>
<aff id="A">
<institution><![CDATA[,  ]]></institution>
<addr-line><![CDATA[ ]]></addr-line>
</aff>
<pub-date pub-type="pub">
<day>00</day>
<month>03</month>
<year>2011</year>
</pub-date>
<pub-date pub-type="epub">
<day>00</day>
<month>03</month>
<year>2011</year>
</pub-date>
<volume>5</volume>
<numero>1</numero>
<fpage>72</fpage>
<lpage>95</lpage>
<copyright-statement/>
<copyright-year/>
<self-uri xlink:href="http://www.scielo.org.bo/scielo.php?script=sci_arttext&amp;pid=S1683-07892011000100004&amp;lng=en&amp;nrm=iso"></self-uri><self-uri xlink:href="http://www.scielo.org.bo/scielo.php?script=sci_abstract&amp;pid=S1683-07892011000100004&amp;lng=en&amp;nrm=iso"></self-uri><self-uri xlink:href="http://www.scielo.org.bo/scielo.php?script=sci_pdf&amp;pid=S1683-07892011000100004&amp;lng=en&amp;nrm=iso"></self-uri><abstract abstract-type="short" xml:lang="es"><p><![CDATA[Muchas veces nos encontramos con problemas de combinatoria difíciles de resolver. Estos problemas aparecen comúnmente no solo en el ámbito académico (por ejemplo en los dominios de la inteligencia artificial, bases de datos, investigación operativa, etc.), sino también en el ámbito de nuestra vida cotidiana (por ejemplo en las áreas de planificación, programación de actividades, asignación de recursos, etc.). Programando con restricciones es posible en muchos casos encontrar, de manera altamente eficiente, soluciones a muchos de estos problemas manejando su complejidad de manera simple e, incluso, elegante. Este artículo es una introducción a la programación con restricciones. Describe de manera sencilla una buena parte de las técnicas y conceptos fundamentales que la sustentan a través de ejemplos abordados de manera clara y concisa. Finaliza con un ejemplo práctico y concreto, mostrando la resolución de un problema clásico usando C++.]]></p></abstract>
<abstract abstract-type="short" xml:lang="en"><p><![CDATA[Hard combinatorial problems are ubiquitous in our society. They arise in many application domains (e.g., artificial intelligence, data bases, operations research, etc.) and diverse real life settings (e.g., scheduling, timetabling, resource allocation, etc.). Constraint Programming is a technique that manages the complexity of these problems in a simple and even elegant manner. It usually allows us to highly efficiently find solutions to many hard combinatorial problems. This article is an introduction to Constraint Programming. It describes many of its fundamental concepts and techniques through clear and concise examples. It finishes with a practical example, solving a classical problem, using C++.]]></p></abstract>
<kwd-group>
<kwd lng="es"><![CDATA[programación declarativa]]></kwd>
<kwd lng="es"><![CDATA[problema de combinatoria]]></kwd>
<kwd lng="es"><![CDATA[restricción]]></kwd>
<kwd lng="es"><![CDATA[programación con restricciones]]></kwd>
<kwd lng="en"><![CDATA[declarative programming]]></kwd>
<kwd lng="en"><![CDATA[combinatorial problem]]></kwd>
<kwd lng="en"><![CDATA[constraint]]></kwd>
<kwd lng="en"><![CDATA[constraint programming]]></kwd>
</kwd-group>
</article-meta>
</front><body><![CDATA[  <h1 align="center"><font size="4" face="Verdana"><b>Programando con restricciones</b></font></h1>     <p align="center">&nbsp;</p>     <p align="center">&nbsp;</p>     <p align="center"><font size="2" face="Verdana"><b>Rodrigo Ronald Gumucio Escobar</b></font></p>     <p align="center"><font size="2" face="Verdana"><a href="mailto:RGumucio@gmail.com">RGumucio@gmail.com</a></font></p>     <p align="center">&nbsp;</p>     <p align="center">&nbsp;</p> <hr align="center" noshade>     <p align="justify"><font size="2" face="Verdana"><b>Resumen: </b>Muchas veces    nos encontramos con problemas de combinatoria difíciles de resolver. Estos problemas    aparecen comúnmente no solo en el ámbito académico (por ejemplo en los dominios    de la inteligencia artificial, bases de datos, investigación operativa, etc.),    sino también en el ámbito de nuestra vida cotidiana (por ejemplo en las áreas    de planificación, programación de actividades, asignación de recursos, etc.).    </font></p>     <p align="justify"><font size="2" face="Verdana">Programando con restricciones    es posible en muchos casos encontrar, de manera altamente eficiente, soluciones    a muchos de estos problemas manejando su complejidad de manera simple e, incluso,    elegante. </font></p>     <p align="justify"><font size="2" face="Verdana">Este artículo es una introducción    a la programación con restricciones. Describe de manera sencilla una buena parte    de las técnicas y conceptos fundamentales que la sustentan a través de ejemplos    abordados de manera clara y concisa. Finaliza con un ejemplo práctico y concreto,    mostrando la resolución de un problema clásico usando C++.</font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana"><b>Palabras clave: </b>programación    declarativa, problema de combinatoria, restricción, programación con restricciones</font></p>     <p align="justify"><font size="2" face="Verdana"><b>Abstract: </b>Hard combinatorial    problems are ubiquitous in our society. They arise in many application domains    (e.g., artificial intelligence, data bases, operations research, etc.) and diverse    real life settings (e.g., scheduling, timetabling, resource allocation, etc.).</font></p>     <p align="justify"><font size="2" face="Verdana">Constraint Programming is a technique    that manages the complexity of these problems in a simple and even elegant manner.    It usually allows us to highly efficiently find solutions to many hard combinatorial    problems.</font></p>     <p align="justify"><font size="2" face="Verdana">This article is an introduction    to Constraint Programming. It describes many of its fundamental concepts and    techniques through clear and concise examples. It finishes with a practical    example, solving a classical problem, using C++.</font></p>     <p align="justify"><font size="2" face="Verdana"><b>Key words</b>: declarative    programming, combinatorial problem, constraint, constraint programming</font></p>   <hr align="center" noshade>     <p align="justify">&nbsp;</p>     <p align="justify">&nbsp;</p> <h2 align="justify"><font size="3" face="Verdana"><b>1&nbsp;&nbsp; Introducción</b></font></h2>     <p align="justify"><font size="2" face="Verdana">Resolver un problema programando    con restricciones se reduce a modelar dicho problema en términos de restricciones.<a href="#_ftn1" name="_ftnref1" title="">[1]</a> Como es habitual en la programación declarativa,    no es necesario describir paso a paso el conjunto de instrucciones que producirán    una solución, basta con describir el problema (es decir, detallar las características    de su solución sin conocerla). </font></p>     <p align="justify"><font size="2" face="Verdana">Las tecnologías basadas en restricciones,    entre ellas la programación con restricciones y la búsqueda local basada en    restricciones, se ocupan principalmente de proveer los mecanismos internos que    permitirán a los lenguajes de programación declarativa encontrar eficientemente    soluciones a los problemas expresados en términos de restricciones. </font></p>     <p align="justify"><font size="2" face="Verdana">Los problemas que pueden ser    expresados en términos de restricciones, particularmente problemas de combinatoria,    son llamados <em>problemas de restricciones</em> y para ser resueltos requieren    que todas sus restricciones sean cumplidas y, opcionalmente, que el costo (o    beneficio) sea minimizado (o maximizado). </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">Informalmente, una <em>restricción</em>    es una secuencia de variables junto con las combinaciones de valores permitidas    para dicha secuencia. Las tecnologías basadas en restricciones calculan soluciones    a problemas de restricciones razonando en torno a las restricciones que definen    el problema, las variables sobre las cuales las restricciones han sido definidas,    y los dominios finitos (es decir, los posibles valores) de estas variables.    </font></p>     <p align="justify"><font size="2" face="Verdana">La programación con restricciones    es una <em>técnica general</em> para resolver problemas de restricciones. Como    tal, dado cualquier problema modelado con restricciones, se ocupa primero de    reducir el espacio de posibles soluciones y, luego, de ejecutar métodos específicos    de búsqueda. </font></p> <h2 align="justify"><font size="2" face="Verdana"><a></a></font></h2> <h2 align="justify">&nbsp;</h2> <h2 align="justify"><font size="3" face="Verdana"><b>2&nbsp;&nbsp; Modelado</b></font></h2>     <p align="justify"><font size="2" face="Verdana">Un buen ejemplo de problema de    restricciones es el rompecabezas Sudoku:<a href="#_ftn2" name="_ftnref2" title="">[2]</a></font></p>     <p align="justify"><font size="2" face="Verdana">Colocar dígitos (excluyendo el    cero) en una tabla de dimensiones <img border=0 width=33 height=20 src="/img/revistas/ran/v5n1/v5n1a04-01.gif">, compuesta por <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-02.gif"> bloques adyacentes de dimensiones <img border=0 width=32 height=20 src="/img/revistas/ran/v5n1/v5n1a04-03.gif">, de manera que (en la tabla) cada columna,    fila, y bloque, contenga todos los dígitos del uno al nueve sin repetición.</font></p>     <p align="justify"><font size="2" face="Verdana">Dado que solo es posible escoger    dígitos del <img border=0 width=9 height=17 src="/img/revistas/ran/v5n1/v5n1a04-04.gif"> al <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-02.gif">, este problema puede ser modelado    estableciendo 27 restricciones: para cada fila, columna, y bloque, se establece    que todos sus dígitos deben ser diferentes. Si las 27 restricciones se cumplen,    el problema está resuelto. </font></p>     <p align="justify"><font size="2" face="Verdana"><b>Definición 2.1. </b>(Restricción    [2])<b>. </b><i>Dada una secuencia finita </i><img border=0 width=18 height=18 src="/img/revistas/ran/v5n1/v5n1a04-05.gif"><i>de </i><img border=0 width=42 height=20 src="/img/revistas/ran/v5n1/v5n1a04-06.gif"><i>variables </i><img border=0 width=69 height=27 src="/img/revistas/ran/v5n1/v5n1a04-07.gif"><i>con dominios </i><img border=0 width=76 height=27 src="/img/revistas/ran/v5n1/v5n1a04-08.gif"><i>, de manera que cada variable </i><img border=0 width=17 height=24 src="/img/revistas/ran/v5n1/v5n1a04-09.gif"><i>toma valores en </i><img border=0 width=22 height=24 src="/img/revistas/ran/v5n1/v5n1a04-10.gif"><i>. Una restricción </i><img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif"><i>en </i><img border=0 width=18 height=18 src="/img/revistas/ran/v5n1/v5n1a04-05.gif"><i>es un subconjunto de</i><img border=0 width=81 height=24 src="/img/revistas/ran/v5n1/v5n1a04-12.gif"><i>.</i></font></p>     <p align="justify"><font size="2" face="Verdana"><i>La secuencia de variables    <img border=0 width=71 height=26 src="/img/revistas/ran/v5n1/v5n1a04-13.gif">sobre la cual está    definida <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif">se denota <img border=0 width=49 height=22 src="/img/revistas/ran/v5n1/v5n1a04-14.gif">, y se dice que una secuencia de valores <img border=0 width=68 height=26 src="/img/revistas/ran/v5n1/v5n1a04-15.gif"> cumple la restricción <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif">si    y solamente si <img border=0 width=91 height=26 src="/img/revistas/ran/v5n1/v5n1a04-16.gif">.</i></font></p>     <p align="justify"><font size="2" face="Verdana">Un ejemplo de restricción (útil    para modelar el problema del rompecabezas Sudoku) es <img border=0 width=180 height=25 src="/img/revistas/ran/v5n1/v5n1a04-17.gif"> [3], definida sobre    una secuencia <img border=0 width=68 height=26 src="/img/revistas/ran/v5n1/v5n1a04-18.gif"> de <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-19.gif"> variables    de tipo entero, que se cumple si y solamente si cada par de variables enteras    <img border=0 width=17 height=24 src="/img/revistas/ran/v5n1/v5n1a04-09.gif"> y <img border=0 width=20 height=25 src="/img/revistas/ran/v5n1/v5n1a04-20.gif">toma    valores diferentes para <img border=0 width=34 height=22 src="/img/revistas/ran/v5n1/v5n1a04-21.gif"> (con <img border=0 width=72 height=22 src="/img/revistas/ran/v5n1/v5n1a04-22.gif">). </font></p>     <p align="justify"><font size="2" face="Verdana">De hecho, esta restricción es    un ejemplo de <em>restricción global</em> ya que puede ser definida en un número    variable <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> (no fijo) de variables.    La programación con restricciones le debe gran parte de su éxito al descubrimiento    de las restricciones globales y por tanto es muy importante entenderlas. </font></p>     <p align="justify"><font size="2" face="Verdana"><b>Definición 2.2. </b>(Restricción    global)<b>. </b><i>Una restricción global, denotada <img border=0 width=24 height=25 src="/img/revistas/ran/v5n1/v5n1a04-24.gif">, es una restricción <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif">cuyo número de variables (sobre la cual    está definida) es especificado por el parámetro <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif">(con <img border=0 width=83 height=22 src="/img/revistas/ran/v5n1/v5n1a04-25.gif">).</i></font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">Modelando un problema, típicamente,    uno encuentra que las restricciones globales pueden ser expresadas de manera    alternativa como la conjunción de varias restricciones no globales (definidas    en un número fijo de variables). Sin embargo, las restricciones globales juegan    un papel importante en la búsqueda de soluciones porque traducen de mejor manera    la estructura del problema y logran que el proceso de resolución sea <em>mucho</em>    más eficiente. En consecuencia, el modelado usando restricciones globales es    altamente recomendado. </font></p>     <p align="justify"><font size="2" face="Verdana">Por ejemplo, es posible exigir    que tres variables tomen valores distintos usando una única restricción <img border=0 width=120 height=25 src="/img/revistas/ran/v5n1/v5n1a04-26.gif">,    pero también, de manera alternativa, usando tres restricciones no globales <img border=0 width=89 height=22 src="/img/revistas/ran/v5n1/v5n1a04-27.gif">. Una restricción (no global) <img border=0 width=119 height=22 src="/img/revistas/ran/v5n1/v5n1a04-28.gif">, definida en dos variables, se cumple si y solamente    si el par de variables enteras <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif">e<img border=0 width=15 height=22 src="/img/revistas/ran/v5n1/v5n1a04-30.gif"> toman    valores distintos. </font></p>     <p align="justify"><font size="2" face="Verdana">La programación con restricciones,    como veremos más adelante, intenta encontrar soluciones a problemas de restricciones    reduciendo el tamaño de los dominios de las variables (razonando sobre estos    usando las restricciones establecidas) hasta que todas las restricciones sean    cumplidas o hasta determinar que no existe ninguna solución. </font></p>     <p align="justify"><font size="2" face="Verdana">Sean tres variables <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif">,    <img border=0 width=15 height=22 src="/img/revistas/ran/v5n1/v5n1a04-30.gif">, y <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-31.gif">,    con dominios <img border=0 width=36 height=22 src="/img/revistas/ran/v5n1/v5n1a04-32.gif">, <img border=0 width=36 height=22 src="/img/revistas/ran/v5n1/v5n1a04-32.gif">, y <img border=0 width=47 height=22 src="/img/revistas/ran/v5n1/v5n1a04-33.gif">,    respectivamente. Usando las <em>tres</em> restricciones <img border=0 width=119 height=22 src="/img/revistas/ran/v5n1/v5n1a04-28.gif">, <img border=0 width=117 height=22 src="/img/revistas/ran/v5n1/v5n1a04-34.gif">, y <img border=0 width=117 height=22 src="/img/revistas/ran/v5n1/v5n1a04-35.gif">,    no es posible inferir nada acerca de la solución (por lo que es necesario recurrir    a una búsqueda). Al contrario, dadas las mismas tres variables, con los mismos    dominios, y <em>una sola</em> restricción <img border=0 width=160 height=25 src="/img/revistas/ran/v5n1/v5n1a04-36.gif">, es posible inferir que una solución existe    y además que <img border=0 width=36 height=20 src="/img/revistas/ran/v5n1/v5n1a04-37.gif">. </font></p>     <p align="justify"><font size="2" face="Verdana"><b>Definición 2.3. </b>(Problema    de restricciones)<b>. </b><i>Un problema de restricciones es una tripleta </i><img border=0 width=57 height=26 src="/img/revistas/ran/v5n1/v5n1a04-38.gif"><i>con</i></font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i><img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-39.gif">un conjunto finito de variables,</i></font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i><img border=0 width=17 height=18 src="/img/revistas/ran/v5n1/v5n1a04-40.gif">un conjunto finito de valores posibles    para las variables en <img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-39.gif">,    es decir, su dominio, y</i></font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i><img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-41.gif">un conjunto finito de restricciones.</i></font></p>     <p align="justify"><font size="2" face="Verdana">Cada una de las restricciones    <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif"> en <img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-41.gif"> es    definida de manera tal que <img border=0 width=74 height=22 src="/img/revistas/ran/v5n1/v5n1a04-42.gif">, y todas las variables en <img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-39.gif">comparten (inicialmente) el mismo dominio <img border=0 width=17 height=18 src="/img/revistas/ran/v5n1/v5n1a04-40.gif">[1].<a href="#_ftn3" name="_ftnref3" title="">[3]</a></font></p>     <p align="justify">&nbsp;</p>     ]]></body>
<body><![CDATA[<p align=center><font size="2" face="Verdana"><b><img border=0 width=400 height=234 id="Picture 226" src="/img/revistas/ran/v5n1/v5n1a04-43.gif" alt=figura></b></font></p>     <p align="center"><font size="2" face="Verdana"><b>Figura 1:&nbsp;&nbsp; </b>Modelo    para el problema Sudoku (izquierda). Asignación inicial de algunas variables    para dar lugar a una instancia sencilla de este problema (derecha). </font></p>     <p align="justify"><font size="2" face="Verdana">El problema Sudoku (ver Figura    1), descrito al inicio de esta sección, puede entonces ser expresado usando    una matriz de <img border=0 width=29 height=20 src="/img/revistas/ran/v5n1/v5n1a04-44.gif"> variables enteras en <img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-39.gif"> con dominios <img border=0 width=68 height=22 src="/img/revistas/ran/v5n1/v5n1a04-45.gif">, y <img border=0 width=56 height=20 src="/img/revistas/ran/v5n1/v5n1a04-46.gif"> restricciones    <img border=0 width=120 height=25 src="/img/revistas/ran/v5n1/v5n1a04-47.gif">en <img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-41.gif">.    De manera que el problema de restricciones para Sudoku está dado entonces por    la tripleta <img border=0 width=56 height=26 src="/img/revistas/ran/v5n1/v5n1a04-48.gif"> con: </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <img border=0 width=149 height=25 src="/img/revistas/ran/v5n1/v5n1a04-49.gif"></font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <img border=0 width=86 height=22 src="/img/revistas/ran/v5n1/v5n1a04-50.gif"></font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <img border=0 width=368 height=92 src="/img/revistas/ran/v5n1/v5n1a04-51.gif"></font></p>     <p align="justify"><font size="2" face="Verdana">¿Podrías definir el problema    de las 8-reinas como problema de restricciones?</font></p>     <p align="justify"><font size="2" face="Verdana">Colocar, en un tablero de dimensiones    <img border=0 width=32 height=20 src="/img/revistas/ran/v5n1/v5n1a04-52.gif"> , ocho reinas de manera que ninguna de ellas ataque    a otra bajo las reglas del ajedrez.</font></p>     <p align="justify"><font size="2" face="Verdana">Si bien es posible modelar este    problema usando también solamente restricciones <img border=0 width=117 height=25 src="/img/revistas/ran/v5n1/v5n1a04-53.gif">, existen, por supuesto,    muchas otras restricciones (muy útiles e interesantes) ya diseñadas e implementadas    que permiten modelar un gran número de problemas.<a href="#_ftn4" name="_ftnref4" title="">[4]</a></font></p> <h2 align="justify">&nbsp;</h2> <h2 align="justify">&nbsp;</h2> <h2 align="justify"><font size="3" face="Verdana"><b>3&nbsp;&nbsp; Reducción por    propagación</b></font></h2>     <p align="justify"><font size="2" face="Verdana">La programación con restricciones    permite encontrar soluciones a problemas de restricciones realizando una búsqueda    inteligente que de ser necesario (por ejemplo en problemas de optimización)    llega a explorar (implícitamente) el espacio de posibles soluciones en su totalidad.    </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">La forma ingenua de llevar a    cabo una búsqueda completa, generando todas las posibles soluciones del problema    en cuestión, no es práctico ni factible porque el espacio de posibles soluciones    puede ser tan grande como podamos imaginar. La belleza de la programación con    restricciones reside en su habilidad de, en la mayoría de los casos, evitar    generar todas las posibles soluciones por medio de la reducción por propagación    [1]. </font></p>     <p align="justify"><font size="2" face="Verdana">Los algoritmos que se ocupan    de reducir el espacio de posibles soluciones son usualmente llamados <em>algoritmos    de reducción por propagación</em> [2], y el denominador común de estos es el    aprovechamiento de condiciones de necesidad para reconocer valores en los dominios    de las variables que, si fueran asignados, violarían alguna restricción [1].    El único propósito de un algoritmo de reducción por propagación es entonces    simplificar el problema que está siendo resuelto reduciéndolo a otro equivalente    pero más pequeño. </font></p>     <p align=center><font size="2" face="Verdana"><img border=0 width=442 height=462 id="Picture 227" src="/img/revistas/ran/v5n1/v5n1a04-54.jpg" alt=figura></font></p>     <p align="center"><font size="2" face="Verdana"><a name="Ref_x1-30012"></a><b>Figura    2:&nbsp;&nbsp; </b>Resolución de una instancia del problema Sudoku usando solamente    reducción por propagación. </font></p>     <p align="justify"><font size="2" face="Verdana">Un concepto muy importante en    los algoritmos de reducción por propagación es el de <em>consistencia</em>.    Estos algoritmos reducen el tamaño de los dominios de las variables de acuerdo    a un <em>nivel de consistencia</em>. Por ejemplo, tomemos nuevamente el problema    clásico analizado como ejemplo en la sección anterior: sean tres variables <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif">,    <img border=0 width=15 height=22 src="/img/revistas/ran/v5n1/v5n1a04-30.gif">, y <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-31.gif">,    con dominios <img border=0 width=36 height=22 src="/img/revistas/ran/v5n1/v5n1a04-32.gif">, <img border=0 width=36 height=22 src="/img/revistas/ran/v5n1/v5n1a04-32.gif">, y <img border=0 width=47 height=22 src="/img/revistas/ran/v5n1/v5n1a04-33.gif"> respectivamente.</font></p>     <p align="justify"><font size="2" face="Verdana">Si <img border=0 width=34 height=18 src="/img/revistas/ran/v5n1/v5n1a04-55.gif"> o <img border=0 width=38 height=18 src="/img/revistas/ran/v5n1/v5n1a04-56.gif">, entonces sería imposible asignar valores diferentes    a <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif">e<img border=0 width=15 height=22 src="/img/revistas/ran/v5n1/v5n1a04-30.gif">, y por tanto no existiría ninguna solución. Esto    significa que el dominio de <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-31.gif"> puede    ser reducido a <img border=0 width=25 height=22 src="/img/revistas/ran/v5n1/v5n1a04-57.gif">. Sin embargo, considerando las    tres restricciones <img border=0 width=89 height=22 src="/img/revistas/ran/v5n1/v5n1a04-27.gif">, <img border=0 width=38 height=22 src="/img/revistas/ran/v5n1/v5n1a04-58.gif">, <img border=0 width=38 height=22 src="/img/revistas/ran/v5n1/v5n1a04-59.gif">,    y <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-60.gif">, no fue posible hacer esta inferencia. Al contrario,    usando una única restricción global <img border=0 width=120 height=25 src="/img/revistas/ran/v5n1/v5n1a04-61.gif">, sí fue posible hacer esta inferencia. Por tanto,    decimos que el nivel de consistencia de <img border=0 width=120 height=25 src="/img/revistas/ran/v5n1/v5n1a04-61.gif"> puede ser más alto que el nivel de consistencia usando    3 restricciones <img border=0 width=89 height=22 src="/img/revistas/ran/v5n1/v5n1a04-27.gif">. </font></p>     <p align="justify"><font size="2" face="Verdana">En el nivel más alto de consistencia,    se garantiza que todos los valores que no participan de ninguna solución sean    eliminados del dominio de las variables correspondientes. Con los niveles de    consistencia más bajos simplemente se realiza alguna reducción en los dominios    cuando una variable es asignada (es decir cuando la cardinalidad de alguna variable    es reducida a 1). </font></p>     <p align="justify"><font size="2" face="Verdana">Por ejemplo, usando un nivel    de consistencia denominado <em>comprobación de coherencia</em>, para una restricción    <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif">, toda vez que un valor <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-62.gif"> es asignado a una variable <img border=0 width=17 height=24 src="/img/revistas/ran/v5n1/v5n1a04-09.gif">, todos los valores en los dominios de las otras variables    en <img border=0 width=49 height=22 src="/img/revistas/ran/v5n1/v5n1a04-14.gif"> que entran en conflicto    con la restricción <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif"> (debido    a que <img border=0 width=42 height=24 src="/img/revistas/ran/v5n1/v5n1a04-63.gif">) son eliminados. Por ejemplo, si <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif"> es <img border=0 width=160 height=25 src="/img/revistas/ran/v5n1/v5n1a04-64.gif"> con <img border=0 width=60 height=22 src="/img/revistas/ran/v5n1/v5n1a04-65.gif">,    <img border=0 width=72 height=22 src="/img/revistas/ran/v5n1/v5n1a04-66.gif"> y <img border=0 width=60 height=22 src="/img/revistas/ran/v5n1/v5n1a04-67.gif">;    si se asigna el valor <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-68.gif"> a la variable <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif">, entonces el algoritmo de reducción por propagación    con un nivel de consistencia de comprobación de coherencia devuelve <img border=0 width=49 height=22 src="/img/revistas/ran/v5n1/v5n1a04-69.gif">, <img border=0 width=60 height=22 src="/img/revistas/ran/v5n1/v5n1a04-70.gif"> y <img border=0 width=49 height=22 src="/img/revistas/ran/v5n1/v5n1a04-71.gif">.    </font></p>     <p align="justify"><font size="2" face="Verdana">En la programación con restricciones,    las restricciones se implementan a través de <em>propagadores</em>. Un propagador    es una función <img border=0 width=99 height=22 src="/img/revistas/ran/v5n1/v5n1a04-72.gif"> que lleva a cabo reducción    por propagación [5]. Por tanto, los propagadores son funciones que se aplican    a un conjunto de los dominios de las variables en <img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-39.gif">, denotado <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif">, y básicamente lo que hacen es reducir los dominios    de estas variables eliminando los valores que no pueden ser asignados de acuerdo    con la restricción que implementan. </font></p>     <p align="justify"><font size="2" face="Verdana">Los propagadores deben cumplir,    fundamentalmente, tres propiedades: </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    Nunca añaden valores a los dominios de las variables. Es decir, solo les está    permitido eliminar ningún, uno, o varios valores. </font></p>     <p align="justify"><font size="2" face="Verdana">2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    Nunca eliminan soluciones de la restricción que implementan. Es decir, solo    les está permitido eliminar valores de los dominios de las variables siempre    y cuando ninguna solución sea eliminada en el acto. </font></p>     <p align="justify"><font size="2" face="Verdana">3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    La función <img border=0 width=99 height=22 src="/img/revistas/ran/v5n1/v5n1a04-72.gif"> que lleva a cabo reducción por    propagación es monotónica.</font></p>     <p align="justify"><font size="2" face="Verdana">Si en algún momento alguno de    los dominios contenidos en <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"> es vacío, decimos que <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"> ha    fallado, y que por tanto no fue posible encontrar una solución. Cuando ya no    es posible realizar más reducción por propagación y todos los dominios contenidos    en <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"> tienen cardinalidad uno, hemos encontrado una solución.    </font></p>     <p align="justify"><font size="2" face="Verdana">Dado un problema de restricciones    <img border=0 width=56 height=26 src="/img/revistas/ran/v5n1/v5n1a04-48.gif">, donde el conjunto de propagadores que implementan    las restricciones en <img border=0 width=16 height=20 src="/img/revistas/ran/v5n1/v5n1a04-41.gif"> es <img border=0 width=16 height=18 src="/img/revistas/ran/v5n1/v5n1a04-74.gif">, y el conjunto de dominios iniciales de las variables    es <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif">, el algoritmo básico    de reducción por propagación es el mostrado en la Figura 3. </font></p>     <p align="center"><font size="2" face="Verdana"><img border=0 width=173 height=26 src="/img/revistas/ran/v5n1/v5n1a04-75.gif"></font></p>     <p align="center"><font size="2" face="Verdana">1 mientras exista<img border=0 width=42 height=22 src="/img/revistas/ran/v5n1/v5n1a04-76.gif">con<img border=0 width=55 height=22 src="/img/revistas/ran/v5n1/v5n1a04-77.gif"></font></p>     <p align="center"><font size="2" face="Verdana">2     <img border=0 width=61 height=22 src="/img/revistas/ran/v5n1/v5n1a04-78.gif"></font></p>     <p align="center"><font size="2" face="Verdana">3 retornar<img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"></font></p>     <p align="center"><font size="2" face="Verdana"><b>Figura 3:&nbsp;&nbsp; </b>Algoritmo    básico de reducción por propagación. </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">Las tres propiedades fundamentales    de este algoritmo son: </font></p>     <p align="justify"><font size="2" face="Verdana">1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    El algoritmo siempre termina. </font></p>     <p align="justify"><font size="2" face="Verdana">2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    El algoritmo no elimina ninguna solución. </font></p>     <p align="justify"><font size="2" face="Verdana">3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    Si <img border=0 width=200 height=26 src="/img/revistas/ran/v5n1/v5n1a04-79.gif">, entonces <img border=0 width=15 height=18 src="/img/revistas/ran/v5n1/v5n1a04-80.gif"> es el punto fijo simultáneo más grande (o más débil)    de todos los propagadores en <img border=0 width=16 height=18 src="/img/revistas/ran/v5n1/v5n1a04-74.gif">.</font></p>     <p align="justify"><font size="2" face="Verdana">Una demostración de que estas    propiedades se cumplen puede ser encontrada en [5]: el algoritmo termina porque    los propagadores nunca añaden valores a los dominios de las variables, y las    otras dos propiedades son consecuencias directas de las propiedades individuales    de los propagadores. </font></p>     <p align="justify"><font size="2" face="Verdana">Evidentemente, el algoritmo mostrado    en la Figura 3 es muy simple y puede ser considerablemente optimizado (ver [5]).    Una consecuencia importante de estas propiedades es que los propagadores pueden    ser invocados en cualquier orden, es decir, el orden en el cual los propagadores    son aplicados no afecta el resultado de la reducción por propagación. </font></p>     <p align="justify"><font size="2" face="Verdana">En la Figura 2 se ilustra el    proceso de resolver (mecánicamente) la instancia del problema Sudoku presentado    en la Figura 1, donde algunas variables ya estaban asignadas en <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif">.    Como el ejemplo muestra, algunas veces es posible encontrar soluciones usando    solamente reducción por propagación. Sin embargo, en la mayoría de los casos    la reducción por propagación no es suficiente por sí sola y por tanto es necesario    recurrir a algoritmos de búsqueda. </font></p>     <p align="justify"><font size="2" face="Verdana">¿Podrías encontrar una solución    al problema de las 8-reinas usando solamente la reducción por propagación? </font></p> <h2 align="justify">&nbsp;</h2> <h2 align="justify">&nbsp;</h2> <h2 align="justify"><font size="3" face="Verdana"><b>4&nbsp;&nbsp; Búsqueda sistemática</b></font></h2>     <p align="justify"><font size="2" face="Verdana">En la programación con restricciones,    toda vez que la reducción por propagación no es suficiente por sí sola, para    encontrar una solución, se recurre a algoritmos de búsqueda sistemática. Estos    algoritmos, sin embargo, no están de ninguna manera libres de la reducción por    propagación ya que esta se ejecuta después de cada paso durante la búsqueda.    </font></p>     <p align="justify"><font size="2" face="Verdana">Una vez que se determina que    la reducción por propagación no puede encontrar una solución por sí misma, se    empieza a buscar la solución dividiendo (o partiendo) el problema en otros subproblemas    más pequeños o simples. La reducción por propagación es ejecutada, luego, en    cada uno de estos subproblemas. El patrón general de búsqueda consiste, por    tanto, en el uso alternado de la subdivisión del problema y la reducción por    propagación [2]. </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">Típicamente un algoritmo de búsqueda    requiere tanto de un árbol (de búsqueda) como de un algoritmo de exploración.    En la programación con restricciones, los llamados <em>ramificadores </em>están    a cargo de definir el árbol de búsqueda mientras que los algoritmos de exploración    construyen, incrementalmente, el árbol hasta que una solución (o todas las soluciones,    o la solución óptima) sea encontrada. Los algoritmos de exploración no siempre    toman decisiones correctas (que llevan inmediatamente a encontrar soluciones),    algunas veces cometen errores de los cuales necesitan aprender para luego retroceder    y tomar otra (mejor) decisión. </font></p>     <p align="justify"><font size="2" face="Verdana">El propósito de los ramificadores    es tomar decisiones informadas, de acuerdo a alguna heurística, para sugerir    nuevas restricciones que permitan dividir el problema en subproblemas de manera    inteligente. Usualmente, una heurística requiere que el ramificador tenga acceso,    por lo menos, al conjunto de dominios de las variables (por ejemplo, para determinar    cuál es la variable con el dominio más pequeño) y el conjunto de propagadores    (por ejemplo, para determinar cuál es la variable sobre la cual está defina    la mayor cantidad de restricciones). </font></p>     <p align="justify"><font size="2" face="Verdana">Por ejemplo, un ramificador,    con una heurística simple, seleccionaría de un problema de restricciones una    variable <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif"> junto con un valor <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-62.gif"> de su dominio (de cardinalidad mayor a uno) y sugeriría    la restricción <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-81.gif"> para    dividir el problema en dos subproblemas: uno obtenido añadiendo la restricción    <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-81.gif"> , y otro obtenido añadiendo la restricción <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-82.gif"> . Esta sencilla estrategia usualmente se    optimiza seleccionando la variable con el dominio más pequeño y toma el nombre    de heurística de <em>fallar pronto</em>. </font></p>     <p align="justify"><font size="2" face="Verdana">Un ramificador debe mostrar un    buen comportamiento de manera que [5]: </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    el árbol de búsqueda se mantenga finito, </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    ninguna solución sea perdida durante la búsqueda, y </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    las soluciones no se repitan.</font></p>     <p align="justify"><font size="2" face="Verdana"><b>Definición 4.1. </b>(Ramificador)<b>.    </b><i>Un ramificador es una función <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-83.gif">que toma como entrada    un conjunto de propagadores <img border=0 width=16 height=22 src="/img/revistas/ran/v5n1/v5n1a04-84.gif"> junto    con el conjunto de los dominios de las variables en cuestión <img border=0 width=13 height=15 src="/img/revistas/ran/v5n1/v5n1a04-85.gif">, y produce una tupla <img border=0 width=68 height=26 src="/img/revistas/ran/v5n1/v5n1a04-86.gif"> de conjuntos de propagadores <img border=0 width=20 height=24 src="/img/revistas/ran/v5n1/v5n1a04-87.gif">.</i></font></p>     <p align="justify"><font size="2" face="Verdana">Asumamos que <img border=0 width=218 height=26 src="/img/revistas/ran/v5n1/v5n1a04-88.gif"> para <img border=0 width=56 height=20 src="/img/revistas/ran/v5n1/v5n1a04-89.gif"> y <img border=0 width=185 height=26 src="/img/revistas/ran/v5n1/v5n1a04-90.gif">.    Entonces, un ramificador <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-83.gif"> debe ser: </font></p>     <p align="justify"><font size="2" face="Verdana">1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    completo, es decir, <img border=0 width=69 height=36 src="/img/revistas/ran/v5n1/v5n1a04-91.gif">,</font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    disjunto, es decir, <img border=0 width=81 height=25 src="/img/revistas/ran/v5n1/v5n1a04-92.gif"> para <img border=0 width=67 height=22 src="/img/revistas/ran/v5n1/v5n1a04-93.gif"> con <img border=0 width=34 height=22 src="/img/revistas/ran/v5n1/v5n1a04-94.gif">,    y </font></p>     <p align="justify"><font size="2" face="Verdana">3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    decreciente, es decir, los elementos de <img border=0 width=206 height=26 src="/img/revistas/ran/v5n1/v5n1a04-95.gif"> deben tener menor o    igual cardinalidad a los elementos de <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif">.</font></p>     <p align="justify"><font size="2" face="Verdana">El cumplimento de estas propiedades    aseguran que un ramificador <img border=0 width=13 height=19 src="/img/revistas/ran/v5n1/v5n1a04-96.gif"> tenga un buen comportamiento. La completitud    garantiza que ninguna solución es perdida; la disjunción garantiza que ninguna    solución aparezca repetida en el árbol; y la propiedad de ser decreciente garantiza    que las restricciones sugeridas provocarán reducción por propagación. De esta    manera el árbol será finito [5]. </font></p>     <p align="justify"><font size="2" face="Verdana"><b>Definición 4.2. </b>(Árbol    de búsqueda)<b>. </b><i>Un árbol de búsqueda para un problema de restricciones<img border=0 width=56 height=26 src="/img/revistas/ran/v5n1/v5n1a04-97.gif"> y    un ramificador <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-83.gif">, es un árbol cuyos nodos son nombrados con pares    <img border=0 width=38 height=26 src="/img/revistas/ran/v5n1/v5n1a04-98.gif"> donde <img border=0 width=16 height=22 src="/img/revistas/ran/v5n1/v5n1a04-84.gif"> es    un conjunto de propagadores, y <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif">el resultado de ejecutar la reducción por propagación    con respecto a <img border=0 width=16 height=22 src="/img/revistas/ran/v5n1/v5n1a04-84.gif">.    De ahí que</i>:</font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i>la </i><em>raíz </em><i>del árbol es nombrada </i><img border=0 width=38 height=26 src="/img/revistas/ran/v5n1/v5n1a04-99.gif"><i>, donde </i><img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"> <i>es obtenido de </i><img border=0 width=200 height=26 src="/img/revistas/ran/v5n1/v5n1a04-100.gif"></font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i>para cualquier </i><em>hoja</em><img border=0 width=38 height=26 src="/img/revistas/ran/v5n1/v5n1a04-98.gif"><i>,</i></font></p>     <p align="justify"><font size="2" face="Verdana">o&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i>podemos decir que </i><img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"><i>ha    fallado, y por tanto que el nodo hoja ha fallado; o bien</i></font></p>     <p align="justify"><font size="2" face="Verdana">o&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i>podemos decir que el nodo hoja ha sido resuelto cuando </i><img border=0 width=79 height=26 src="/img/revistas/ran/v5n1/v5n1a04-101.gif"><i>;</i></font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <i>finalmente para cualquier nodo interno </i><img border=0 width=38 height=26 src="/img/revistas/ran/v5n1/v5n1a04-98.gif"><i>, </i><img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"> <i>no    ha fallado y </i><img border=0 width=128 height=26 src="/img/revistas/ran/v5n1/v5n1a04-102.gif"><i>con </i><img border=0 width=33 height=20 src="/img/revistas/ran/v5n1/v5n1a04-103.gif"><i>. Por tanto, un nodo interno tiene </i><img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> <i>nodos hijos, donde el </i><img border=0 width=9 height=20 src="/img/revistas/ran/v5n1/v5n1a04-104.gif"><i>-ésimo nodo es nombrado, con </i><img border=0 width=67 height=22 src="/img/revistas/ran/v5n1/v5n1a04-105.gif"><i>,</i> <img border=0 width=271 height=29 src="/img/revistas/ran/v5n1/v5n1a04-106.gif"><i>.</i></font></p>     <p align="justify"><font size="2" face="Verdana">Por construcción, para un nodo    <img border=0 width=38 height=26 src="/img/revistas/ran/v5n1/v5n1a04-98.gif"> en el árbol de    búsqueda, <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-73.gif"> es un punto fijo simultáneo de    <img border=0 width=16 height=22 src="/img/revistas/ran/v5n1/v5n1a04-84.gif">. También debido a la propiedad decreciente    de los ramificadores, dados dos nodos <img border=0 width=49 height=26 src="/img/revistas/ran/v5n1/v5n1a04-107.gif"> y <img border=0 width=52 height=26 src="/img/revistas/ran/v5n1/v5n1a04-108.gif">,    si el primero está en la misma rama que el segundo, pero más abajo, entonces    los elementos de <img border=0 width=16 height=22 src="/img/revistas/ran/v5n1/v5n1a04-109.gif"> deben tener menor o igual cardinalidad    a los elementos de <img border=0 width=18 height=22 src="/img/revistas/ran/v5n1/v5n1a04-110.gif"> [5].    </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">Una solución al problema de restricciones    estará dada por un nodo hoja donde todos los dominios de todas las variables    tengan cardinalidad uno, es decir, donde todas las variables hayan sido asignadas    de manera que todas las restricciones se cumplan. </font></p>     <p align="justify"><font size="2" face="Verdana">Dado un ramificador, la exploración    de un árbol es el proceso de construir el árbol hasta que la primera solución    sea encontrada, un cierto número de soluciones sean encontradas, todas las soluciones    sean encontradas, o incluso hasta que ninguna o la más óptima solución (con    respecto a una medida de calidad) sea encontrada. </font></p>     <p align="center"><img src="/img/revistas/ran/v5n1/v5n1a04-159.gif" width="487" height="437"></p>     <p align="justify"><font size="2" face="Verdana">Dos típicas estrategias de exploración    son la búsqueda en profundidad y la búsqueda por ramificación y acotación. La    Figura 4 muestra el algoritmo para la búsqueda en profundidad [5] donde, por    simplicidad, restringimos nuestra atención a los ramificadores que retornan    o una tupla vacía <img border=0 width=22 height=26 src="/img/revistas/ran/v5n1/v5n1a04-114.gif"> o un par <img border=0 width=54 height=26 src="/img/revistas/ran/v5n1/v5n1a04-119.gif"> (en lugar de una tupla de <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> elementos). </font></p>     <p align=center><font size="2" face="Verdana"><b><img border=0 width=362 height=141 id="Picture 244" src="/img/revistas/ran/v5n1/v5n1a04-120.jpg" alt=figura></b></font></p>     <p align="center"><font size="2" face="Verdana"><b>Figura 5:&nbsp;&nbsp; </b>Ejemplo    de búsqueda en profundidad. </font></p>     <p align="justify"><font size="2" face="Verdana">Por ejemplo, consideremos un    problema de restricciones con <img border=0 width=67 height=22 src="/img/revistas/ran/v5n1/v5n1a04-121.gif">, <img border=0 width=83 height=22 src="/img/revistas/ran/v5n1/v5n1a04-122.gif">,    y <img border=0 width=156 height=22 src="/img/revistas/ran/v5n1/v5n1a04-123.gif">. La Figura 5 muestra el árbol de búsqueda para este    problema con la heurística simple descrita al inicio de esta sección. En el    árbol, un círculo representa un nodo con un dominio de cardinalidad mayor a    uno, un cuadrado representa un nodo que ha fallado y un diamante representa    un nodo resuelto. </font></p>     <p align="justify"><font size="2" face="Verdana">¿Podrías resolver el problema    de las 8-reinas usando (además de reducción por propagación) un ramificador    con heurística de <em>fallar pronto</em> y el algoritmo presentado en la Figura    4?</font></p>     <p align="justify"><font size="2" face="Verdana">En los problemas de optimización,    cuando se intenta buscar la mejor solución con respecto a una medida de calidad,    calcular todas las soluciones y luego seleccionar la que minimice el costo (o    maximice el beneficio) es impráctico puesto que en problemas difíciles de combinatoria,    el número de soluciones crece exponencialmente con el tamaño del problema. </font></p>     <p align="justify"><font size="2" face="Verdana">La búsqueda por ramificación    y acotación se usa para resolver tales problemas de optimización. Esta búsqueda    se realiza como una versión modificada de la búsqueda en profundidad mostrada    en la Figura 4. La idea es emplear la información ya obtenida para reducir considerablemente    el espacio de búsqueda de soluciones. </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">La información ya obtenida, con    respecto a la solución, es expresada en términos de restricciones: toda vez    que se encuentra una solución, una restricción adicional es añadida al modelo    exigiendo que cualquier otra solución encontrada debe ser mejor a las ya encontradas    anteriormente. Con esta restricción adicional, el árbol de búsqueda se vuelve    considerablemente más pequeño. </font></p>     <p align=center><font size="2" face="Verdana"><b><img border=0 width=349 height=273 id="Picture 245" src="/img/revistas/ran/v5n1/v5n1a04-124.jpg" alt=figura></b></font></p>     <p align="center"><font size="2" face="Verdana"><a name="Ref_x1-40066"></a><b>Figura    6:&nbsp;&nbsp; </b>Ejemplo de búsqueda por ramificación y acotación. </font></p>     <p align="justify"><font size="2" face="Verdana">Consideremos, por ejemplo, un    problema de restricciones con <img border=0 width=79 height=22 src="/img/revistas/ran/v5n1/v5n1a04-125.gif">, <img border=0 width=77 height=22 src="/img/revistas/ran/v5n1/v5n1a04-126.gif">,    y <img border=0 width=112 height=22 src="/img/revistas/ran/v5n1/v5n1a04-127.gif">. El objetivo es encontrar una solución con el valor    más grande posible para <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-31.gif">.    Nuevamente, usando la heurística simple descrita al inicio de esta sección,    la Figura 6 muestra el árbol de búsqueda para la solución óptima a este problema.    </font></p>     <p align="justify"><font size="2" face="Verdana">Para empezar, la primera solución    es encontrada usando la búsqueda en profundidad. El valor para <img border=0 width=13 height=18 src="/img/revistas/ran/v5n1/v5n1a04-31.gif"> en    esta solución es <img border=0 width=9 height=18 src="/img/revistas/ran/v5n1/v5n1a04-128.gif">, por tanto una nueva restricción    <img border=0 width=33 height=18 src="/img/revistas/ran/v5n1/v5n1a04-129.gif"> es añadida. Luego, el nodo 5    falla porque <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-130.gif"> reduce a <img border=0 width=33 height=18 src="/img/revistas/ran/v5n1/v5n1a04-131.gif">, y el nodo 3 reduce a <img border=0 width=38 height=18 src="/img/revistas/ran/v5n1/v5n1a04-132.gif"> . Luego, el nodo 3 se divide en dos nuevos: los    nodos 6 y 7. El nodo 6 es una nueva y mejor solución con <img border=0 width=38 height=18 src="/img/revistas/ran/v5n1/v5n1a04-132.gif">, por tanto la restricción <img border=0 width=38 height=18 src="/img/revistas/ran/v5n1/v5n1a04-133.gif"> es agregada al nodo 7 lo cual hace que falle. Finalmente,    la mejor solución es <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-134.gif">,    <img border=0 width=38 height=22 src="/img/revistas/ran/v5n1/v5n1a04-135.gif">, y <img border=0 width=38 height=18 src="/img/revistas/ran/v5n1/v5n1a04-132.gif"> .    Estos dos últimos ejemplos con sus respectivas figuras fueron tomados de [4].</font></p>     <p align="justify"><font size="2" face="Verdana">¿Podrías, tomando inspiración    del algoritmo presentado en la Figura 4, escribir el algoritmo correspondiente    a la búsqueda por ramificación y acotación? </font></p>     <p align="justify"><font size="2" face="Verdana">De esta manera, la programación    con restricciones resuelve problemas explorando (implícitamente) todo el espacio    de posibles soluciones, realizando una búsqueda de manera sistemática (aprendiendo    y retrocediendo cuando es necesario), dando lugar a un árbol de búsqueda donde    la reducción por propagación es ejecutada en cada nodo. </font></p> <h2 align="justify">&nbsp;</h2> <h2 align="justify">&nbsp;</h2> <h2 align="justify"><font size="3" face="Verdana"><b>5&nbsp;&nbsp; Un ejemplo    práctico</b></font></h2>     <p align="justify"><font size="2" face="Verdana">En esta sección se resuelve,    programando con restricciones, el problema de las <em>n-reinas</em>. La solución    es implementada en el lenguaje C++ usando la librería Gecode<a href="#_ftn5" name="_ftnref5" title="">[5]</a> (tanto el código fuente como las    explicaciones están basadas en las presentadas dentro la documentación de su    distribución).</font></p>     <p align="justify"><font size="2" face="Verdana">Generalizando la formulación    del problema de las 8-reinas presentado en la sección 2, el problema de las    n-reinas exige:</font></p>     <p align="justify"><font size="2" face="Verdana">Colocar, en un tablero de dimensiones    <img border=0 width=33 height=20 src="/img/revistas/ran/v5n1/v5n1a04-136.gif">, con <img border=0 width=36 height=20 src="/img/revistas/ran/v5n1/v5n1a04-137.gif">, <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> reinas    de manera que ninguna de ellas ataque a otra bajo las reglas del ajedrez.</font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">Las restricciones para modelar    este problema son: </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    ningún par de reinas debe ser colocada en la misma columna, </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    ningún par de reinas debe ser colocada en la misma fila, </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    ningún par de reinas debe ser colocada en la misma diagonal de arriba a abajo    de izquierda a derecha, y </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    ningún par de reinas debe ser colocada en la misma diagonal de arriba a abajo    de derecha a izquierda.</font></p>     <p align="justify"><font size="2" face="Verdana">Una posible representación de    este problema de restricciones usa <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> variables de tipo entero, <img border=0 width=57 height=24 src="/img/revistas/ran/v5n1/v5n1a04-138.gif">, cada una con dominio <img border=0 width=38 height=22 src="/img/revistas/ran/v5n1/v5n1a04-139.gif">[2], de manera que cada variable <img border=0 width=17 height=24 src="/img/revistas/ran/v5n1/v5n1a04-09.gif"> denota la posición, es decir la fila, de la reina    colocada en la <img border=0 width=9 height=20 src="/img/revistas/ran/v5n1/v5n1a04-104.gif">-ésima columna del tablero.    </font></p>     <p align="justify"><font size="2" face="Verdana">Las restricciones pueden entonces    ser expresadas como: </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <img border=0 width=181 height=25 src="/img/revistas/ran/v5n1/v5n1a04-140.gif">, </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <img border=0 width=239 height=25 src="/img/revistas/ran/v5n1/v5n1a04-141.gif">,<a href="#_ftn6" name="_ftnref6" title="">[6]</a> y </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <img border=0 width=239 height=25 src="/img/revistas/ran/v5n1/v5n1a04-142.gif"> .</font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana">En esta representación, la restricción    de que ningún par de reinas debe ser colocada en la misma columna es implícita    (y por tanto está ausente de la anterior lista de restricciones). Puesto que    tenemos <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> reinas y <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> filas, y ningún par de reinas pueden convivir en    la misma columna, cada columna debe contener exactamente una reina. Consecuentemente,    una variable fue creada para cada columna, y los valores tomados por estas variables    representan la fila de la reina correspondiente. Por tanto, no es necesario    exigir explícitamente que ningún par de reinas se ataquen verticalmente. Una    restricción implícita, en este caso producida por la forma en que se modela    el problema, nunca será violada y es rígida en ese sentido. </font></p>     <p align="justify"><font size="2" face="Verdana">Con el objetivo de enfatizar    que el uso de restricciones globales es altamente recomendado, es oportuno hacer    notar que, en el modelo de este problema, se da preferencia al uso de restricciones    <img border=0 width=179 height=25 src="/img/revistas/ran/v5n1/v5n1a04-143.gif"> sobre el uso de conjunciones de <img border=0 width=63 height=42 src="/img/revistas/ran/v5n1/v5n1a04-144.gif"> restricciones    <img border=0 width=133 height=25 src="/img/revistas/ran/v5n1/v5n1a04-145.gif"> (una restricción <img border=0 width=133 height=25 src="/img/revistas/ran/v5n1/v5n1a04-145.gif"> para cada <img border=0 width=81 height=22 src="/img/revistas/ran/v5n1/v5n1a04-146.gif"> y <img border=0 width=80 height=22 src="/img/revistas/ran/v5n1/v5n1a04-147.gif">).</font></p>     <p align="justify"><font size="2" face="Verdana">Un modelo de un problema de restricciones,    en Gecode, es implementado usando un <em>espacio</em> en el que se definen las    variables (de decisión), los propagadores (implementaciones de restricciones)    y los ramificadores (que definirán el árbol de búsqueda). </font></p>     <p align="justify"><font size="2" face="Verdana"><b>Programa 5.1</b> Estructura    de un programa heredando la clase Space de Gecode.</font></p>     <p align=justify><font size="2" face="Verdana">1 using namespace Gecode;      <br>   2    <br>   3 class Reinas : public Space {     <br>   4<i>     /// Constructor: implementaci<em>ó</em>n del modelo</i>    <br>   5<i>     /// Constructor de copia: para clonar objetos</i>    <br>   6<i>     /// Funci<em>ó</em>n de copia: para copiar durante la   clonaci<em>ó</em>n    de objetos</i>    ]]></body>
<body><![CDATA[<br>   7<i>     /// Funci<em>ó</em>n para imprimir la soluci<em>ó</em>n</i>    <br>   8 };     <br>   9 <i>/// Funci<em>ó</em>n principal</i></font></p>     <p align="justify"><font size="2" face="Verdana"><a name="Ref_x1-5003r1"></a>Prácticamente,    toda la funcionalidad necesaria se encuentra visible dentro del espacio de nombres    Gecode (Línea 1 del Programa 5.1). Los Espacios están implementados por la clase    Space, de manera que para implementar el modelo es necesario heredar de esta    clase e implementar el modelo en el constructor (de la subclase). Además del    constructor, para que la búsqueda funcione apropiadamente es necesario implementar,    en la subclase, un constructor de copia, y una función de copia. </font></p>     <p align="justify"><font size="2" face="Verdana"><a name="Ref_x1-5014r2"></a><b>Programa    5.2.</b> Variables de decisión </font></p>     <p align=justify><font size="2" face="Verdana">1 #include &lt;gecode/int.hh&gt;    <br>   2    <br>   3 using namespace Gecode;     <br>   4    <br>   5 class Reinas : public Space {     ]]></body>
<body><![CDATA[<br>   6    protected:     <br>   7      IntVarArray reina;       <br>   8    public:     <br>   9      Reinas() {     <br>   10        const int n = 8;      <br>   11        reina = IntVarArray(*this, n, 0, n - 1);     <br>   12<i>         /// Establecer restricciones</i>    <br>   13<i>         /// Especificar ramificador</i>    <br>   14     }     <br>   15<i>   /// Constructor de copia: para clonar objetos</i>    ]]></body>
<body><![CDATA[<br>   16<i>   /// Funci</i><em>ó</em><i>n de copia: para copiar durante la clonaci</i><em>ó</em><i>n    de objetos</i>    <br>   17<i>   /// Funci</i><em>ó</em><i>n para imprimir la soluci</i><em>ó</em><i>n</i>    <br>   18 };     <br>   19 <i>/// Funci</i><em>ó</em><i>n principal</i></font></p>     <p align="justify"><font size="2" face="Verdana">Para implementar el modelo, por    simplicidad, definimos una constante de tipo entero <img border=0 width=13 height=21 src="/img/revistas/ran/v5n1/v5n1a04-148.gif"> (que normalmente sería    un parámetro obtenido desde la línea de comando) para especificar el número    de reinas, y un vector <img border=0 width=38 height=20 src="/img/revistas/ran/v5n1/v5n1a04-149.gif"> de    <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-23.gif"> variables de decisión de tipo entero (Líneas 7 y    10 del Programa 5.2). Para usar variables de decisión y restricciones de tipo    entero, es necesario incluir &lt;gecode/int.hh&gt;. </font></p>     <p align="justify"><font size="2" face="Verdana">El constructor del vector de    variables de decisión de tipo entero toma como primer argumento el espacio actual.    (De hecho, cualquier función que dependa del espacio, toma al espacio actual    como argumento y por tanto esto se repite en los constructores de variables    de decisión, funciones que establecen restricciones, y funciones que especifican    ramificadores.) </font></p>     <p align="justify"><font size="2" face="Verdana"><b>Programa5.3.</b> Restricciones    </font></p>     <p align=justify><font size="2" face="Verdana">1 #include &lt;gecode/int.hh&gt;    <br>   2    <br>   3 using namespace Gecode;     ]]></body>
<body><![CDATA[<br>   4    <br>   5 class Reinas : public Space {     <br>   6    protected:     <br>   7      IntVarArray reina;     <br>   8    <br>   9    public:     <br>   10     Reinas() {     <br>   11       const int n = 8;     <br>   12       reina = IntVarArray(*this, n, 0, n - 1);     <br>   13    ]]></body>
<body><![CDATA[<br>   14       distinct(*this, reina, ICL_VAL);       <br>   15       IntArgs c(n);      <br>   16       for (int i = n; i--; ) c[i] = i;     <br>   17       distinct(*this, c, reina, ICL_VAL);       <br>   18       for (int i = n; i--; ) c[i] = -i;     <br>   19       distinct(*this, c, reina, ICL_VAL);       <br>   20    <br>   21<i>       /// Especificar ramificador</i>    <br>   22     }     <br>   23<i>   /// Constructor de copia: para clonar objetos</i>    ]]></body>
<body><![CDATA[<br>   24<i>   /// Funci</i><em>ó</em><i>n de copia: para copiar durante la clonaci</i><em>ó</em><i>n    de objetos</i>    <br>   25<i>   /// Funci</i><em>ó</em><i>n para imprimir la soluci</i><em>ó</em><i>n</i>    <br>   26 };     <br>   27 <i>/// Funci</i><em>ó</em><i>n principal</i></font></p>     <p align="justify"><font size="2" face="Verdana"><a name="Ref_x1-5035r3"></a>Para    lograr expresar las restricciones <img border=0 width=117 height=25 src="/img/revistas/ran/v5n1/v5n1a04-53.gif">en las diagonales del tablero,    en el constructor, declaramos un vector de argumentos de tipo entero IntArgs    (Línea 15 del Programa 5.3). La memoria asignada a los vectores de variables    de decisión (como IntVarArray) se libera solamente cuando termina la vida del    espacio en el que han sido definidos. Esto hace que este tipo de vectores no    sean adecuados para variables temporales, en este caso para ser usados como    argumentos en la especificación de restricciones. Los vectores de tipo IntArgs,    al contrario, son inmutables, obtienen espacio del heap, y la memoria es liberada    cuando su destructor es ejecutado. </font></p>     <p align="justify"><font size="2" face="Verdana">La implementación de la restricción    <img border=0 width=117 height=25 src="/img/revistas/ran/v5n1/v5n1a04-53.gif"> en Gecode es llamada restricción distinct. Establecer    distinct(space, x) (Línea 14 del Programa 5.3) exige que todas las variables    en <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif"> tomen valores diferentes. De igual manera, establecer    distinct(space, c, x) (Líneas 17 y  19 del Programa5.3), para un vector de valores    enteros <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-11.gif"> (de tipo IntArgs y del mismo tamaño que    <img border=0 width=13 height=20 src="/img/revistas/ran/v5n1/v5n1a04-29.gif">), exige que <img border=0 width=108 height=25 src="/img/revistas/ran/v5n1/v5n1a04-150.gif"> para <img border=0 width=80 height=22 src="/img/revistas/ran/v5n1/v5n1a04-151.gif"> e    <img border=0 width=34 height=22 src="/img/revistas/ran/v5n1/v5n1a04-94.gif"> . Estas dos funciones pueden tomar un último parámetro    especificando el nivel de consistencia para la reducción por propagación. En    este caso, especificamos el nivel de consistencia por valores a través de la    constante ICL_VAL indicando que la reducción por propagación se efectuará cuando    alguna variable sea asignada. <a name="Ref_x1-5064r4"></a></font></p>     <p align="justify"><font size="2" face="Verdana"><b>Programa 5.4.</b> Búsqueda    </font></p>     <p align=justify><font size="2" face="Verdana">1 #include &lt;gecode/int.hh&gt;    <br>   2      <br>   3 using namespace Gecode;     ]]></body>
<body><![CDATA[<br>   4      <br>   5 class Reinas : public Space {     <br>   6  protected:     <br>   7    IntVarArray reina;     <br>   8      <br>   9  public:     <br>   10    Reinas() {     <br>   11     const int n = 8;     <br>   12     reina = IntVarArray(*this, n, 0, n - 1);     <br>   13      ]]></body>
<body><![CDATA[<br>   14     distinct(*this, reina, ICL_VAL);     <br>   15     IntArgs c(n);     <br>   16     for (int i = n; i--; ) c[i] = i;     <br>   17     distinct(*this, c, reina, ICL_VAL);     <br>   18     for (int i = n; i--; ) c[i] = -i;     <br>   19     distinct(*this, c, reina, ICL_VAL);     <br>   20      <br>   21     branch(*this, reina, INT_VAR_SIZE_MIN, INT_VAL_MIN);       <br>   22    }     <br>   23      ]]></body>
<body><![CDATA[<br>   24    Reinas(bool share, Reinas&amp; s) : Space(share,s){      <br>   25     reina.update(*this, share, s.reina);     <br>   26    }     <br>   27      <br>   28    virtual Space* copy(bool share) {       <br>   29     return new Reinas(share,*this);     <br>   30    }     <br>   31      <br>   32 <i> /// Funci</i><em>ó</em><i>n para imprimir la soluci</i><em>ó</em><i>n</i>    <br>   33 };     ]]></body>
<body><![CDATA[<br>   34 <i>/// Funci</i><em>ó</em><i>n principal</i></font></p>     <p align="justify"><font size="2" face="Verdana">El siguiente paso es especificar    un ramificador que, usualmente, toma un vector de variables que deben ser asignadas    durante la búsqueda, junto con una estrategia de selección de variables y una    estrategia de selección de valores. </font></p>     <p align="justify"><font size="2" face="Verdana">En nuestro caso (Línea 21 del    Programa5.4), usando una heurística de fallar pronto, especificamos para el    vector de variables reinas, seleccionar primero las variables con el dominio    de menor cardinalidad (a través de la constante INT_VAR_SIZE_MIN) y luego asignar    primero el menor valor del dominio (a través de la constante INT_VAL_SIZE_MIN).    </font></p>     <p align="justify"><font size="2" face="Verdana">Por la manera en que la búsqueda    es implementada en Gecode, es necesario implementar un constructor de copia    (Línea 24 del Programa5.4) y una función de copia (Línea 28 del Programa 5.4).    La función de copia es virtual para que sea posible crear una copia de un espacio    aun cuando no se conozca la subclase exacta de este. El argumento share no debería    preocupar al lector puesto que es usado internamente por Gecode. <a name="Ref_x1-5100r5"></a></font></p>     <p align="justify"><font size="2" face="Verdana"><b>Programa 5.5.</b> Solución    al problema de las n-reinas </font></p>     <p align=justify><font size="2" face="Verdana">1 #include &lt;gecode/int.hh&gt;    <br>   2 #include &lt;gecode/search.hh&gt;    <br>   3      <br>   4 using namespace Gecode;     <br>   5      ]]></body>
<body><![CDATA[<br>   6 class Reinas : public Space {     <br>   7  protected:     <br>   8    IntVarArray reina;     <br>   9      <br>   10  public:     <br>   11    Reinas() {     <br>   12     const int n = 8;     <br>   13     reina = IntVarArray(*this, n, 0, n - 1);     <br>   14      <br>   15     distinct(*this, reina, ICL_VAL);     ]]></body>
<body><![CDATA[<br>   16     IntArgs c(n);     <br>   17     for (int i = n; i--; ) c[i] = i;     <br>   18     distinct(*this, c, reina, ICL_VAL);     <br>   19     for (int i = n; i--; ) c[i] = -i;     <br>   20     distinct(*this, c, reina, ICL_VAL);     <br>   21      <br>   22     branch(*this, reina, INT_VAR_SIZE_MIN, INT_VAL_MIN);     <br>   23    }     <br>   24      <br>   25    Reinas(bool share, Reinas&amp; s) : Space(share,s){     ]]></body>
<body><![CDATA[<br>   26     reina.update(*this, share, s.reina);     <br>   27    }     <br>   28      <br>   29    virtual Space* copy(bool share) {     <br>   30     return new Reinas(share,*this);     <br>   31    }     <br>   32      <br>   33    virtual void print(std::ostream&amp; os) const {       <br>   34     os&lt;&lt; &quot;reinas\t&quot; &lt;&lt;reina&lt;&lt;std::endl;     <br>   35    }     ]]></body>
<body><![CDATA[<br>   36 };     <br>   37      <br>   38 int main(int argc, char* argv[]) {       <br>   39  Reinas* m = new Reinas;      <br>   40  DFS&lt;Reinas&gt; e(m);      <br>   41  delete m;     <br>   42      <br>   43  Reinas* s = e.next();       <br>   44  s-&gt;print(std::cout);      <br>   45  delete s;     ]]></body>
<body><![CDATA[<br>   46      <br>   47  return 0;     <br>   48 }  </font></p>     <p align="justify"><font size="2" face="Verdana">Finalmente, para encontrar la    solución, además de una función para imprimir los valores asignados a nuestras    variables de decisión (Línea 33 del Programa 5.5), es (por supuesto) necesario    implementar la función principal que, </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    crea el modelo (Línea 39 del Programa 5.5), </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    crea un motor de búsqueda en profundidad (Línea 40 del Programa 5.5) incluido    en &lt;gecode/search.hh&gt;,</font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    busca la primera solución (Línea 43 del Programa 5.5), e </font></p>     <p align="justify"><font size="2" face="Verdana">·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    imprime la primera solución encontrada (Línea 44 del Programa 5.5).</font></p>     <p align="justify"><font size="2" face="Verdana">El resultado es: reinas {0, 4,    7, 5, 2, 6, 1, 3}.<a href="#_ftn7" name="_ftnref7" title="">[7]</a> ¿Podrías comprobar que este resultado es correcto?</font></p>     <p align="justify"><font size="2" face="Verdana">Una herramienta muy útil que    ofrece Gecode es Gist: una interfaz gráfica y herramienta interactiva que permite    explorar el árbol de búsqueda, inspeccionando sus nodos, ya sea paso por paso    o automáticamente. El uso de Gist es afortunadamente simple. Para este caso,    basta con incluir &lt;gecode/gist.hh&gt; y reescribir la función principal como    se muestra en el Programa 5.6. </font></p>     ]]></body>
<body><![CDATA[<p align="justify"><font size="2" face="Verdana"><a name="Ref_x1-5151r6"></a><b>Programa    5.6.</b> Función principal para usar Gist<img width=1 height=1 src="/img/revistas/ran/v5n1/v5n1a04-152.gif"></font></p>     <p align=justify><font size="2" face="Verdana">1 int main(int argc, char* argv[])    {     <br>   2  Reinas* m = new Reinas;     <br>   3  Gist::Print&lt;Reinas&gt; p(&quot;Mostrar solucion&quot;);     <br>   4  Gist::Options o;     <br>   5  o.inspect.click(&amp;p);     <br>   6  Gist::dfs(m,o);     <br>   7  delete m;     <br>   8      <br>   9  return 0;     ]]></body>
<body><![CDATA[<br>   10 } </font></p>     <p align=center><font size="2" face="Verdana"><img border=0 width=475 height=293 id="Picture 246" src="/img/revistas/ran/v5n1/v5n1a04-153.jpg" alt=figura></font></p>     <p align="center"><font size="2" face="Verdana"><a name="Ref_x1-51637"></a><b>Figura    7:&nbsp;&nbsp; </b>Árbol de búsqueda mostrado por Gist para encontrar la primera    solución al problema de las 8-reinas. </font></p>     <p align="justify"><font size="2" face="Verdana">Ejecutando el nuevo programa,<a href="#_ftn8" name="_ftnref8" title="">[8]</a> podemos observar la raíz del árbol, y realizar la búsqueda paso    por paso o automáticamente. Por ejemplo, si pedimos que la búsqueda se realice    automáticamente hasta encontrar la siguiente (es decir, la primera) solución,    obtenemos gráficamente el árbol construido hasta encontrar reinas {0, 4, 7,    5, 2, 6, 1, 3} tal como se muestra en la Figura 7.</font></p>     <p align="justify"><font size="2" face="Verdana">¿Podrías escribir un programa    en C++ usando Gecode (y Gist) para resolver instancias del rompecabezas Sudoku?</font></p>     <p align="justify"><font size="2" face="Verdana">¡Se dice que las instancias más    difíciles de Sudoku publicadas en los periódicos pueden ser resueltas fácilmente    usando programación con restricciones en muy poco tiempo con pocos intentos    fallidos en la búsqueda!</font></p>     <p align="justify">&nbsp;</p>     <p align="justify">&nbsp;</p> <hr align="center" noshade> <h2 align="justify"><font size="3" face="Verdana"><b>6&nbsp;&nbsp; Referencias</b></font></h2>     <!-- ref --><p align="justify"><font size="2" face="Verdana">[1]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <a name="Ref_XAgren%3APhD"></a>Magnus Ågren. <i>Set Constraints for Local Search</i>.    PhD thesis, Department of Information Technology, Uppsala University, Sweden,    2008. Disponible en <a href="http://urn.kb.se/resolve?urn=urn:nbn:se:uu:diva-8373">http://urn.kb.se/resolve?urn=urn:nbn:se:uu:diva-8373</a>.    </font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&#160;<a href="javascript:void(0);" onclick="javascript: window.open('/scielo.php?script=sci_nlinks&ref=770907&pid=S1683-0789201100010000400001&lng=','','width=640,height=500,resizable=yes,scrollbars=1,menubar=yes,');">Links</a>&#160;]<!-- end-ref --><!-- ref --><p align="justify"><font size="2" face="Verdana"><a name="Ref_XApt%3AconstraintsBook"></a>[2]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    Krzysztof R. Apt. <i>Principles of Constraint Programming</i>. Cambridge University    Press, 2003. </font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&#160;<a href="javascript:void(0);" onclick="javascript: window.open('/scielo.php?script=sci_nlinks&ref=770908&pid=S1683-0789201100010000400002&lng=','','width=640,height=500,resizable=yes,scrollbars=1,menubar=yes,');">Links</a>&#160;]<!-- end-ref --><!-- ref --><p align="justify"><font size="2" face="Verdana"><a name="Ref_XRegin%3Aalldifferent"></a>[3]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    Jean-Charles Régin. A filtering algorithm for constraints of difference in CSPs.    In Barbara Hayes-Roth and Richard E. Korf, editors, <i>Proceedings of AAAI&#8217;94</i>,    pages 362&#8211;367. AAAI Press, 1994. </font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&#160;<a href="javascript:void(0);" onclick="javascript: window.open('/scielo.php?script=sci_nlinks&ref=770909&pid=S1683-0789201100010000400003&lng=','','width=640,height=500,resizable=yes,scrollbars=1,menubar=yes,');">Links</a>&#160;]<!-- end-ref --><!-- ref --><p align="justify"><font size="2" face="Verdana"><a name="Ref_XSCHULTE%3ABook%3AConstraintServices"></a>[4]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    Christian Schulte. <i>Programming constraint services</i>. Springer, 2002. </font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&#160;<a href="javascript:void(0);" onclick="javascript: window.open('/scielo.php?script=sci_nlinks&ref=770910&pid=S1683-0789201100010000400004&lng=','','width=640,height=500,resizable=yes,scrollbars=1,menubar=yes,');">Links</a>&#160;]<!-- end-ref --><!-- ref --><p align="justify"><font size="2" face="Verdana"><a name="_Ref343005084"></a><a name="Ref_XNOTE%3ACP%3AKTH%3A11"></a>[5]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Christian    Schulte. <i>Course Notes. Constraint Programming (ID2204). Spring semester.    </i>Royal Institute of Technology - KTH<i>, </i>2011. </font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&#160;<a href="javascript:void(0);" onclick="javascript: window.open('/scielo.php?script=sci_nlinks&ref=770911&pid=S1683-0789201100010000400005&lng=','','width=640,height=500,resizable=yes,scrollbars=1,menubar=yes,');">Links</a>&#160;]<!-- end-ref --><p align="justify"><font size="2" face="Verdana"><a href="#_ftnref1" name="_ftn1" title="">[1]</a>    Y además, como veremos más adelante, a escoger un algoritmo de búsqueda.</font></p>     <p align="justify"><font size="2" face="Verdana"><a href="#_ftnref2" name="_ftn2" title="">[2]</a>    Problema ampliamente conocido gracias a numerosos periódicos que publican muchas    de sus instancias en sus secciones de pasatiempos.</font></p>     <p align="justify"><font size="2" face="Verdana"><a href="#_ftnref3" name="_ftn3" title="">[3]</a>    No existe pérdida de generalidad exigiendo que todas las variables compartan    inicialmente el mismo dominio, puesto que siempre es posible especificar dominios    más pequeños para ciertas variables en <img width=17 height=21 src="/img/revistas/ran/v5n1/v5n1a04-154.gif">a través de restricciones de pertenencia/membresía.</font></p>     <p align="justify"><font size="2" face="Verdana"><a href="#_ftnref4" name="_ftn4" title="">[4]</a>    Ver, por ejemplo, el catálogo de restricciones globales disponible en <a href="http://www.emn.fr/z-info/sdemasse/gccat/">http://www.emn.fr/z-info/sdemasse/gccat/</a></font></p>     <p align="justify"><font size="2" face="Verdana"><a href="#_ftnref5" name="_ftn5" title="">[5]</a>    Código abierto y libre, bajo una licencia permisiva, disponible en <a href="http://www.gecode.org/">http://www.gecode.org/</a></font></p>     <p align="justify"><font size="2" face="Verdana"><a href="#_ftnref6" name="_ftn6" title="">[6]</a>    <img border=0 width=113 height=25 src="/img/revistas/ran/v5n1/v5n1a04-155.gif">denota una secuencia de variables<img border=0 width=19 height=25 src="/img/revistas/ran/v5n1/v5n1a04-156.gif">tal    que <img border=0 width=70 height=25 src="/img/revistas/ran/v5n1/v5n1a04-157.gif">e <img border=0 width=61 height=23 src="/img/revistas/ran/v5n1/v5n1a04-158.gif"></font></p>     <p align="justify"><font size="2" face="Verdana"><a href="#_ftnref7" name="_ftn7" title="">[7]</a>    Tras instalar correctamente Gecode, el programa mostrado en el Programa 5.5,    guardado en un archivo reinas.cpp, puede ser compilado con el siguiente comando:    ]]></body>
<body><![CDATA[<br>   g++ reinas.cpp -o reinas -lgecodeint -lgecodesearch</font></p>     <p align="justify"><font size="2" face="Verdana"><a href="#_ftnref8" name="_ftn8" title="">[8]</a> Compilado previamente con el comando :                                   <br>   g++ reinas-gist.cpp -o reinas-gist -lgecodeint -lgecodesearch -lgecodegist</font></p>       ]]></body><back>
<ref-list>
<ref id="B1">
<nlm-citation citation-type="">
<source><![CDATA[Set Constraints for Local Search. PhD thesis, Department of Information Technology, Uppsala University, Sweden]]></source>
<year></year>
</nlm-citation>
</ref>
<ref id="B2">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[Krzysztof]]></surname>
<given-names><![CDATA[R.]]></given-names>
</name>
</person-group>
<source><![CDATA[Apt. Principles of Constraint Programming. Cambridge University Press]]></source>
<year></year>
</nlm-citation>
</ref>
<ref id="B3">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[Régin]]></surname>
<given-names><![CDATA[Jean-Charles]]></given-names>
</name>
</person-group>
<source><![CDATA[A filtering algorithm for constraints of difference in CSPs. In Barbara Hayes-Roth and Richard E. Korf, editors]]></source>
<year></year>
</nlm-citation>
</ref>
<ref id="B4">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[Schulte]]></surname>
<given-names><![CDATA[Christian]]></given-names>
</name>
</person-group>
<source><![CDATA[Programming constraint services.]]></source>
<year></year>
</nlm-citation>
</ref>
<ref id="B5">
<nlm-citation citation-type="">
<person-group person-group-type="author">
<name>
<surname><![CDATA[Schulte]]></surname>
<given-names><![CDATA[Christian]]></given-names>
</name>
</person-group>
<source><![CDATA[Course Notes. Constraint Programming (ID2204)]]></source>
<year></year>
</nlm-citation>
</ref>
</ref-list>
</back>
</article>
