La programació lògica amb restriccions (CLP, per les seves sigles en anglès) és una extensió de la programació lògica que permet treballar amb restriccions en lloc de simples fets i regles. Aquesta tècnica és especialment útil per a problemes d'optimització, planificació i altres problemes que impliquen restriccions complexes.

Conceptes Clau

  1. Què és una Restricció?

Una restricció és una condició que ha de ser satisfeta per a que una solució sigui vàlida. En el context de CLP, les restriccions es poden expressar com a relacions entre variables.

  1. Domini de les Variables

El domini d'una variable és el conjunt de valors que aquesta variable pot prendre. En CLP, els dominis poden ser finits o infinits.

  1. Solucionadors de Restriccions

Un solucionador de restriccions és un algorisme que troba valors per a les variables que satisfan totes les restriccions imposades.

Exemples Pràctics

Exemple 1: Problema de les N-Reines

El problema de les N-reines consisteix a col·locar N reines en un tauler de N x N de manera que cap reina pugui atacar una altra. Això significa que no hi pot haver dues reines en la mateixa fila, columna o diagonal.

:- use_module(library(clpfd)).

n_reines(N, Reines) :-
    length(Reines, N),
    Reines ins 1..N,
    totes_diferents(Reines),
    no_ataca(Reines),
    labeling([], Reines).

totes_diferents([]).
totes_diferents([X|Xs]) :-
    all_different(Xs),
    totes_diferents(Xs).

no_ataca([]).
no_ataca([X|Xs]) :-
    no_ataca(Xs, X, 1),
    no_ataca(Xs).

no_ataca([], _, _).
no_ataca([Y|Ys], X, Dist) :-
    X #\= Y,
    X #\= Y + Dist,
    X #\= Y - Dist,
    Dist1 #= Dist + 1,
    no_ataca(Ys, X, Dist1).

Explicació del Codi

  1. Importació del Mòdul CLP(FD): :- use_module(library(clpfd)). importa el mòdul de restriccions sobre dominis finits.
  2. Definició del Problema: n_reines/2 defineix el problema de les N-reines.
    • length(Reines, N): Crea una llista de longitud N.
    • Reines ins 1..N: Defineix el domini de les variables.
    • totes_diferents(Reines): Assegura que totes les reines estan en diferents columnes.
    • no_ataca(Reines): Assegura que les reines no es poden atacar entre elles.
    • labeling([], Reines): Troba una solució que satisfaci totes les restriccions.
  3. Restriccions de Diferència: totes_diferents/1 assegura que totes les reines estan en diferents columnes.
  4. Restriccions de No Atac: no_ataca/1 assegura que les reines no es poden atacar en les diagonals.

Exemple 2: Problema de la Mochila

El problema de la mochila consisteix a seleccionar un subconjunt d'objectes amb pesos i valors donats per maximitzar el valor total sense excedir un pes màxim.

:- use_module(library(clpfd)).

mochila(Pesos, Valors, Capacitat, Seleccio, ValorTotal) :-
    length(Pesos, N),
    length(Seleccio, N),
    Seleccio ins 0..1,
    scalar_product(Pesos, Seleccio, #=<, Capacitat),
    scalar_product(Valors, Seleccio, #=, ValorTotal),
    labeling([maximize(ValorTotal)], Seleccio).

Explicació del Codi

  1. Importació del Mòdul CLP(FD): :- use_module(library(clpfd)). importa el mòdul de restriccions sobre dominis finits.
  2. Definició del Problema: mochila/5 defineix el problema de la mochila.
    • length(Pesos, N): Obté el nombre d'objectes.
    • length(Seleccio, N): Crea una llista de selecció de longitud N.
    • Seleccio ins 0..1: Defineix el domini de les variables de selecció (0 o 1).
    • scalar_product(Pesos, Seleccio, #=<, Capacitat): Assegura que el pes total no excedeixi la capacitat.
    • scalar_product(Valors, Seleccio, #=, ValorTotal): Calcula el valor total dels objectes seleccionats.
    • labeling([maximize(ValorTotal)], Seleccio): Troba una solució que maximitzi el valor total.

Exercicis Pràctics

Exercici 1: Sudoku

Implementa un solucionador de Sudoku utilitzant CLP.

Solució

:- use_module(library(clpfd)).

sudoku(Rows) :-
    length(Rows, 9),
    maplist(same_length(Rows), Rows),
    append(Rows, Vs), Vs ins 1..9,
    maplist(all_distinct, Rows),
    transpose(Rows, Columns),
    maplist(all_distinct, Columns),
    Rows = [A,B,C,D,E,F,G,H,I],
    blocks(A, B, C), blocks(D, E, F), blocks(G, H, I),
    maplist(label, Rows).

blocks([], [], []).
blocks([A,B,C|Bs1], [D,E,F|Bs2], [G,H,I|Bs3]) :-
    all_distinct([A,B,C,D,E,F,G,H,I]),
    blocks(Bs1, Bs2, Bs3).

Exercici 2: Problema de la Coloració de Grafs

Implementa un solucionador per al problema de la coloració de grafs utilitzant CLP.

Solució

:- use_module(library(clpfd)).

coloracio_graf(Nodes, Edges, Colors) :-
    length(Nodes, N),
    Nodes ins 1..Colors,
    maplist(no_same_color(Nodes), Edges),
    labeling([], Nodes).

no_same_color(Nodes, (A, B)) :-
    nth1(A, Nodes, ColorA),
    nth1(B, Nodes, ColorB),
    ColorA #\= ColorB.

Resum

En aquesta secció, hem après sobre la programació lògica amb restriccions (CLP) i com utilitzar-la per resoldre problemes complexos. Hem vist exemples pràctics com el problema de les N-reines i el problema de la mochila, i hem proporcionat exercicis per practicar. La CLP és una eina poderosa que amplia les capacitats de la programació lògica tradicional, permetent treballar amb restriccions i dominis de variables de manera eficient.

© Copyright 2024. Tots els drets reservats