Programmazione a vincoli

Da Wikipedia, l'enciclopedia libera.

La programmazione a vincoli, detta anche programmazione con vincoli o constraint è un paradigma di programmazione dove le relazioni fra variabili possono essere dichiarate in forma di vincoli. I vincoli differiscono dalle primitive normalmente definite dagli altri linguaggi di programmazione per il fatto che non specificano azioni singole da eseguire passo-passo, ma piuttosto si limitano a specificare le proprietà di cui deve essere dotata la soluzione da trovare. I vincoli usati possono essere di vari tipi: quelli basati sul cosiddetto problema di soddisfacimento di vincoli (Constraint satisfaction problem o CSP), quelli risolvibili mediante l'algoritmo del Simplesso (Simplex Algorithm) ed altri. I vincoli da applicare possono essere forniti embedded nel linguaggio di programmazione, oppure in librerie separate.

La programmazione a vincoli iniziò come programmazione logica a vincoli, introducendo vincoli integrati in un programma di tipo logico. Questa variante della programmazione logica fu opera di Jaffar e Lassez, che, nel 1987, svilupparono una classe di vincoli specificatamente progettata per essere usata nel linguaggio Prolog II. Le prime implementazioni di programmazione logica a vincoli furono Prolog III, CLP(R), e CHIP. Attualmente esistono molti interpreti per programmi logici a vincoli, come per esempio GNU Prolog.

A differenza dalla programmazione logica, i vincoli possono essere inseriti nella programmazione funzionale, nella riscrittura e nei linguaggi imperativi. Nella programmazione funzionale i vincoli sono implementati ad esempio nel linguaggio di programmazione multi-paradigma Oz. Vincoli sono embedded (integrati) nel linguaggio imperativo Kaleidoscope. Nei linguaggi imperativi, tuttavia, i vincoli sono implementati principalmente mediante i cosiddetti constraint solving toolkits, che sono librerie separate, fornite insieme al linguaggio. ILOG CP Optimizer, è un esempio è di queste librerie per C++, Java e .NET.

Programmazione logica a vincoli[modifica | modifica sorgente]

La programmazione a vincoli consiste nell'integrazione di vincoli all'interno di un linguaggio che funge da host. I primi linguaggi usati per fungere da host furono linguaggi di tipo logico, tanto che queste applicazioni vennero inizialmente chiamate programmazione logica a vincoli. I due paradigmi condividono molte importanti caratteristiche, come le variabili logiche ed il backtracking. Attualmente la maggior parte delle implementazioni di Prolog includono una o più librerie per supportare la programmazione logica a vincoli. Le differenze fra programmi logici e programmi a vincoli è sostanzialmente determinata dallo stile usato per creare modelli di simulazione del mondo reale. A seconda dei casi uno dei due stili di programmazione risulta più semplice e "naturale" da adottare.

L'approccio su cui si fonda la programmazione a vincoli è cercare uno "stato" del "mondo" in cui un grande numero di vincoli sono contemporaneamente soddisfatti. Si assume che risolvere un "problema" equivalga a trovare un "mondo possibile" descritto da un numero (inizialmente sconosciuto) di variabili. Il programma va alla ricerca dei valori che, attribuiti alle variabili, meglio definiscono il "mondo" soggetto ai vincoli imposti.

La programmazione a vincoli temporal concurrent (TCC) e la programmazione a vincoli temporal concurrent non-deterministica (NTCC) sono varianti della programmazione a vincoli in cui entra in gioco la variabile tempo.

Lista di alcuni linguaggi di programmazione logica a vincoli:

Domini di applicazione[modifica | modifica sorgente]

I vincoli usati nella programmazione a vincoli appartengono tipicamente ad alcuni specifici domini, fra cui:

I domini finiti sono uno dei campi in cui la programmazione a vincoli ha avuto maggiore successo. In alcune aree (come la ricerca operativa) la programmazione a vincoli è praticamente tutta basata sui domini finiti. Gli algoritmi risolutori sui domini finiti sono utili per risolvere problemi di soddisfacimento di vincoli, e si basano spesso sulla cosiddetta consistenza locale, o su una delle sue approssimazioni.

La sintassi per esprimere vincoli su domini finiti dipende dal linguaggio host. L'esempio che segue è un esempio di programma Prolog che risolve il classico puzzle dei programmi di programmazione a vincoli logici, noto come SEND+MORE=MONEY:

 sendmore(Digits) :-
    Digits = [S,E,N,D,M,O,R,E],     % Crea le variabili
    Digits :: [0..9],               % Associa il dominio alle variabili
    S #\= 0,                        % Vincolo: S deve essere diverso da 0
    M #\= 0,
    alldifferent(Digits),           % Tutti gli elementi devono assumere valori diversi
                 1000*S + 100*E + 10*N + D     % Altri vincoli
               + 1000*M + 100*O + 10*R + E
    #= 10000*M + 1000*O + 100*N + 10*E + Y,
    labeling(Digits).               % Inizia la ricerca della soluzione

L'interprete crea una variabile per ciascuna lettera del puzzle. Il simbolo :: è usato per specificare il dominio di queste variabili, in modo da consentire il range di valori {0,1,2,3, ..., 9}. I vincoli S#\=0 and M#\=0 significano che queste due variabili non possono assumere il valore zero. Quando l'interprete elabora ed applica questi vincoli, restringe i domini di queste due variabili rimuovendo da essi il valore 0. Poi viene elaborato il vincolo alldifferent(Digits), che non produce la riduzione di alcun dominio, ma è semplicemente memorizzato. L'ultimo vincolo impone che i digit assegnati alle lettere devono essere tali che l'espressione "SEND+MORE=MONEY" rimanga valida quando a ciascuna lettera venga sostituito il proprio corrispondente digit. Dall'analisi di questo vincolo, mediante un'operazione di inferenza, il programma solver deduce che M=1. Di conseguenza tutti i vincoli precedentemente memorizzati, e contenenti la variabile M, sono riesaminati: nell'esempio, mediante la propagazione del vincolo (constraint propagation) sul vincolo alldifferent, il valore 1 viene rimosso dal dominio di tutte le altre variabili. La propagazione del vincolo può risolvere il problema riducendo tutti i domini ad un singolo valore, oppure arrivare a dimostrare che il problema non ammette soluzioni, riducendo il dominio ad un insieme vuoto. Inoltre può anche concludersi senza dimostrare né la soddisfabilità, né l'insoddisfabilità del problema. I letterali etichettati con labeling sono usati per avviare l'effettiva ricerca di una soluzione.

Programmazione a vincoli in linguaggi imperativi[modifica | modifica sorgente]

La programmazione a vincoli è possibile anche con alcuni linguaggi imperativi utilizzando librerie separate. Alcune fra le più popolari librerie sono:

Collegamenti esterni[modifica | modifica sorgente]


Voci correlate[modifica | modifica sorgente]