Showing posts with label eficiencia en programación. Show all posts
Showing posts with label eficiencia en programación. Show all posts

Tuesday, April 17, 2012

Mi caso contra OpenGL


OpenGL sirve para hacer gráficas. De acuerdo a la Wikipedia: OpenGL (Open Graphics Library) es una especificación estándar que define una API multilenguaje y multiplataforma para escribir aplicaciones que produzcan gráficos 2D y 3D. La interfaz consiste en más de 250 funciones diferentes que pueden usarse para dibujar escenas tridimensionales complejas a partir de primitivas geométricas simples, tales como puntos, líneas y triángulos. Fue desarrollada originalmente por Silicon Graphics Inc. (SGI) en 1992 y se usa ampliamente en CAD, realidad virtual, representación científica, visualización de información y simulación de vuelo. También se usa en desarrollo de videojuegos, donde compite con Direct3D en plataformas Microsoft Windows.

Y este tema me interesó hace tiempo, pero hasta ahora que estoy dando un curso de graficación en la Facultad de Ciencias de la UNAM, decidí aplicarme y ver qué tanto se podía hacer en OpenGL. Hallé de entrada que hay muchísima documentación y por ende, es fácil encontrar ejemplos, tutoriales, etc. En Google se pueden ver montones de imágenes muy bien logradas con esta biblioteca gráfica. Sin embargo, después de un par de meses de estar lidiando con este asunto encontré que hay cosas que no me convencen. He aquí algunas de ellas:

OpenGL tiene sus virtudes, pues se puede instalar prácticamente en cualquier herramienta de programación. Sin embargo, para cada una hay que seguir pasos diferentes. No tiene un procedimiento estándar para esto y cambia de acuerdo al marco de trabajo que quiera usarse.

  1. Para poder usar OpenGL y sacar provecho del mismo hay que pensar en modelos matemáticos. Uno lo que hace, al programar en OpenGL es crear un medio ambiente tridimensional, el cual es muy flexible en muchos sentidos. El problema es que esto hay que tenerlo presente al programar. Por ejemplo, si queremos crear una esfera, tenemos que escribir el código que haga esto. Si queremos que tenga textura tenemos que escribir las instrucciones que nos permiten "texturizar" el objeto, etc. No obstante, nada de esto podemos verlo "en vivo", es decir, necesitamos correr el programa y ver si nuestro modelo tridimensional matemático es lo que estábamos esperando (cosa que pocas veces sucede).
  2. Las instrucciones de OpenGL vienen en diferentes "formatos". Se puede usar por ejemplo, una instrucción que contenga parámetros enteros, dobles, de punto flotante, y tendremos que hay tres instrucciones diferentes, una para cada formato, en donde se agrega a la instrucción lo siguiente: GLColor* (1.0, 1.0, 1.0);en donde el * representa 3f (3 coordenadas de punto flotante); 3d (tres coordenadas de resolución doble); 3i (tres coordenadas enteras). Esto en mi opinión puede ser muy versátil, pero es confuso.
  3. La curva de aprendizaje es realmente lenta, porque insisto y hago énfasis: OpenGL no tiene un sistema para ir visualizando cómo se van haciendo las cosas de acuerdo a las instrucciones escritas. Hasta que se compila puede verse el resultado final, que de verdad, pocas veces coincide con lo que estábamos pensando.

Para mi gusto, sería mucho más amable tener una herramienta al mejor estilo 3dStudio, el cual permite en muchos casos hacer las imágenes interactivas, poner texturas, luces, trayectorias de la cámara para ver cómo se va a mover, etc. Así como está OpenGL, deja mucho que desear.

Quizás para alguna aplicación específica sea la herramienta adecuada pero hasta el momento usar OpenGL como la biblioteca gráfica de programación, parece ser demasiado complicado y poco amable con el programador.

Monday, January 09, 2012

Errores y solución al concurso de programadores reales

En el artículo pasado puse mi programa en prolog, el cual sacaba la solución al problema propuesto, que tomar los 100 primeros enteros y descomponerlos como la suma de dos enteros al cuadrado (también del 0 al 100). El programa que puse era defectuoso, pero fue a "ojo de buen cubero" (que no resulté tan buen cubero). Ya con calma me senté a resolver el asunto y éste es el código que sí funciona:


predicates
   num(integer)
   cuenta(integer,integer,integer).
   checa(integer)


clauses
    num(0).
    num(1).
    num(2).
    num(3).
    num(4).
    num(5).
    num(6).
    num(7).
    num(8).
    num(9).
    num(10).
    num(11).
    num(12).
    num(13).
    num(14).
    num(15).
    num(16).
    num(17).
    num(18).
    num(19).
    num(20).
    num(21).
    num(22).
    num(23).
    num(24).
    num(25).
    num(26).
    num(27).
    num(28).
    num(29).
    num(30).
    num(31).
    num(32).
    num(33).
    num(34).
    num(35).
    num(36).
    num(37).
    num(38).
    num(39).
    num(40).
    num(41).
    num(42).
    num(43).
    num(44).
    num(45).
    num(46).
    num(47).
    num(48).
    num(49).
    num(50).
    num(51).
    num(52).
    num(53).
    num(54).
    num(55).
    num(56).
    num(57).
    num(58).
    num(59).
    num(60).
    num(61).
    num(62).
    num(63).
    num(64).
    num(65).
    num(66).
    num(67).
    num(68).
    num(69).
    num(70).
    num(71).
    num(72).
    num(73).
    num(74).
    num(75).
    num(76).
    num(77).
    num(78).
    num(79).
    num(80).
    num(81).
    num(82).
    num(83).
    num(84).
    num(85).
    num(86).
    num(87).
    num(88).
    num(89).
    num(90).
    num(91).
    num(92).
    num(93).
    num(94).
    num(95).
    num(96).
    num(97).
    num(98).
    num(99).
    num(100).
    
    checa(101) :- !,fail.
    checa(_).
          
    cuenta(X,A,B) :- 
               num(A),
               num(B),
               X = (A*A) + (B*B),
               write(X," = ", A,"^2 + ",B,"^2"), nl,
               X1 = X + 1, !,
               checa(X1),
               cuenta(X1,A1,B1).


    cuenta(X,A,B) :- X1 = X + 1,
                     checa(X1),
                     cuenta(X1,A,B).


La solución completa la dio en Mathematica Emmanuel Garcés, la cual realmente es elegante, mucho mejor que mi código en prolog. se ve que mi tocayo conoce bastante bine el programa de Wolfram

Concurso para programadores reales


Se supone que los programadores reales, los de verdad, son tan capaces que casi casi no necesitan herramientas de software para sus labores. Esto por supuesto es una exageración que se ha llevado ya al extremo del folklore urbano (*) en esta rama de la ciencia.

Pues bien, Facebook lanzó la segunda versión de su concurso "hacker-cup", para aquellos interesados en pasar a la historia como uno de los mejores programadores del planeta. El concurso está abierto a todo aquel que quiera participar, en cualquier parte del mundo y hasta donde he entendido no hay ninguna restricción sobre qué lenguaje de programación usar.

La justa se hará en sucesivas fechas, en las cuales se irá obteniendo a los ganadores. Por ejemplo, en la primera etapa se plantean tres problemas., Si se resuelve al menos uno, se pasa a la siguiente prueba. ¿Qué tipo de pruebas se exigen en el concurso? No lo sé, pero he aquí un ejemplo del año pasado: se trata de hallar dos números enteros, del 1 al cien, que pongan todas las posibles combinaciones de estos números en la forma A^2 + B^2.

Por ejemplo, 25 puede ponerse como 3^2 + 4^2 o bien, 0^2 + 5^2.

No pienso entrar en el concurso, porque francamente no tengo tiempo y seguro hay programadores mil veces más clavados que yo. Sin embargo, este pequeño problema, se me ocurre, se puede resolver fácilmente en Prolog. He aquí mi código, el cual probaré a la brevedad:

predicates
   suma (integer,integer,integer)
   num(integer)
   prueba

clauses
    suma(R, A, B) :- R = (A^2) + (B^2).
    num(0).
    num(1).
    num(2).
    num(3).
        .
        .
        .
    num(99).
    num(100).

    prueba :-
      num(A),
      num(B),
      R = A,         
      suma(R,A,B),
      write("Los valores de los números son ", A, " y  ", B), nl,
      fail.

 goal
    prueba.         


Ahora que pruebe mi código pondré las reflexiones del caso.
_____
(*) El término "programador real" describe a esos programadores "duros" que prácticamente reniegan de todas las herramientas y lenguajes modernos para hacerlo todo desde una manera más directa y efectiva, muchas veces relacionada con el hardware. El arquetipo de los programadores reales es sin duda Mel Kaye, de la McBee Computer Corporation, quien está inmortalizado en "La Historia de Mel", en la cual se dice que "escribió en código de máquina, sin adornos, todo su código en el inescrutable código hexadecimal. Directamente".

Tuesday, December 27, 2011

Fotos panorámicas de Acapulco


JC me acaba de mandar unas fotos panorámicas de Acapulco, que tomó con su maravillosa cámara que hace este proceso de forma automática (necesito uno de estos dispositivos urgentemente).


Sin embargo, para verlas mejor, tengo un programa que escribí hace tiempo, usando un componente explícitamente  escrito para manejar fotos panorámicas, el cual hace la experiencia mucho más sencilla. Pueden bajar el ejecutable con las dos fotos que ilustran este artículo para que vean la playa del revolcadero y el complejo en donde estuvimos hospedados. 

El enlace es éste.

Sunday, November 20, 2011

Inteligencia artificial y sistemas expertos


La inteligencia artificial, término que acuñó John McCarthy me parece, se basa en la idea de hacer sistemas inteligentes, tan capaces como los que puede lograr el cerebro humano. Sin embargo, se halló, después de los primeros años frustrantes, que la inteligencia humano no sólo era complicada, sino mucho más complicada de lo que habíamos pensado. Por ello, hubo una división natural de tareas: visión por computadora; sistemas expertos; reconocimiento de patrones; entre otros.



Uno de los temas que por algunos años estuvieron en boga, pero que probablemente han caído en el desuso es el de los sistemas expertos, el cual se basa en escribir software que fuese tan bueno como un experto humano en un tema particular. En ese sentido por ejemplo, un programa de ajedrez como los actuales, que le ganan al 99.99% de los jugadores humanos,  es un sistema experto muy exitoso, pero las técnicas de programación para jugar tan bien están lejos de la teoría tradicional de los sistemas expertos. En este caso las cosas son así. Un sistema experto se basa en tres subtemas:

  • Interfaz con el usuario
  • Base de conocimientos (reglas de producción)
  • Motor de inferencias

En ese sentido, cuando se va a trabajar con un sistema experto hay que reconocer cómo se diseñará cada parte. En el caso de la interfaz del usuario, aunque hay muchas alternativas, la más común es responder "sí" o "no" a las preguntas que hace el sistema. esto -desde luego- no es tan poderoso como aquellos sistemas que además de responder a preguntas con "sí" o "no", también puedes darle un valor de confiabilidad a la respuesta. Por ejemplo,

Pregunta: "¿Te duele la cabeza"
Respuesta: "sí"
Pregunta: Del 1 al 10, ¿cuánto te duele? (donde 10 es el dolor más fuerte)

este tipo de sistemas usan probabilidad para decidir el margen de confiabilidad de las respuestas que entrega el sistema experto, basado en las confiabilidades que se dieron en las diferentes respuestas por parte del usuario. Para ello se usa el teorema de Bayes Sin embargo, para poner las cosas de la manera más simple, muchos sistemas expertos solamente permiten responder "sí" o "no".

Pues bien, una vez hecho esto, tenemos que describir la base de conocimientos, la cual es la que nos dará información sobre el tema que nos ocupa. Por ejemplo, en el programa muestra que te mando, la base de conocimientos es la información sobre los diferentes perros que existen. Así, un snauzer será un perro pequeño, con cola y orejas cortas, de buen talante, etc. En esta base se definen algunos perros y sus características. La idea del sistema experto es que el programa vaya pidiéndole información al usuario para que éste pueda concluir de qué perro se trata. Las bases de conocimiento están puestas en general como predicados "causa - efecto". Así, una regla en general podría ser: "si te duele la cabeza es que tienes gripe". La causa: el tener gripe; el efecto: el dolor de cabeza.

El motor de inferencias es quien pregunta al usuario basándose en esas cláusulas causa - efecto. Los sistemas expertos usan tres posibles motores de inferencia:

  • encadenamiento hacia atrás (backward chaining)
  • encadenamiento hacia adelante (forward chaining)
  • sistema de borrador (blackboard system)

El primer caso funciona así: Imagina que vas con el médico porque te sientes mal. Él te ve y te empieza a preguntar cosas sobre tus malestares. Sin embargo, antes de empezar las preguntas, las dirige asumiendo que tienes gripe, por ejemplo. Entonces te preguntará síntomas asociados de la gripe. Si le das más de una respuesta que no es presumiblemente de la gripe, se formulará mentalmente otra hipótesis y de nuevo empezará el interrogatorio.

El segundo caso es el encadenamiento hacia adelante. Siguiendo el ejemplo anterior, vas al médico y éste comienza a preguntarte qué te duele, pero no asume que tiene gripe o cualquier otra enfermedad. Lo que hace es acumular datos (respuestas) y entonces busca en su base de conocimientos qué es lo que más se parece a lo que puedes tener.

El sistema de borrador ya es obsoleto. Imagina un salón de clases lleno de expertos humanos en alguna materia. Entonces se plantea un problema y cada experto tiene un pedazo del borrador en la pared para poner su solución. Después de que todos hayan puesto su posible solución, un supervisor lee todas las respuestas y arma la respuesta final. Así funcionaba HearSay, un sistema de reconocimiento de voz de los años ochentas, actualmente en desuso.

Cabe señalar que los sistemas expertos deben estar construídos para no repetir hasta el hartazgo la misma pregunta. Por ejemplo, imagina que un sistema de encadenamiento hacia atrás te pregunta si te duele la cabeza y le contestas que no. Si es así, probablemente la primera hipótesis, la de tener gripe, no funcione. Entonces el sistema crea a través de la siguiente regla la nueva hipótesis. Si en esta nueva regla hay que preguntar de nuevo si te duele la cabeza, sería poco inteligente y serio de un sistema que te volviese a preguntar lo mismo. Así, el sistema experto (como el que te mando), guarda las respuestas del usuario y checa antes si ya respondiste a la pregunta para no volverla a preguntar.

Otra cuestión, que no está considerada en el sistema experto es la de explicar su funcionamiento. Es decir, ¿por qué el sistema experto llegó a las conclusiones y diagnósticos a los que llegó? Hay muchas maneras de hacer esto pero una de ellas es simplemente avisarle al programador, vía mensajes a la pantalla, en qué regla está trabajando. Otrso sistemas expertos pueden trazar la ruta de desarrollo. Por ejemplo, pueden decirte: "primero usé la regla 4, la cual me remitió a la regla 92 y por las respuestas del usuario tuve que probar las reglas 153 y 25", etc. Pero esto es mucho más sofisticado y difícil de programar.



/*      Program: Dog Expert        */
/* Purpose: To show the working of */
/* an expert system. It is a pro-  */
/* duction rule-based system.      */
/*                                 */
/* Remarks: This is a dog classi-  */
/* cation expert system. It uses a */
/* set of production rules for the */
/* purpose of inferring.           */

domains

database

   xpositive(symbol,symbol)
   xnegative(symbol,symbol)


predicates

   do_expert_job
   do_consulting
   ask(symbol,symbol)
   dog_is(symbol)
   it_is(symbol)
   positive(symbol,symbol)
   negative(symbol,symbol)
   remember(symbol,symbol,symbol)
   clear_facts

goal

   do_expert_job.


clauses

/*  User Interface System (UIS) */

do_expert_job :-
     makewindow(1,7,7,"An Expert System",1,16,22,58),
     nl, write(" ************************************"),
     nl, write("    Welcome to a Dog Expert System"),
     nl, write("                                 "),
     nl, write(" This is a dog identification system"),
     nl, write(" Please, respond by typing in 'yes'"),
     nl, write(" or 'no'.            Thank you.    "),
     nl,nl,
     do_consulting,
     write("Press space bar..."), nl,
     readchar(_),
     clearwindow,
     exit.

do_consulting :-
     dog_is(X), !,
     nl, write(" Your dog may be a(n) ",X,"."),
     clear_facts.

do_consulting :-
     nl, write("Sorry, unable to determine the dog."),nl,
     clear_facts.

ask(X,Y) :-
     write("   Question :- ",X," it, ",Y," ? "),
     readln(Reply),
     remember(X,Y,Reply).


/* Inference Engine (INE) */

positive(X,Y) :-
     xpositive(X,Y),!.

positive(X,Y) :-
     not(negative(X,Y)),!,
     ask(X,Y).

negative(X,Y) :-
     xnegative(X,Y),!.

remember(X,Y,yes) :-
     asserta(xpositive(X,Y)).

remember(X,Y,no) :-
     asserta(xnegative(X,Y)),
     fail.

clear_facts :-
     retract(xpositive(_,_)),
     fail.

clear_facts :-
     retract(xnegative(_,_)),
     fail.


/* Production Rules */


dog_is("English Bulldog") :-
     it_is("short-haired dog"),
     positive(has,"height under 22 inches"),
     positive(has,"low-set tail"),
     positive(has,"good natured personality"),!.

dog_is("Beagle") :-
     it_is("short-haired dog"),
     positive(has,"height under 22 inches"),
     positive(has,"long ears"),
     positive(has,"good natured personality"),!.

dog_is("Great Dane") :-
     it_is("short-haired dog"),
     positive(has,"low-set tail"),
     positive(has,"longer ears"),
     positive(has,"good natured personality"),
     positive(has,"weight over 100 lb"),!.

dog_is("American Foxhound") :-
     it_is("short-haired dog"),
     positive(has,"height under 30 inches"),
     positive(has,"longer ears"),
     positive(has,"good natured personality"),!.
    
dog_is("Cocker Spaniel") :-
     it_is("long-haired dog"),
     positive(has,"height under 22 inches"),
     positive(has,"low-set tail"),
     positive(has,"longer ears"),
     positive(has,"good natured personality"),!.

dog_is("Irish Setter") :-
     it_is("long-haired dog"),
     positive(has,"height under 30 inches"),
     positive(has,"low-set tail"),
     positive(has,"good natured personality"),!.

dog_is("Collie") :-
     it_is("long-haired dog"),
     positive(has,"height under 30 inches"),
     positive(has,"low-set tail"),
     positive(has,"good natured personality"),!.

dog_is("St. Bernard") :-
     it_is("long-haired dog"),
     positive(has,"low-set tail"),
     positive(has,"good natured personality"),
     positive(has,"weight over 100 lb"),!.
    
it_is("short-haired dog") :-
     positive(has,"short-haired"),!.
    
it_is("long-haired dog") :-         
     positive(has,"long-haired"),!.

Este sistema experto está escrito para turbo prolog, que funciona bajo MsDOS y está sacado del libro -si mal no recuerdo- Exploring Artificial Intelligence With Turbo PROLOG por Keith Weiskamp, el cual no sé dónde está. No lo halló más.

Sunday, September 11, 2011

Sobre resolver con Prolog el problema de los sudokus

En mi último artículo sobre programación y sudokus, hablé de un programa que podría resolver, en esencia, cualquier sudoku que se le pusiese, utilizando para ello fuerza bruta, es decir, considerando todas las posibilidades de números a poner en cada casilla. Alguna combinación debe ser la adecuada y con ello el asunto estaría resuelto.

Cuando corrí mi programa, pensé que se tardaría algunas horas quizás, de hecho no lo sabía, pero sospechaba que así sería. Un par de horas después de haber empezado el proceso lo aborté porque me hartó. No se veía para cuando terminaría. Así que decidí primero ver cuántos cálculos tiene que hacer el programa para poder resolver el sudoku planteado, que en ese caso hablamos de 46 números por hallar. Si usamos Prolog, tenemos que calcular la cantidad de combinaciones con repetición de 9 números tomados de 46 en 46.

La fórmula para ello es:
                               (n+r-1)!
Combinaciones =  ----------
                                r!(n-1)!

 donde n es la cantidad de números diferentes y r es la cantidad de espacios a llenar. Además, se pueden repetir los números, es decir, no todos tienen que ser siempre distintos. El resultado de esto es 1,040,465,790, es decir, mil cuatrocientos millones de posibles combinaciones. Para entender la magnitud de este número, si cada combinación se genera en un segundo (muy lento), entonces tardará unos 32 años en probar todas las posibles combinaciones. Si hace 1000 combinaciones por segundo (una aproximación más razonable), el sistema tardará unos 120 días en resolver todas las posibles combinaciones de números. Algo sin duda, demasiado lento. Vaya, si hiciese 10000 combinaciones por segundo, tardaría 12 días en resolverlo. Aún así es muy lento.

La razón de esto es que el programa, como originalmente está escrito, está obligado a prtimero poner a todos los números que buscamos, un "1". Se prueban entonces la combinación (como si fuese una caja fuerte). Si no "se abre", entonces probamos con otra combinación, haciendo backtrack. El resultado es un gigantesco proceso de ir cambiando números.

¿Cómo se podría mejorar? Desde luego que la técnica de prolog de examinar hasta agotar todas las posibilidades (simple fuerza bruta), no es práctica en este caso. Se necesita más inteligencia. Aún así, si no se quiere pensar mucho, bien podría intercalarse la búsqueda de unos pocos números, y entonces checar algunas de las ecuaciones, si eso está correcto, entonces buscar las restantes. Esto es lo que en principio sugirió el buen amigo Eduardo Ramos, aunque aún así los resultados pueden tardar si bien nos va, muchos días. De hecho, el programa se vería esta intercalación así:

predicates

   sudoku
   suma(integer, integer, integer, integer, integer, integer, integer, integer, integer, integer)
   num(integer)
  
clauses
  
   num(1).
   num(2).
   num(3).
   num(4).
   num(5).
   num(6).
   num(7).
   num(8).
   num(9).
  
   suma(A,B,C,D,E,F,G,H,I,R) :-
                          A+B+C+D+E+F+G+H+I = R.  

   sudoku :-
            / horizontales */
          
             num(A1), num(B1), num(C1), num(D1),
             suma(5,A1,4,3,B1,6,C1,7,D1,45),
           
             num(A2), num(B2), num(C2), num(D2), num(E2),   

             num(F2), num(G2), num(H2),
             suma(A2,B2,1,C2,D2,E2,F2,G2,H2,45),
           
             num(A3), num(B3), num(C3), num(D3), num(E3),
             suma(A3,7,6,B3,C3,2,9,D3,E3,45),
           
             num(A4), num(B4), num(C4), num(D4),
             suma(A4,8,B4,7,C4,5,6,D4,1,45),
                       
             num(A5), num(B5), num(C5), num(D5),
             suma(7,6,A5,B5,3,C5,D5,8,9,45),
           
             num(A6), num(B6), num(C6), num(D6),
             suma(9,A6,3,8,B6,4,C6,2,D6,45),
           
             num(A7), num(B7), num(C7), num(D7), num(E7),
             suma(A7,B7,8,1,C7,D7,2,9,E7,45),

             num(A8), num(B8), num(C8), num(D8), num(E8), 

             num(F8), num(G8), num(H8),
             suma(A8,B8,C8,D8,E8,F8,3,G8,H8,45),

             num(A9), num(B9), num(C9), num(D9),
             suma(A9,3,B9,4,C9,7,1,D9,6,45),

            
             /* verticales */
            
             suma(5,A2,A3,A4,7,9,A7,A8,A9,45),
             suma(A1,B2,7,8,6,A6,B7,B8,3,45),
             suma(4,1,6,B4,A5,3,8,C8,B9,45),
             suma(3,C2,B3,7,B5,8,1,D8,4,45),
             suma(B1,D2,C3,C4,3,B6,C7,E8,C9,45),
             suma(6,E2,2,5,C5,4,D7,F8,7,45),
             suma(C1,F2,9,6,D5,C6,2,3,1,45),
             suma(7,G2,D3,D4,8,2,9,G8,D9,45),
             suma(D1,H2,E3,1,9,D6,E7,H8,6,45),
            
             /* cajas */
            
             suma(5,A1,4,A2,B2,1,A3,7,6,45),
             suma(3,B1,6,C2,D2,E2,B3,C3,2,45),
             suma(C1,7,D1,F2,G2,H2,9,D3,E3,45),
             suma(A4,8,B4,7,6,A5,9,A6,3,45),
             suma(7,C4,5,B5,3,C5,8,B6,4,45),
             suma(6,D4,1,D5,8,9,C6,2,D6, 45),
             suma(A7,B7,8,A8,B8,C8,A9,3,B9,45),
             suma(1,C7,D7,D8,E8,F8,4,C9,7,45),
             suma(2,9,E7,3,G8,H8,1,D9,6,45).
            

por cierto, este programa está en el antiguo turbo Prolog 2.0 de Borland.

La conclusión inicial es que si tuviésemos memoria infinita y poder de procesamiento infinito, las soluciones tipo prolog, resolviendo todo el árbol de búsquedas (árbol solución), podría llegar a la conclusión del resultado correcto. Pero en la vida real, al tener limitaciones en memoria y velocidad de proceso, esto desde luego vuelve impráctico este enfoque.

Cabe decir que no por ello prolog no es útil para resolver problemas. Simplemente el sudoku -utilizando el esquema de fuerza bruta- no es el más adecuado.