SAT/SMTã½ã«ããèªä½ãã¦ã¿ã話
ãã®è¨äºã¯ Kobe University Advent Calendar 2017 - Adventar 17æ¥ç®ã®è¨äºã§ãã
1å¹´ãããåã«C3ã¨ããSMTã½ã«ããCè¨èªã§ã¹ã¯ã©ããããä½ã£ãã®ã§ããã®è©±ã§ããã¾ãã
ããã«ãã£ã¦ãªãSMTã½ã«ããCã§æ¸ãããã¨ããã¨ãè¥æ°ã®è³ãã§ãã¤ãã¼ãã¤ã¶ã«çµã¿è¾¼ãã ããã¦éãã§ãããã§ãã
ã²ã¹ãã·ã¹ãã ã®æ¤è¨¼ãã©ã³ã¿ã¤ã ã«ãã¦ãããè¶
軽éãªãã¤ãã¼ãã¤ã¶ãã£ããã«ãã³ã¤ã¤ãããªãã§ããã
ã¨ããå²ã¨é©å½ãªçç±ã§ä½ã£ããã§ãããå´åã«å¯¾ããææããã¾ãã«ãè¦åããªãããã¦ãä»ã¯ã¢ããã¼ããå¤ãã¦ãã¾ãã
ããããããã§éå»ã®éºç©ããçã¾ããCè¨èªè£½SMTã½ã«ãC3ãªã®ã§ããããã®ã¾ã¾ãèµå
¥ããããã®ãä½ãªã®ã§ã³ã¼ãã®è§£èª¬ã¨ãSMTã½ã«ããã©ããã£ã¦åãã¦ãã®ãã¿ãããªè©±ããã¦ã¿ã¾ãã
ã ãã¨ãç§ã¯ä¸ä»ã®æ å ±ç³»å¦çã§è«çå¦å¾ã§ã¯ãªãã®ã§ãã¨ããã©ããä¸æ£ç¢ºãªè¡¨ç¾ããããããããªãã®ã§ææãã¦ããã ããã°å¹¸ãã§ãã
1. SATã½ã«ãã¨ã¯
SMTã½ã«ãã®èª¬æã®åã«ã¾ãSATã½ã«ãã®èª¬æããã¾ãã
SATã¨ã¯satisfiability problem(å
足å¯è½æ§åé¡)ã®ç¥ã§ãã
å
足å¯è½æ§åé¡ã¨ããã®ã¯ãä¸ã¤ã®å½é¡è«çå¼ãä¸ããããã¨ããããã«å«ã¾ããå¤æ°ã®å¤ãå½ (False) ãããã¯ç (True) ã«ãã¾ãå®ãããã¨ã«ãã£ã¦å
¨ä½ã®å¤ã'ç'ã«ã§ããããã¨ããåé¡ã§ã¯ã©ã¹ã¨ãã¦ã¯NPå®å
¨åé¡ã«ãªãã¾ãã
SATã½ã«ãã¯å
¥åã¨ãã¦å½é¡è«çå¼ãåãåããå¼å
¨ä½ã®å¤ã'ç'ã«ã§ãã(SAT)å ´åã¯åå¤æ°ã«å¯¾ããå
·ä½çãªçå½å¤å²ãå½ã¦ãåºåããããã§ãªãå ´åã¯å
足ä¸è½(UNSAT)ã§ããæ¨ãåºåãã¾ãã
ä¾ãã°ä»¥ä¸ã®ãããªè«çå¼ãä¸ããããæã
x1=ç, x2=å½, ã代å
¥ããã¨è«çå¼ã¯çã«ãªãã®ã§ã(1,0)ã¨ãããããªåºåããã¾ãã
ããå°ãããã¨ããä¾ã¨ãã¦æ°ç¬ã解ãã¦ã¿ã¾ãããã
æ°ç¬ã¨ããã®ã¯ä»¥ä¸ã®ãããªæãã§ã
. .|. 4 . .|1 2 ---+---- . 1|4 3 4 3|2 1
- åãã¹ã« 1 ãã 4 ã®ãããããå ¥ã
- åè¡ã«åãæ°åã 2 å以ä¸ç¾ããªã
- ååã«åãæ°åã 2 å以ä¸ç¾ããªã
- åãããã¯ã«åãæ°åã 2 å以ä¸ç¾ããªã
ã®ã«ã¼ã«ãæºãããããªæ°åã空ãã¦ãç®æã«å
¥ããã¨ããç©ã§ããããæ°èãªããã«è¼ã£ã¦ããã¤ã§ããã
ã§ããã¤ã¯å®ã¯å
足å¯è½æ§åé¡ã«è½ã¨ãè¾¼ãã¾ãã
詳ããã¯ä»¥ä¸ãè¦ã¦ããã ããã°è¯ãã§ããã
SAT ソルバで数独を解く方法 - まめめも
è¦ããã«åãã¹ã«å¤æ°ãå²ãå½ã¦ã¦
a b|c d e f|g h ---+--- i j|k l m n|o p
åå¤æ°ã«å¯¾ãã¦1~4ã®ã©ã®æ°åãå ¥ãããa1-a4ã¨ããå¤æ°ã§è¡¨ããã¨ã«ãã¾ããã¤ã¾ã
- a1 ã true ã®ã¨ããa ã®ãã¹ã«ã¯ 1 ãå ¥ã
- a2 ã true ã®ã¨ããa ã®ãã¹ã«ã¯ 2 ãå ¥ã
- a3 ã true ã®ã¨ããa ã®ãã¹ã«ã¯ 3 ãå ¥ã
- a4 ã true ã®ã¨ããa ã®ãã¹ã«ã¯ 4 ãå ¥ã
ã¦ãªæãã§ãã
ãã¨ã¯ãããå¤æ°ã使ã£ã¦æ°ç¬ã®ã«ã¼ã«éãã«è«çå¼ãçµã¿ç«ã¦ã¦è¡ããã§ããã説æããã®ãé¢åãªã®ã§è©³ããã¯ä¸ã®URLãè¦ã¦ãã ããã
ã§ãç§ãä½ã£ãC3ã½ã«ãã¯SATã½ã«ããããã®ã§å®éã«è§£ãã¦ã¿ã¾ãããã
GitHub - RKX1209/c3: The C3, SMT/SAT solver written in C.
ã§ã
$ make $ ./test/sudoku/gen_cnf.sh /usr/bin/c3 -D /tmp/sudoku.cnf > /tmp/c3-test/gen_cnf-BIfeLg/out 2> /tmp/c3-test/gen_cnf-BIfeLg/err
ã¨ãããã¨ä¸ã«æ¸ããæ°ç¬ã®çãã /tmp/c3-test/gen_cnf-BIfeLg/err ã«åºåããã¦ã¾ãã
$ tail /tmp/c3-test/gen_cnf-BIfeLg/err (x1 or x3) and (!x3) and (!x27) and (!x38) and (!x3) and (!x38) and (!x27) and (!x3) and (!x27) and (!x38) found one literal -3(0x2431850) (x1) and (!x27) and (!x38) and (!x38) and (!x27) and (!x27) and (!x38) found one literal -27(0x2432b90) (x1) and (!x38) and (!x38) and (!x38) found one literal -38(0x2433960) (x1) found one literal 1(0x242f880) s SATISFIABLE v 1 -2 -3 -4 -5 6 -7 -8 -9 -10 11 -12 -13 -14 -15 16 -17 -18 19 -20 -21 -22 -23 24 25 -26 -27 -28 -29 30 -31 -32 -33 34 -35 -36 37 -38 -39 -40 -41 -42 -43 44 -45 -46 47 -48 -49 -50 -51 52 -53 -54 55 -56 -57 58 -59 -60 61 -62 -63 -64 0
ã¯ãããªãããã°ãããã£ã¨åºã¦ã¾ãã大äºãªã®ã¯
s SATISFIABLE v 1 -2 -3 -4 -5 6 -7 -8 -9 -10 11 -12 -13 -14 -15 16 -17 -18 19 -20 -21 -22 -23 24 25 -26 -27 -28 -29 30 -31 -32 -33 34 -35 -36 37 -38 -39 -40 -41 -42 -43 44 -45 -46 47 -48 -49 -50 -51 52 -53 -54 55 -56 -57 58 -59 -60 61 -62 -63 -64 0
ã§ãã ãããçµæã§ãa1,a2,a3,a4, b1,b2,b3...... p1,p2,p3,p4ã¨ãã64åã®å¤æ°ãå
é¨ã§1~64ã¾ã§çªå·ä»ãããã¦ãããçµæã®1ã¨ããã®ã¯1 = trueã§-2ã¨ããã®ã¯2=falseã¨ããããã«ç¬¦å·ã-ã§ããã°falseã表ãã¾ãã
ã§ãããã¤ãæ°ç¬ã®çµæã«å½ã¦ã¯ããã¨
a1 = true, b2=true, c3=true, e3=true, f4=true, i2=true (æ¢ã«æ°åãå ¥ã£ã¦ãå¤æ°ã¯çç¥)
ã§ããç¤é¢ã«èµ·ããã¨
1 2|3 4 3 4|1 2 ---+---- 2 1|4 3 4 3|2 1
ã¯ããæ£ãã解ãã¦ã¾ãã
ã¨ããããã§C3ã¯å 足å¯è½æ§åé¡ã®å¿ç¨ä¾ã®ä¸ã¤ã¨ãã¦æ°ç¬ã解ãã¾ãã
2. DIMACSãã©ã¼ããã
ä¸ã§SATã½ã«ãã®åºæ¬ã説æãã¾ããã
æ®ã©ã®SATã½ã«ãã¯å
¥åã¨ãã¦é£è¨æ¨æºå½¢(CNF)ãåãåãã¾ãã
ã½ã«ãã®ã¢ã«ã´ãªãºã çã«ãCNFã対象ã¨ããæ¹ãä½ãã¨é½åãè¯ãã±ã¼ã¹ãå¤ãããã§ãã
è«çå¼ã¯ã©ã¹ãCNFã«çµã£ãSATãç¹ã«CNF-SATã¨è¨ã£ã¦ãä¸è¬ã«æ®ã©ã®SATã½ã«ãã¯CNF-SATã解ãç©ã«ãªã£ã¦ãã¾ãã
ä»»æã®å½é¡è«çå¼ãCNFã«å¤æããããã®ã¢ã«ã´ãªãºã (Tseitin Encoding)ãããã®ã§SATã½ã«ãèªä½ã¯å
¥åãCNFã«çµã£ã¦ãåé¡ãªãããã§ããã¡ãªã¿ã«CNF-SATãNPå®å
¨åé¡ã§ãã
ãã¦ãã®CNFãSATã½ã«ãã«å
¥åã¨ãã¦ä¸ããéã®ãã©ã¼ãããã¨ããã®ããã£ã¦ãDIMACSã¨ããã®ãããã¡ã¯ãã¹ã¿ã³ãã¼ãã§ãã
DIMACSã«ã¤ãã¦ã¯ä»¥ä¸åç
§ãã¾ãã¨ã¦ãåç´ãªãã©ã¼ãããã§ãã
2009-02-08 - ひとり勉強会
C3ã¯-Dãªãã·ã§ã³ãã¤ãããã¨ã§DIMACSå½¢å¼ãèªãã§SATã½ã«ãã§è§£ããã¨ãåºæ¥ã¾ãã
$ ./c3 -D ./test/simple.cnf c: comment c: comment p: header size=3, val=5 1 -5 4 -1 5 3 4 -3 -4 (x1 or !x5 or x4) and (!x1 or x5 or x3 or x4) and (!x3 or !x4) assume 5 (x1 or x4) and (!x4 or !x3) pure literal -3 0x5626677ed030 (x1 or x4) pure literal 1 0x5626677ed030 s SATISFIABLE v 1 2 -3 4 5 0 Verifying.... [SUCCESS]
3. SMTã½ã«ã
ãã¦ãã§ã¯SMTã½ã«ãã®èª¬æãç°¡åã«ãã¾ãã
SMTã¯Satisfiable Modulo Theoriesã®ç¥ã§ãä¸éè¿°èªè«çå¼ã®å
足å¯è½æ§ãå¤å®ãã¦ãããç¹ãSATã½ã«ãã¨ç°ãªãã¾ããå½é¡è«çããã表ç¾åãä¸ããã®ã§ãã½ããã¦ã§ã¢ã®æ¤è¨¼ãå®ç証æçã«å¿ç¨ããã¾ãã
SMTã½ã«ãã®åºæ¬çãªæ§æã¯"SATã½ã«ã" + "çè«ã½ã«ã"ã§ãã大ã¾ããªæ§å³ã¯ä»¥ä¸ã®ããã«ãªã£ã¦ãã¾ãã
SAT/SMTソルバの仕組み ãã
ã¤ã¾ãa > 0ãb-2c >= 0ã¨ãã£ãçè«ã«ä¾åããé
ã®å
容ãAbstractionã«ãã£ã¦è«çå¤æ°ã«å¤æãã
SATã½ã«ãã«å
足å¯è½æ§ã解ãã¦ããã£ãå¾ãAbstractionã«ãã£ã¦å¤±ãããã»ãã³ãã£ã¯ã¹ãçè«ã½ã«ãå´ã§èæ
®ãã¦ãæ¬å½ã«å¯è½ãªçå½å¤å²ãå½ã¦ãªã®ããæ¤è¨¼ããå¾ããã£ã¼ãããã¯çã«å度å¶ç´ã追å ããã¨ããç©ã§ãã
4. BitVectorã»ãªãªã¼
ãã¦ãSMTã½ã«ãã§æ±ããçè«ã«ã¯æ´æ°ãæçæ°ã®ç®è¡ãé¢æ°ãçå·ã«é¢ããçè«çããã®ã§ãããä»åC3ã§å®è£
ããã®ã¯ãBitVectorã¨å¼ã°ããçè«ã§ãã
ãã®çè«ã¯ä¸»ã«ã½ããã¦ã§ã¢ããã¼ãã¦ã§ã¢ã®æ¤è¨¼ã«ä½¿ç¨ããããã«ã¡ã¢ãªã®ã¢ãã«åãç®æãããã®ã§ãã
å
·ä½çã«ã¯ãã½ããã¦ã§ã¢ä¸ã§æ±ãããæ´æ°çã2é²æ°ã®ãã¤ããªbitã¨ãã¦æ±ããããã»ããµåæ§ã«å æ¸ä¹é¤ç®ã符å·æ¡å¼µæä½ã¨ãã£ããããæ¼ç®ãæ±ãçè«ã§ãã
å
·ä½çãªææ³ã¯ä»¥ä¸ã®ããã«ãªã£ã¦ãã¾ãã
formula : formula ⨠formula | ¬formula | atom atom : term rel term | Boolean-Identifier | term[ constant ] rel : = | < term : term op term | identifier | â¼ term | constant | atom?term:term | term[ constant : constant ] | ext( term ) op : + | â | · | / | << | >> | & | | | â | ⦠⼠x: bit-wise negation of x ext(x): sign- or zero-extension of x x << d: left shift with distance d x ⦠y: concatenation of x and y
ä¾ãã°a+bã¨ããå¼ã¯BitVectorã§ã¯å
¨å ç®å¨ãã¢ãã«ã¨ãã¦ä»¥ä¸ã®ããã«æ±ããã¾ãã
http://www.decision-procedures.org/slides/bit-vectors.pdfãã
1-bitã®å ç®ã¯å ¨å ç®å¨ã®è«çå¼ãCNFã«å¤æããå³ã®ä¸ã«ãããããªå½é¡è«çã§è¡¨ãã¾ãã
ã¾ãè¦ããã«CPUã®ããã»ããµã¼(è«çåè·¯)ãè¡ã£ã¦ããè«çæ¼ç®ãããããCNFã«å¤æãã¦ãããããªçè«ã§ãã
ããã°ã©ã ã®ãããªè¤éãªè«çæ¼ç®ã®éåããå
¨ã¦CNFã«å¤æãã¦SATã½ã«ãã«é£ãããã¨ããã®ãBitVectorãå®è£
ããSMTã½ã«ãã®æ¦è¦ã§ãã
ãã£ã¦çè«ã½ã«ããå¿ è¦ããã¾ããããªããªãããããBitVectorã§ã¯åå¤æ°ãããã0/1ã表ããããªçè«ã§ãããããBoolean Abstractionçã®æä½ãè¡ããªãã¦ããCNFã«ããå¤æãã¦ãã¾ãã°ãã®ã¾ã¾SATã½ã«ãã«é£ãããããããã§ãã
BitVecotrã«ã¤ãã¦è©³ããã¯ä»¥ä¸åç
§ã
Bit-Vectors: Decision Procedures An Algorithmic Point of View
http://www.decision-procedures.org/slides/bit-vectors.pdf
5. å®è£ (SMTã½ã«ã)
ãã¦ãã§ã¯C3ã®ã³ã¼ããè¦ãªããSMTã½ã«ãã®å®è£
ã«ã¤ãã¦ã¡ããã£ã¨è§£èª¬ãã¾ãã
SMTã½ã«ãã¯æ¤è¨¼ãããæ¡ä»¶å¼ãªã©ãSMTLIB2ã¨ãããã©ã¼ãããã§è¨è¿°ãããã¡ã¤ã«ãå
¥åã¨ãã¦åãåãã¾ãã
SMTLIB2ã®ä»æ§æ¸ã¯ããã«ããã¾ãã
The SMT-LIB Standard Version 2.5
SMT-LIB The Satisfiability Modulo Theories Library
C3ã®ã¬ãã¸ããªã«ããµã³ãã«ãããã¾ãã
$ cat test/sign-extend.smt2 (set-logic QF_BV) (set-info :smt-lib-version 2.0) (echo "This is simple Sign Extend test") (declare-fun x () (_ BitVec 2)) ; sext1(x[2:]) < 0[3:] xor x[2:] < 0[2:] ; sext1(x) < 0 is equivalence to x < 0 ; This proposition must be true. Result of oppsition should become unsat (i.e. no counter example). (assert (xor (bvslt ((_ sign_extend 1) x) (_ bv0 3)) (bvslt x (_ bv0 2)))) (exit)
;ã¯ã³ã¡ã³ãã§ããã¾ã(set-logic QF_BV)ãæå®ããäºã§BitVectorçè«ã使ç¨ããäºã宣è¨ãã¾ãã
åºæ¬ææ³ã¯Så¼ã§ãã assertã証æãããä»®å®ã§ããå¾ã¯xorã¨ãbvsltã¨ãããããæ¼ç®ãããã¾ãããè¦ããã«ãã®ãµã³ãã«ã示ãããä»®å®ã¯
sext1(x) < 0 <=> x < 0
ã§ããxãè² æ°ã§ããäºã¨xã符å·æ¡å¼µããç©ãåããè² æ°ã§ããäºãåå¤ã§ããã¨è¨ã£ã¦ãã¾ãã
ã¾ãç´æçã«ãæããã§ããããã®ä»®å®ã¯æ£ããã§ããå®éãã®assertã¯UNSATã«ãªãã¾ãã
sext1(x) < 0 xor x < 0ãUNSATãªã®ã§ã両è
ã1,0ã0,1ã¨ãã£ãç°ãªãçå½å¤ãåãäºãç¡ããã¤ã¾ãåå¤ã§ãã
ã¨ããäºã§ãã
ã§ã¯C3ã®å®è£
ãè¦ã¦ã¿ã¾ãããã
C3ã¯ä¸è¨ã®ãããªSMTLIB2ãã©ã¼ããããã¡ã¤ã«ãåãåãã¨ã¾ãåå¥è§£æã¨æ§æ解æãè¡ãã¾ãã
(flexã¨bisonã使ç¨ãã¦ãã¾ã)
ã¾ãã¯åå¥è§£æã§ãããã¾ãããã¯å¤æ°åã«è©²å½ããåå¥è¦åãè¦ã¤ããããã¼ãã«ã«è¨é²ãããããããç¹çããäºã¯ãªãã§ãã
parser/smt2.lex
c3/smt2.lex at master · RKX1209/c3 · GitHub
%{ /* C3 Theorem Prover - Apache v2.0 - Copyright 2017 - rkx1209 */ #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <c3_core.h> #include "parsesmt2.h" extern char *yytext; char *string_lit = NULL; static int lookup(char *s) { char * cleaned = NULL; size_t len; // The SMTLIB2 specifications sez that the outter bars aren't part of the // name. This means that we can create an empty string symbol name. if (s[0] == '|' && s[(len = strlen(s))-1] == '|') { cleaned = (char*) malloc(len); strncpy(cleaned,s+1,len-2); // chop off first and last characters. cleaned[len-2] = '\0'; s = cleaned; } bool found = false; ASTNode *sym_ast; if ((sym_ast = c3_lookup_symbol(&c3, s))) { found = true; } if (found) { if (cleaned) { free (cleaned); } yylval.node = ast_dup_node (sym_ast); if (ast_get_type (yylval.node) == BOOLEAN_TYPE) { printf ("FORMID: %s\n", s); return FORMID_TOK; } else { printf ("TERMID: %s\n", s); return TERMID_TOK; } } else { if (cleaned) free (cleaned); yylval.str = strdup (s); printf ("LITERAL: %s\n", s); return STRING_TOK; } } %} %option noyywrap LETTER ([a-zA-Z]) DIGIT ([0-9]) OPCHAR ([~!@$%^&*\_\-+=<>\.?/]) ANYTHING ({LETTER}|{DIGIT}|{OPCHAR}) %% [ \n\t\r\f] { /* skip */ } {DIGIT}+ { yylval.uintval = strtoul(yytext, NULL, 10); return NUMERAL_TOK; } bv{DIGIT}+ { yylval.str = strdup(yytext + 2); return BVCONST_DECIMAL_TOK; } #b{DIGIT}+ { yylval.str = strdup(yytext + 2); return BVCONST_BINARY_TOK; } #x({DIGIT}|[a-fA-F])+ { yylval.str = strdup(yytext + 2); return BVCONST_HEXIDECIMAL_TOK; } {DIGIT}+"."{DIGIT}+ { return DECIMAL_TOK; } <STRING_LITERAL>. { size_t old = strlen (string_lit); if (!(string_lit = realloc (string_lit, old + 2))) { c3_fatal_error ("string expansion failed\n"); } string_lit[old] = *yytext; string_lit[old + 1] = '\0'; } <STRING_LITERAL>"\n" { size_t old = strlen (string_lit); if (!(string_lit = realloc (string_lit, old + 2))) { c3_fatal_error ("string expansion failed\n"); } string_lit[old] = *yytext; string_lit[old + 1] = '\0'; } /* Valid character are: ~ ! @ # $ % ^ & * _ - + = | \ : ; " < > . ? / ( ) */ "(" { return LPAREN_TOK; } ")" { return RPAREN_TOK; } "_" { return UNDERSCORE_TOK; } "!" { return EXCLAIMATION_MARK_TOK; } ":" { return COLON_TOK; } /* Set info types */ /* This is a very restricted set of the possible keywords */ ":source" { return SOURCE_TOK;} ":category" { return CATEGORY_TOK;} ":difficulty" { return DIFFICULTY_TOK; } ":smt-lib-version" { return VERSION_TOK; } ":status" { return STATUS_TOK; } /* Attributes */ ":named" { return NAMED_ATTRIBUTE_TOK; } /* COMMANDS */ "assert" { return ASSERT_TOK; } "check-sat" { return CHECK_SAT_TOK; } "check-sat-assuming" { return CHECK_SAT_ASSUMING_TOK;} "declare-const" { return DECLARE_CONST_TOK;} .... (çç¥) ... ({LETTER}|{OPCHAR})({ANYTHING})* { return lookup (yytext); } \|([^\|]|\n)*\| { return lookup(yytext); } . { yyerror("Illegal input character."); } %%
ãã¨ã¯æ§æ解æã§ãããSMTLIB2ã®ä»æ§ãèªã¿ãªãããã®ã¾ã¾æ¸ãã¦ããã ãã§ãã
ãã¼ã¹ããªããASTãçµã¿ç«ã¦ã¦è¡ãã¾ãã
parser/smt2.y
c3/smt2.y at master · RKX1209/c3 · GitHub
%{ #include <stdint.h> #include <stdio.h> #include <string.h> #include <parser/ast.h> #include <parser/parser.h> #include <c3_core.h> #include <c3_utils.h> /* C3 Theorem Prover - Apache v2.0 - Copyright 2017 - rkx1209 */ extern FILE* yyin; extern char* yytext; extern int yylineno; int yyerror(const char *s) { printf ("syntax error: line %d token: %s\n", yylineno, yytext); return 1; } %} %union { unsigned uintval; char *str; ASTNode *node; ASTVec vec; }; %start cmd %type <node> status %type <vec> an_formulas an_terms function_params an_mixed %type <node> an_term an_formula function_param %token <uintval> NUMERAL_TOK %token <str> BVCONST_DECIMAL_TOK %token <str> BVCONST_BINARY_TOK %token <str> BVCONST_HEXIDECIMAL_TOK /* We have this so we can parse :smt-lib-version 2.0 */ %token DECIMAL_TOK %token <node> FORMID_TOK TERMID_TOK %token <str> STRING_TOK BITVECTOR_FUNCTIONID_TOK BOOLEAN_FUNCTIONID_TOK /* set-info tokens */ %token SOURCE_TOK %token CATEGORY_TOK %token DIFFICULTY_TOK %token VERSION_TOK %token STATUS_TOK /* ASCII Symbols */ /* Semicolons (comments) are ignored by the lexer */ %token UNDERSCORE_TOK %token LPAREN_TOK %token RPAREN_TOK /* Used for attributed expressions */ %token EXCLAIMATION_MARK_TOK %token NAMED_ATTRIBUTE_TOK .... (çç¥) ... var_decl: /* (func () (_ BitVec 8)) */ STRING_TOK LPAREN_TOK RPAREN_TOK LPAREN_TOK UNDERSCORE_TOK BITVEC_TOK NUMERAL_TOK RPAREN_TOK { ASTNode *ast_sym = c3_create_variable (0, $7, $1); c3_add_symbol (&c3, $1, ast_sym); } /* (func () Bool) */ .... (çç¥) ... | LPAREN_TOK EQ_TOK an_term an_term RPAREN_TOK { ASTNode *n = ast_create_node2 (EQ, $3, $4); $$ = n; } .... (çç¥) ...
ä¸ã®ã³ã¼ãã§ã¯é©å½ã«2ã¤ç¨ã«ã¼ã«ãè¼ãã¦ã¿ã¾ãããã(func () (_ BitVec 8))ã®ãããªé¢æ°å®£è¨ã§ã¯c3_create_variableã c3_add_symbol ã使ã£ã¦å®£è¨ããé¢æ°åãã·ã³ãã«ã¨ãã¦è¿½å ãã¦ã¾ãã
ãã¨ã¯EQ_TOK(=)æ¼ç®åãæ¥ãæã¯ãast_create_node2ã§2ã¤ã®åãæã¤ASTãã¼ããçæãã¦ã¾ãã
ãã¨ã¯çæããASTãã¼ããå½é¡è«çå¼ã«å¤æããBitBlastingã¨ããå¦çãè¡ãã¾ãã
tosat/bitblaster.c
c3/bitblaster.c at master · RKX1209/c3 · GitHub
/* C3 Theorem Prover - Apache v2.0 - Copyright 2017 - rkx1209 */ #include <parser/ast.h> #include <tosat/bitblaster.h> #include <stdlib.h> C3BitBlast *bb; /* (a == b) <=> (a[0] <-> b[0] && a[1] <-> b[1] && ... a[n] <-> b[n]) */ ASTNode *c3_bitblast_equal(ASTVec left, ASTVec right) { ASTNode *result, *node, *node2; C3ListIter *iter, *iter2; ASTVec ands = ast_vec_new (); if (c3_list_length (left) > 1) { iter2 = right->head; c3_list_foreach (left, iter, node) { node2 = (ASTNode *)iter2->data; ASTNode *biteq = ast_create_node2 (IFF, node, node2); ast_vec_add (ands, biteq); iter2 = iter2->n; } result = ast_create_node (AND, ands); } else { result = ast_create_node2 (IFF, (ASTNode *)left->head->data, (ASTNode *)right->head->data); } return result; } static ASTNode *c3_bitblast_bvle (ASTVec left, ASTVec right, bool sign, bool bvlt) { C3ListIter *lit, *rit; ASTNode *prevbit = bb->ASTTrue; lit = left->head; rit = right->head; while (lit->n != left->tail) { ASTNode *lnode = (ASTNode *)lit->data; ASTNode *rnode = (ASTNode *)rit->data; ASTNode *thisbit = ast_create_node3 (ITE, ast_create_node2 (IFF, rnode, lnode), prevbit, rnode); prevbit = thisbit; lit = lit->n; rit = rit->n; } ASTNode *lmsb = (ASTNode *)lit->data; ASTNode *rmsb = (ASTNode *)lit->data; if (sign) { lmsb = ast_create_node1 (NOT, lmsb); rmsb = ast_create_node1 (NOT, rmsb); } ASTNode *msb = ast_create_node3 (ITE, ast_create_node2 (IFF, rmsb, lmsb), prevbit, rmsb); if (bvlt) { msb = ast_create_node1 (NOT, msb); } return msb; } .... (çç¥) ... ASTVec c3_bitblast_term(ASTNode *term) { const ASTKind k = ast_get_kind (term); ASTVec children = term->children, result; unsigned int numbits = term->value_width; switch (k) { case BVNOT: { const ASTVec kids = c3_bitblast_term ((ASTNode *)children->head->data); result = c3_bitblast_neg (kids); break; } case BVSX: case BVZX: { printf ("BVSXÂ¥n"); /* TODO: */ result = term; break; } case BVCONST: { printf ("BVCONSTÂ¥n"); ASTVec cnts = ast_vec_new (); ASTBVConst *bvconst = term->bvconst; unsigned int i; for (i = 0; i < numbits; i++) { ast_vec_add (cnts, ast_bvc_bit_test (bvconst, i) ? bb->ASTTrue : bb->ASTFalse); } result = cnts; break; } default: break; } return result; } .... (çç¥) ... ASTNode *c3_bitblast_form(ASTNode *form) { ASTNode *result, *child; ASTVec children = form->children; ASTVec echildren = ast_vec_new (); C3ListIter *iter; const ASTKind k = ast_get_kind (form); switch (k) { case TRUE: result = bb->ASTTrue; break; case FALSE: result = bb->ASTFalse; break; case NOT: result = ast_create_node1 (NOT, c3_bitblast_form ((ASTNode *)children->head->data)); break; case ITE: result = ast_create_node3 (ITE, c3_bitblast_form ((ASTNode *)children->head->data), c3_bitblast_form ((ASTNode *)children->head->n->data), c3_bitblast_form ((ASTNode *)children->head->n->n->data)); break; case AND: case OR: case NAND: case NOR: case IFF: case XOR: case IMPLIES: { printf ("TWOÂ¥n"); c3_list_foreach (children, iter, child) { c3_list_append (echildren, c3_bitblast_form (child)); } result = ast_create_node (k, echildren); break; } case EQ: { ASTVec left = c3_bitblast_term ((ASTNode *)children->head->data); ASTVec right = c3_bitblast_term ((ASTNode *)children->head->n->data); result = c3_bitblast_equal (left, right); break; } case BVLE: case BVGE: case BVGT: case BVLT: case BVSLE: case BVSGE: case BVSGT: case BVSLT: { printf ("BVSLTÂ¥n"); result = c3_bitblast_cmp (form); break; } default: break; } return result; } void c3_bitblast(C3 *c3, ASTNode *assertq) { bb = c3_bitblast_new (); assertq = c3_bitblast_form (assertq); c3_bitblast_free (bb); }
ã§ãå®ã¯ãã®BitBlastingã®å¦çãã¾ã å
¨ã¦ã®ASTé
ã«å¯¾å¿ãããã¦ããªãã®ã§ä¸é¨å¤æãã§ããªãã®ã§ããã
ä½ããã£ã¦ããã¨è¨ãã¨ä¾ãã°a == bã¨ããSMTã®å¼ãa[0] <-> b[0] && a[1] <-> b[1] && ... a[n] <-> b[n]ã¨ãã£ãå½é¡è«çå¼ã®ASTã«å¤æãã¦ãããã§ãã
ãããã¦å½é¡è«çå¼ã§è¡¨ãããASTãçæãããå¾ãæå¾ã«Tseitin Encodingã§CNFã«å¤æãã¾ãã
Tseitin Encodingã«ã¤ãã¦ã¯ä»¥ä¸åç
§ã
SATソルバを使うためにCNFを作る - soutaroブログ
6.å®è£ (SATã½ã«ã)
åç¯ã§SMTLIB2ãã©ã¼ãããã®è¨è¿°ãCNFã§è¡¨ãããå½é¡è«çå¼ã«å¤æããæã¾ã§ã§ããã®ã§ããã¨ã¯ããã¤ãSATã½ã«ãã«é£ãããã°å
足å¯è½æ§ãå¤å®ã§ãã¾ãã
ãã¦ãC3ã¯SATã½ã«ããèªåã§ç¨æãã¦ããã®ã§ããã®å®è£
ãå°ãè¦ã¦ã¿ã¾ãã
ã¢ã«ã´ãªãºã ã¯DPLLã使ã£ã¦ãã¾ãã
DPLLアルゴリズム - Wikipedia
å²ã¨ç´æçãªã¢ã«ã´ãªãºã ã§ã以ä¸ã®ã«ã¼ã«ã«å¾ãã¾ãã
- 1ãªãã©ã«è¦åï¼one literal rule, unit ruleï¼
ãªãã©ã« L 1ã¤ã ãã®ç¯ãããã°ãL ãå«ãç¯ãé¤å»ã,ä»ã®ç¯ã®å¦å®ãªãã©ã« ¬L ãæ¶å»ããã
- ç´ãªãã©ã«è¦åï¼pure literal rule, affirmative-nagative ruleï¼
ç¯éåã®ä¸ã«å¦å®ã¨è¯å®ã®ä¸¡æ¹ãç¾ããªããªãã©ã«ï¼ç´ãªãã©ã«ï¼ L ãããã°ãL ãå«ãç¯ãé¤å»ããã
- åå²è¦åï¼splitting rule, rule of case analysisï¼
ç¯éå F ã®ä¸ã«å¦å®ã¨è¯å®ã®ä¸¡æ¹ããããªãã©ã« L ãããã°ããã®ãªãã©ã«ãçå½ã«è§£éãã¦ãããã2ã¤ã®ç¯éåã«åå²ããã
ã¾ãè¦ããã«ãæããã«çå½å¤ãåãããããªãªãã©ã«ãåé¤ãã¦ãã£ã¦è«çå¼ã®ãµã¤ãºãæ¸ããã¦è¡ããããã§ãªãå ´åã¯åå²è¦åã§çå½å¤ã2ãã¿ã¼ã³ã¯ãã¦ã¿ã¦æ¢ç´¢ããã¨ããç©ã§ãã
core.c
c3/core.c at master · RKX1209/c3 · GitHub
/* C3 Theorem Prover - Apache v2.0 - Copyright 2017 - rkx1209 */ #include <unistd.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #include <c3_core.h> #include <c3_utils.h> #include <parser/parsecnf.h> #include <parser/parser.h> #include <tosat/bitblaster.h> .... (çç¥) ... /* one literal rule */ static C3_STATUS _c3_dpll_simplify1(C3 *c3, C3List *cnf, int32_t *res) { bool simplify; C3_STATUS status = C3_NONE; C3ListIter *iter, *next; C3List *disj; do { simplify = false; iter = cnf->head; while (iter && (disj = iter->data)) { next = iter->n; if (c3_list_length (disj) == 1) { /* Found alone literal */ int32_t* onep = c3_list_head_data (disj); int32_t one = *onep; int32_t oneab = abs(one); int32_t value = (one < 0) ? -1 : 1; debug_log (1, "found one literal %d(%p)\n", one, onep); if (res[oneab - 1] && res[oneab - 1] != value) { /* literal is already set. inconsistent */ return C3_UNSAT; } res[oneab - 1] = value; simplify = true; _c3_dpll_remove2 (c3, cnf, one); status = C3_SIMPLIFY; _c3_print_cnf (cnf); } iter = next; } } while (simplify); return status; } /* pure literal rule */ static bool _c3_dpll_simplify2(C3 *c3, C3List *cnf, int32_t *res) { C3ListIter *iter, *iter2, *next; C3List *disj; int32_t *num, i, absi; bool *flag; C3_STATUS status = C3_NONE; /* Memorize all symbols */ c3_list_foreach (cnf, iter, disj) { c3_list_foreach (disj, iter2, num) { flag = malloc (sizeof(bool)); if (!flag) { return false; } *flag = true; c3_hmap_add_int32 (c3->literals, *num, flag); //c3_bstree_add (c3->literals2, num, c3_compare_value); } } /* Delete if literal is pure */ for (i = -c3->valnum; i <= c3->valnum; i++) { if (!c3_hmap_get_int32 (c3->literals, i)) { continue; } if (c3_hmap_get_int32 (c3->literals, -i)) { /* not pure. */ continue; } absi = abs(i); int32_t value = (i < 0) ? -1 : 1; if (res[absi - 1] && res[absi - 1] != value) { /* literal is already set. inconsistent */ return C3_UNSAT; } res[absi - 1] = value; iter = cnf->head; debug_log (1, "pure literal %d\t%p\n", i, iter); while (iter) { disj = iter->data; next = iter->n; if (c3_list_find (disj, &i, c3_compare_value)) { c3_list_clear (disj); c3_listiter_delete (cnf, iter); } iter = next; } status = C3_SIMPLIFY; _c3_print_cnf (cnf); } c3_hmap_clear (c3->literals); return status; } /* Simplification rules */ static C3_STATUS _c3_dpll_simplify(C3 *c3, C3List *cnf, int32_t *res) { C3_STATUS status1 = C3_NONE, status2 = C3_NONE; do { status1 = _c3_dpll_simplify1(c3, cnf, res); if (status1 == C3_UNSAT) return C3_UNSAT; status2 = _c3_dpll_simplify2(c3, cnf, res); if (status2 == C3_UNSAT) return C3_UNSAT; } while (status1 == C3_SIMPLIFY || status2 == C3_SIMPLIFY); return C3_NONE; } static C3_STATUS _c3_derive_dpll(C3 *c3, C3List *cnf, int32_t *res); .... (çç¥) ... /* DPLL algorithm */ static C3_STATUS _c3_derive_dpll(C3 *c3, C3List *cnf, int32_t *res) { C3ListIter *iter; C3List *disj; /* Simplify */ if (_c3_dpll_simplify (c3, cnf, res) == C3_UNSAT) { return C3_UNSAT; } if (c3_list_empty (cnf)) { return C3_SAT; } c3_list_foreach (cnf, iter, disj) { if (c3_list_empty (disj)) { return C3_UNSAT; } } return _c3_dpll_split (c3, cnf, res); } C3_STATUS c3_derive_sat(C3 *c3, int32_t *res) { if (c3 && res) { C3List *cnf2 = c3_dup_cnf (c3->cnf); C3_STATUS status = _c3_derive_dpll (c3, cnf2, res); c3_del_cnf (cnf2); return status; } return C3_INVALID; } .... (çç¥) ... int main(int argc, char **argv, char **envp) { .... (çç¥) ... /* Init */ c3_init (&c3); .... (çç¥) ... } else { /* SMT mode */ c3_smt2_parse (cnfp); c3_list_foreach (c3.asserts, iter, assertq) { c3_solve_by_sat (&c3, assertq); } } /* Finish */ fclose (cnfp); c3_fini (&c3); }
ã¯ãã _c3_dpll_simplify1/2ã¨ãããªãã©ã«è¦åã«ãªãã¾ãã
èå³ãã人ã¯githubã®ã³ã¼ãèªãã§ããã ããã°ã¨æãã¾ãã
7.ãããã«
æ¯æãã®ã¤ããã§è¨äºæ¸ãã¦ãã1æ¥æ½°ãããï¼ï¼
SAT/SMTã½ã«ãä½ããã人éãªãã¦æ¬å½ã«ããã®ãï¼ã¨ããæççãªæ°æã¡ãæ±ãã¤ã¤ãã¾ãèªä½ã¾ã§ã¯ãããªãã¦ãã©ãããä»çµã¿ã§åãã¦ããã®ã¶ãã¯ãªããç解ã¯å½¹ç«ã¤ãããããªãã§ããã
ç¹ã«BitVectorã«é¢ãã¦ã¯ã½ããã¦ã§ã¢/ãã¼ãã¦ã§ã¢æ¤è¨¼å±ããã¨ããèå¼±æ§æ¤åºã¨ããã£ã¦ãã»ãã¥ãªãã£ç 究å±ããã¨ãã