Sto usando un solutore SAT per codificare un problema e, come parte dell'istanza SAT, ho variabili booleane dove è inteso che esattamente uno di questi dovrebbe essere vero e il resto dovrebbe sii falso. (A volte ho visto questo descritto come una codifica "one-hot".)
Voglio codificare il vincolo "esattamente uno su deve essere vero" in SAT. Qual è il modo migliore per codificare questo vincolo, per far funzionare il solutore SAT nel modo più efficiente possibile?
Vedo molti modi per codificare questo vincolo:
Vincoli a coppie. Potrei aggiungere vincoli a coppie per tutti i , j per garantire che al massimo uno x i sia vero, quindi aggiungere x 1 ∨ x 2 ∨ ⋯ ∨ x n per garantire che almeno uno sia vero.
Questo aggiunge clausole e nessuna variabile extra booleana.
Codifica binaria. Ho potuto introdurre nuove variabili booleane i 1 , i 2 , ... , i lg n per rappresentare (in binario) un intero i tale che 1 ≤ i ≤ n (aggiungendo qualche vincoli booleani per garantire che i è nell'intervallo desiderato ). Quindi, posso aggiungere vincoli imponendo che x i sia albero e che tutti gli altri x j siano falsi. In altre parole, per ogni j , aggiungiamo clausole che impongono che i ⇔ x .
Questo aggiunge clausole e non so quante variabili extra booleane.
Conta il numero di valori reali. Potrei implementare un albero di circuiti sommatori booleani e richiedere che , trattando ogni x i come 0 o 1 invece di falso o vero, e utilizzare la trasformazione Tseitin per convertire il circuito in SAT clausole. È sufficiente un albero di semi-additivi: vincola l'output carry di ciascun mezzo-sommatore su 0 e limita l'output finale del mezzo-sommatore finale sull'albero su 1. L'albero può essere scelto per avere qualsiasi forma ( albero binario bilanciato, o sbilanciato, o altro).
Questo può essere fatto in gate e quindi aggiunge Θ ( n ) clausole e Θ ( n ) nuove variabili booleane.
Un caso particolare di questo approccio è quello di introdurre variabili booleane , con l'idea che y i dovrebbe contenere il valore di x 1 ∨ x 2 ∨ ⋯ ∨ x i . Questo intento può essere applicato aggiungendo le clausole y i ∨ ¬ x i , y i ∨ ¬ y i - 1 e ¬ y i ∨ x i ∨ y i -(dove trattiamo come sinonimo di false) per i = 1 , … , n . Successivamente, possiamo aggiungere le restrizioni ¬ y i ∨ ¬ x i + 1 per i = 1 , 2 , … , n - 1 . Questo è sostanzialmente equivalente alla trasformazione di Tseitin di un albero a mezzo sommatore, in cui l'albero ha una forma al massimo sbilanciata.
Rete di farfalle. Potrei costruire una rete di farfalle su bit, vincolare l' ingresso n -bit a 000 ⋯ 01 , limitare l' uscita n -bit a x 1 x 2 ⋯ x n e trattare ogni gate farfalla a 2 bit come un gate indipendente che scambia o non scambia il suo input con la decisione di fare in base a una nuova variabile booleana che non è vincolata. Quindi, posso applicare la trasformazione Tseitin per convertire il circuito in clausole SAT.
Ciò richiede gate e quindi aggiunge Θ ( n lg n ) clausole e Θ ( n lg n ) nuove variabili booleane.
Ci sono altri metodi che ho trascurato? Quale dovrei usare? Qualcuno ha provato questo o li ha provati sperimentalmente o qualcuno ha qualche esperienza con uno di questi? Il numero di clausole e / o il numero di nuove variabili booleane è una buona metrica stand-in per stimare l'impatto di questo sulle prestazioni del solutore SAT o, in caso contrario, quale metrica useresti?
Ho appena notato che questa risposta ha alcuni riferimenti sull'applicazione dei vincoli di cardinalità per SAT, vale a dire, l'applicazione del vincolo che esattamente su n variabili sono vere. Quindi, la mia domanda si riduce a un caso speciale in cui k = 1 . Forse la letteratura sui vincoli di cardinalità aiuterà a far luce sulla mia domanda.