1

生成された真理値表の条件をキャッチするループに小さな問題があります..論理式を入力すると、それが真理値表に変換され、有効か無効か矛盾しているかが解釈されます。これまでのところ、これはそれを解釈するプログラムの一部ですが、無効または有効のみをキャッチしています...これについて教えていただけますか? ありがとう

*edit// これがプログラムの実行方法です:

*******いらっしゃいませ!********

(LogicStart) を入力して開始するか、(終了) を入力していつでも終了します。

;; 読み込まれたファイル MyLogic.lisp

T [2]> (LogicStart) 論理式または式を入力してください: "(p^(~p))"

p (~p) (p^(~p))
T NIL NIL

NIL T NIL

数式が無効です

したがって、入力は論理式のみであり、出力はその式の真理値表です....そしてそれを解釈することもできますが、上記の例は一貫性がない/満足できない (式/式のすべての解釈が偽であるため)

編集を終了

(defun interpret() ; interpret if valid or not or inconsistent
(setq lastcolumn (- (column) 1))
(setq lastcolumnROW 1)
(loop   
    (unless (aref (aref tbl lastcolumn) lastcolumnROW) (progn (princ "The formula is Invalid")(return)))

    (setq lastcolumnROW (+ lastcolumnROW 1))
    (when (= lastcolumnROW (+ 1 (row))) (progn (princ "The formula is a Tautology ") (return)))
)
)

編集 2:///

これは LogicStart 関数です:

(defun LogicStart()  
;Function to run program

(princ "Enter Logical Expression or Formula: " )
(setq input (read))
;Get input

(format t "-----------------------------------------------~C" #\linefeed)

;Create two dimension array(table)
(setq tbl (make-array (column)))
(setq index 0)
(loop 
    (setf (aref tbl index) (make-array  (+ (row) 1)))   
    (setq index (+ 1 index))
    (when (= index (column))(return))
)

(setAtoms)
(setFirstValue)
(tblReplaceValue)
(watchTable)
(format t "-----------------------------------------------~C" #\linefeed)
(interpret)
)

setAtoms 関数:

(defun setAtoms()
;Get ALL possible formula

(setq indexOFTBL (make-array (column)))

(setq openP (make-array (- (column) (length Latoms))))
; Get index of open Parenthesis

(setq cOpenP 0) 
(setq closeP (make-array (- (column) (length Latoms))))
;Get index of close Parenthesis

(setq cCloseP 0) 
(setq index 0)
(loop
    (when (char-equal (char input index) #\() 
        (progn
            (setf (aref openP cOpenP) index)
            (setq cOpenP (+ 1 cOpenP))
        )
    )
    (when (char-equal (char input index) #\)) 
        (progn
            (setf (aref closeP cCloseP) index)
            (setq cCloseP (+ 1 cCloseP))
        )
    )
    (setq index (+ 1 index))
    (when (= index (length input)) (return))
)
;(print openP)

;(print closeP)
(setq index 0)
(loop
    (if (< index (length Latoms))
        (progn
            (setf (aref (aref tbl index) 0) (char Latoms index))
            (setf (aref indexOFTBL index) index)
        )
        (progn
            (setq OpIndex cOpenP)
            (loop
                (setq OpIndex (- OpIndex 1))
                (setq CpIndex 0)
                (loop
                    (if (or (> (aref openP OpIndex) (aref closeP CpIndex)) (= -1 (aref closeP CpIndex)))
                        (progn 
                            (setq CpIndex (+ CpIndex 1))
                        )
                        (progn
                            (setf (aref (aref tbl index) 0) (subseq input (aref openP OpIndex) (+ 1 (aref closeP CpIndex))))
                            (setf (aref closeP CpIndex) -1)
                            (return)
                        )
                    )
                    (when (= CpIndex (length closeP))(return))
                )
                (setq index (+ index 1))
                (when (= OpIndex 0) (return))
            )
            (return)
        )
    )
    (setq index (+ index 1))
    (when (= index (column)) (return))
)
)

watchTable と列関数

(defun watchTable()
; View table

(setq ro 0)
(loop
    (setq co 0)
    (loop
        (princ(aref (aref tbl co) ro))(format t "~C" #\tab)
        (setq co (+ 1 co))
        (when (= co (column))(return))
    )
    (format t "~C" #\linefeed)
    (setq ro (+ 1 ro))
    (when (= ro (+ (row) 1))(return))
)
)


(defun column()
; Get the number of columns
(+ (atoms) (symbols))
)

//編集 3 したがって、(OR A (NOT A)) の場合、テーブルには @jkiiski のコードで「not A」がありません

A   |   NOT A  |  (OR A (NOT A))
----+----------+--------
NIL |    T     |   T  
T   |   NIL    |   T  
This expression is a Tautology.

参照用の別の例: P は Q を暗示していますが、このコードは次のように暗黙を受け入れます: >

 ; Logical Connectives:
 ; ~ negation
 ; - biconditional
 ; > conditional
 ; ^ and
 ; v or

; Example Input:
;   "(~((a^b)>c))"
;   "(p>q)"

p   q      p>q
T   T       T 
T   NIL    NIL 
NIL T       T
NIL NIL     T

Another example:
Enter an expression: "((p>q)^r)"
T <- True 
NIL <- False
--------------------------------------------
p   q   r   (p>q)   ((p>q)^r)   
T   T   T    T         T    
T   T   NIL  T        NIL   
T   NIL T    NIL      NIL   
T   NIL NIL  NIL      NIL   
NIL T   T    T         T    
NIL T   NIL  T        NIL   
NIL NIL T    T         T    
NIL NIL NIL  T        NIL   
--------------------------------------------

したがって、(p>q)^r では、真理値表に p、q、r、(p>q)、および最後に (p>q)^r が表示されます。

4つ編集//

(defun generate-value-combinations (variables)
(let ((combinations (list)))
(labels ((generate (variables &optional (acc (list)))
           (if (endp variables)
               (push (reverse acc) combinations)
               (loop for value in '(t nil)
                     for var-cell = (cons (car variables) value)
                     do (generate (cdr variables) (cons var-cell acc))))))
  (generate variables)
  combinations)))

to this one?
(defun generate-value-combinations (variables)
(let ((combinations (list)))
(labels ((generate (variables &optional (acc (list)))
           (if (endp variables)
               (push (reverse acc) combinations)
               (loop for value in '(t nil)
                     for var-cell = (cons (car variables) value)
                     do (generate (cdr variables) (cons var-cell acc))))))
  (generate variables) nreverse combinations)))
4

2 に答える 2

1

Coredump はすでに答えを出しており、私は彼/彼女のソリューションをこの一部として使用しました (わずかな変更を加えて) が、コードはあまりリピーではないため、学習目的で別のソリューションを示すことにしました。これはかなり簡単に書かれているので、ばかげた間違いをすべて指摘してください...

このコードでは、通常の Lisp 構文 ( など(and a (or b c))) を使用して論理式を指定することを想定しています。

式で使用されるすべての変数を抽出する関数から始めましょう。AND論理演算子 ( 、OR>またはNOT) 以外のものはすべて変数であると仮定します。これはリストを引数として取り、再帰関数 ( EXTRACT) を使用してそれを走査し、演算子ではないすべてのアトムをリスト ( VARIABLES) に収集します。最後にリストを逆にして返します。

(defun extract-variables (input)
  (let ((variables (list)))
    (labels ((extract (input)
               (if (atom input)
                   (unless (member input '(and or not > -))
                     ;; PUSHNEW only pushes variables that haven't
                     ;; already been added to the list.
                     (pushnew input variables))
                   ;; If INPUT is a list, use MAPC to apply EXTRACT
                   ;; to all its elements.
                   (mapc #'extract input))))
      (extract input)
      (nreverse variables))))

これで注意すべき点は次のとおりです。

  1. ローカル変数は、LETではなくを使用して定義する必要がありますSETQ
  2. ローカル関数は を使用して定義されLABELSます。

関数をテストできます:

CL-USER> (extract-variables '(and a (or b c (not a))))
(A B C)

次に、これらの変数のすべての可能な値の組み合わせを生成する関数を書きましょう。簡単にするために、連想リストのリストを使用して変数を保持します。関連リストは、キーと値のペアで構成されるリストです。例えば:

((A . T) (B . T))

ASSOC連想リスト内の要素を検索するために使用できます。ペア全体を返すため、通常CDRは値だけを取得するために使用する必要があります。

CL-USER> (cdr (assoc 'b '((a . nil) (b . t))))
T

したがって、式の値の組み合わせのリストは次の(AND A B)ようになります。

(((A . T) (B . T))
 ((A . T) (B . NIL) ; (B . NIL) would usually be printed (B)
 ((A . NIL) (B . T))
 ((A . NIL) (B . NIL)))

したがって、これを実現する関数は次のとおりです。

(defun generate-value-combinations (variables)
  (let ((combinations (list)))
    (labels ((generate (variables &optional (acc (list)))
               (if (endp variables)
                   (push (reverse acc) combinations)
                   (loop for value in '(nil t)
                         for var-cell = (cons (car variables) value)
                         do (generate (cdr variables) (cons var-cell acc))))))
      (generate variables)
      combinations)))

前の関数と同じ再帰パターンを使用しました。内部関数は、変数値をオプションの引数に累積し、変数ACCリストの最後に到達すると、累積された連想リストが にプッシュされCOMBINATIONSます。連想リストは、変数が指定された順序と同じ順序を維持するために逆になっています。これでテストできます。

CL-USER> (generate-value-combinations '(a b))
(((A) (B)) ((A) (B . T)) ((A . T) (B)) ((A . T) (B . T)))

次に、これらの連想リストの 1 つの変数値を使用して式を評価する関数が必要です。これは、再帰的評価器を使用して簡単に行うことができます。

(defun evaluate (input variables)
  (labels (;; GET-VALUE is just a simple helper to get the value of 
           ;; a variable from the association list.
           (get-value (variable)
             (cdr (assoc variable variables)))
           (evaluator (input)
             (typecase input
               ;; For atoms we just return its value from the alist.
               (atom (get-value input))
               ;; Lists consist of an operator and arguments for it.
               ;; We only recognize three operators: AND, OR and NOT.
               (list (destructuring-bind (operator &rest args) input
                       (ecase operator
                         (and (loop for arg in args always (evaluator arg)))
                         (or (loop for arg in args thereis (evaluator arg)))
                         (> (not (and (evaluator (first args))
                                      (not (evaluator (second args))))))
                         (- (equal (evaluator (first args))
                                   (evaluator (second args))))
                         (not (not (evaluator (first args))))))))))
    (evaluator input)))

もう一度、テストしてみましょう。

CL-USER> (evaluate '(and a (or b c)) '((a . t) (b . nil) (c . t)))
T
CL-USER> (evaluate '(and a (or b c)) '((a . t) (b . nil) (c . nil)))
NIL

これらの関数を使用して、次のような真理値表を作成できます。

CL-USER> (let ((input '(and a (or b c))))
           (mapcar (lambda (row)
                     (append (mapcar #'cdr row)
                             (list (evaluate input row))))
                   (generate-value-combinations (extract-variables input))))
((NIL NIL NIL NIL) (NIL NIL T NIL) (NIL T NIL NIL) (NIL T T NIL)
 (T NIL NIL NIL) (T NIL T T) (T T NIL T) (T T T T))

各サブリストで、最初の 3 つの値は変数の値です (テスト入力に 3 つの値があるため)。最後の値は、それらの変数値で評価された式の値です。

それでは、式が充足可能かどうかをチェックする関数を書きましょう。これは、コアダンプの回答とほぼ同じです。主な違いは、このバージョンでは真理値表が配列ではなくリストとして保存されることです。

(defun interpret (truth-table)
  (loop for (value) in (mapcar #'last truth-table)
        for valid = value then (and valid value)
        for satisfiable = value then (or satisfiable value)
        finally (return (cond (valid :valid)
                              (satisfiable :satisfiable)
                              (t :unsatisfiable)))))

最後に、すべてを接続しましょう。

(defun logic-start ()
  (format *query-io* "~&Enter A Logical Expression: ")
  (finish-output *query-io*)
  (let* ((input (read *query-io*))
         (variables (extract-variables input))
         (value-combinations (generate-value-combinations variables))
         ;; Gather all sub-expressions.
         (columns (labels ((collect-sub-expressions (expression)
                             (append (when (and (listp expression)
                                                (not (and (eql (first expression)
                                                               'not)
                                                          (atom (second expression)))))
                                       (loop for arg in (rest expression)
                                             append (collect-sub-expressions arg)))
                                     (list expression))))
                    (remove-duplicates (collect-sub-expressions input)
                                       :from-end t)))
         ;; Widths of the columns in the table.
         (column-widths (loop for column in columns
                              collect (max 3 (length (princ-to-string column)))))
         (truth-table (mapcar (lambda (variables)
                                (loop for col in columns
                                      for width in column-widths
                                      collect width
                                      ;; This is a bit wasteful, since
                                      ;; it evaluates every sub-expression
                                      ;; separately, as well as evaluating
                                      ;; the full expression.
                                      collect (evaluate col variables)))
                              value-combinations)))
    (format t "~&~{ ~{~v<~a~;~>~}~^ |~}~%~{-~v,,,'-<-~>-~^+~}~%"
            (mapcar #'list column-widths columns) column-widths)
    (format t "~&~{~{ ~v<~a~;~> ~^|~}~%~}" truth-table)
    (format t "~&This expression is ~a.~%"
            (case (interpret truth-table)
              (:valid "a Tautology")
              (:satisfiable "Satisfiable")
              (:unsatisfiable "Unsatisfiable")))))

そしてそれをテストしてください:

CL-USER> (logic-start)
Enter A Logical Expression: (and a (not a))

 A   | (NOT A) | (AND A (NOT A))
-----+---------+-----------------
 NIL | T       | NIL             
 T   | NIL     | NIL             
This expression is Unsatisfiable.

NIL
CL-USER> (logic-start)
Enter A Logical Expression: (or a (not a))

 A   | (NOT A) | (OR A (NOT A))
-----+---------+----------------
 NIL | T       | T              
 T   | NIL     | T              
This expression is a Tautology.

NIL
CL-USER> (logic-start)
Enter A Logical Expression: (and a (or b c) (not d))

 A   | B   | C   | (OR B C) | (NOT D) | (AND A (OR B C) (NOT D))
-----+-----+-----+----------+---------+--------------------------
 NIL | NIL | NIL | NIL      | T       | NIL                      
 NIL | NIL | NIL | NIL      | NIL     | NIL                      
 NIL | NIL | T   | T        | T       | NIL                      
 NIL | NIL | T   | T        | NIL     | NIL                      
 NIL | T   | NIL | T        | T       | NIL                      
 NIL | T   | NIL | T        | NIL     | NIL                      
 NIL | T   | T   | T        | T       | NIL                      
 NIL | T   | T   | T        | NIL     | NIL                      
 T   | NIL | NIL | NIL      | T       | NIL                      
 T   | NIL | NIL | NIL      | NIL     | NIL                      
 T   | NIL | T   | T        | T       | T                        
 T   | NIL | T   | T        | NIL     | NIL                      
 T   | T   | NIL | T        | T       | T                        
 T   | T   | NIL | T        | NIL     | NIL                      
 T   | T   | T   | T        | T       | T                        
 T   | T   | T   | T        | NIL     | NIL                      
This expression is Satisfiable.

入力の解析

入力を処理する最も簡単な方法(a and b > q)は、通常の Lisp 構文に解析することです。これを行うための簡単に書かれたパーサーを次に示します。

(defun find-and-split (item list)
  (let ((position (position item list :from-end t)))
    (when position
      (list (subseq list 0 position)
            item
            (subseq list (1+ position))))))

(defparameter *operator-precedence* '(- > or and))

(defun parse-input (input)
  (typecase input
    (atom input)
    (list (cond
            ((> (length input) 2)
             (dolist (op *operator-precedence* input)
               (let ((split (find-and-split op input)))
                 (when split
                   (destructuring-bind (left operator right) split
                     (return-from parse-input
                       (list operator
                             (parse-input left)
                             (parse-input right))))))))
            ((= (length input) 2) (mapcar #'parse-input input))
            (t (parse-input (first input)))))))

テスト:

CL-USER> (parse-input '(a and b > q))
(> (AND A B) Q)
CL-USER> (parse-input '((not q) or p and x))
(OR (NOT Q) (AND P X))
CL-USER> (parse-input '(q > p or y))
(> Q (OR P Y))

これをプログラムに追加するには、(READ *QUERY-IO*)inLOGIC-STARTを に変更するだけ(PARSE-INPUT (READ *QUERY-IO*))です。

変数名の一部として読み取られる問題-の回避>

で入力を直接読み取る代わりにREAD、 を使用READ-LINEして文字列として読み取り、 と の前後にスペースを挿入して-から>、 を使用READ-FROM-STRINGしてそれをリストに変換することができます。

(defun insert-spaces (input-str)
  (with-output-to-string (str)
    (loop for char across input-str
          ;; Add a space before - or >
          when (or (char= char #\-)
                   (char= char #\>)) do (write-char #\space str)
          ;; Write the character itself.
          do (write-char char str)
             ;; Add a space after - or >
          when (or (char= char #\-)
                   (char= char #\>)) do (write-char #\space str))))

テスト:

CL-USER> (insert-spaces "((p and q)-r)")
"((p and q) - r)"

次に、をに変更(PARSE-INPUT (READ *QUERY-IO*))します(parse-input (read-from-string (insert-spaces (read-line *query-io*))))

于 2016-05-24T18:13:28.427 に答える