Skip to content
Snippets Groups Projects
Commit b496aad0 authored by Michael Leuschel's avatar Michael Leuschel
Browse files

add more material about propositional logic

parent de95161a
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id:9eb5530a tags: %% Cell type:markdown id:9eb5530a tags:
# Propositional Logic # Propositional Logic
Syntax and Semantics Explained using a Prolog Implementation Syntax and Semantics Explained using a Prolog Implementation
%% Cell type:markdown id:dba70591 tags: %% Cell type:markdown id:dba70591 tags:
## Well-Formed Formulas (WFF) ## Well-Formed Formulas (WFF)
All atomic propositions are WFF) All atomic propositions are WFF)
If a und b are WFF then so are: If a und b are WFF then so are:
- (¬ a) - (¬ a)
- (a ∧ b) - (a ∧ b)
- (a ∨ b) - (a ∨ b)
- (a ⇒ b) - (a ⇒ b)
- (a ⟺ b) - (a ⟺ b)
No other formulas are WFF. No other formulas are WFF.
Comment: a, b are metavariablens outside the syntax of propositional logic. Comment: a, b are metavariablens outside the syntax of propositional logic.
%% Cell type:markdown id:dd01f86a tags: %% Cell type:markdown id:dd01f86a tags:
Maybe this reminds you of formal grammars from a theoretical computer science lecture. Maybe this reminds you of formal grammars from a theoretical computer science lecture.
And indeed, the above can be written as a grammar using a non-terminal symbol wff. And indeed, the above can be written as a grammar using a non-terminal symbol wff.
In Prolog, grammars can actually be written using DCG notation, which we will see and understand much later in the course. In Prolog, grammars can actually be written using DCG notation, which we will see and understand much later in the course.
Here we simply write the grammar in Prolog style and can then use it to check if a formula is a WFF: Here we simply write the grammar in Prolog style and can then use it to check if a formula is a WFF:
%% Cell type:code id:964ebd52 tags: %% Cell type:code id:964ebd52 tags:
``` prolog ``` prolog
:- set_prolog_flag(double_quotes, codes). :- set_prolog_flag(double_quotes, codes).
wff --> "p". % atomic proposition wff --> "p". % atomic proposition
wff --> "q". % atomic proposition wff --> "q". % atomic proposition
wff --> "(¬",wff,")". wff --> "(¬",wff,")".
wff --> "(", wff, "∧", wff, ")". wff --> "(", wff, "∧", wff, ")".
wff --> "(", wff, "∨", wff, ")". wff --> "(", wff, "∨", wff, ")".
wff --> "(", wff, "⇒", wff, ")". wff --> "(", wff, "⇒", wff, ")".
wff --> "(", wff, "⟺", wff, ")". wff --> "(", wff, "⟺", wff, ")".
``` ```
%% Output
%% Cell type:code id:fc6823ad tags: %% Cell type:code id:fc6823ad tags:
``` prolog ``` prolog
?- wff("p",""). ?- wff("p","").
``` ```
%% Output %% Output
%% Cell type:code id:152289b6 tags: %% Cell type:code id:152289b6 tags:
``` prolog ``` prolog
?- wff("(¬p)",""). ?- wff("(¬p)","").
``` ```
%% Output %% Output
%% Cell type:code id:2c3dd1bf tags: %% Cell type:code id:2c3dd1bf tags:
``` prolog ``` prolog
?- wff("(p∧(q∨(¬p)))",""). ?- wff("(p∧(q∨(¬p)))","").
%comment. %comment.
``` ```
%% Output %% Output
%% Cell type:markdown id:38b0a282 tags: %% Cell type:markdown id:38b0a282 tags:
This grammar does not talk about whitespace and requires parentheses for every connective used. This grammar does not talk about whitespace and requires parentheses for every connective used.
In practice, one typically uses operator precedences to avoid having to write too many parentheses: In practice, one typically uses operator precedences to avoid having to write too many parentheses:
- negation binds strongest - negation binds strongest
- then come conjunction and disjunction - then come conjunction and disjunction
- then come implication and equivalence. - then come implication and equivalence.
So instead of So instead of
- (((¬ p) ∧ (¬ q)) ⇒ ((¬ p) ∨ (¬ q))) - (((¬ p) ∧ (¬ q)) ⇒ ((¬ p) ∨ (¬ q)))
we can write we can write
- ¬ p ∧ ¬ q ⇒ ¬ p ∨ ¬ q - ¬ p ∧ ¬ q ⇒ ¬ p ∨ ¬ q
We will try not not mix conjunction/disjunction and implication/equivalence without parentheses. We will try not not mix conjunction/disjunction and implication/equivalence without parentheses.
We will also not try to improve our Prolog parser here to accomodate these precedences. We will also not try to improve our Prolog parser here to accomodate these precedences.
This is the subject of another course (on compiler construction). This is the subject of another course (on compiler construction).
%% Cell type:markdown id:92b6dc2d tags: %% Cell type:markdown id:92b6dc2d tags:
We will also see much later that Prolog allows one to annotate grammars with semantic values, here to generate We will also see much later that Prolog allows one to annotate grammars with semantic values, here to generate
a Prolog term representing the logical formal in the form of a syntax tree: a Prolog term representing the logical formal in the form of a syntax tree:
%% Cell type:code id:78163b60 tags: %% Cell type:code id:78163b60 tags:
``` prolog ``` prolog
:- set_prolog_flag(double_quotes, codes). :- set_prolog_flag(double_quotes, codes).
wff(p) --> "p". % atomic proposition wff(p) --> "p". % atomic proposition
wff(q) --> "q". % atomic proposition wff(q) --> "q". % atomic proposition
wff(not(A)) --> "(¬",wff(A),")". wff(not(A)) --> "(¬",wff(A),")".
wff(and(A,B)) --> "(", wff(A), "∧", wff(B), ")". wff(and(A,B)) --> "(", wff(A), "∧", wff(B), ")".
wff(or(A,B)) --> "(", wff(A), "∨", wff(B), ")". wff(or(A,B)) --> "(", wff(A), "∨", wff(B), ")".
wff(impl(A,B)) --> "(", wff(A), "⇒", wff(B), ")". wff(impl(A,B)) --> "(", wff(A), "⇒", wff(B), ")".
wff(equiv(A,B)) --> "(", wff(A), "⟺", wff(B), ")". wff(equiv(A,B)) --> "(", wff(A), "⟺", wff(B), ")".
``` ```
%% Cell type:code id:8ddb568d tags: %% Cell type:code id:8ddb568d tags:
``` prolog ``` prolog
?- wff(Formula,"(¬p)",""). ?- wff(Formula,"(¬p)","").
``` ```
%% Output %% Output
%% Cell type:code id:075dc3b2 tags: %% Cell type:code id:075dc3b2 tags:
``` prolog ``` prolog
?- wff(Formula,"(¬(p∧q))",""). ?- wff(Formula,"(¬(p∧q))","").
``` ```
%% Output %% Output
%% Cell type:code id:338cb7dd tags: %% Cell type:code id:338cb7dd tags:
``` prolog ``` prolog
?- wff(Formula,"(p∧(q∨(¬p)))",""). ?- wff(Formula,"(p∧(q∨(¬p)))","").
``` ```
%% Output %% Output
%% Cell type:markdown id:f9005519 tags: %% Cell type:markdown id:f9005519 tags:
The above Prolog term `and(p,or(q,not(p)))` represents the logical formula in tree form. The above Prolog term `and(p,or(q,not(p)))` represents the logical formula in tree form.
We can display the tree as a dag (directed acyclic graph) using the following subsidiary code We can display the tree as a dag (directed acyclic graph) using the following subsidiary code
(in future the Jupyter kernel will probably have a dedicated command to show a term graphically): (in future the Jupyter kernel will probably have a dedicated command to show a term graphically):
%% Cell type:code id:f6116612 tags: %% Cell type:code id:f6116612 tags:
``` prolog ``` prolog
subtree(Term,Nr,SubTerm) :- subtree(Term,Nr,SubTerm) :-
Term =.. [_|ArgList], %obtain arguments of the term Term =.. [_|ArgList], %obtain arguments of the term
nth1(Nr,ArgList,SubTerm). % get sub-argument and its position number nth1(Nr,ArgList,SubTerm). % get sub-argument and its position number
% recursive and transitive closure of subtree % recursive and transitive closure of subtree
rec_subtree(Term,Sub) :- Term = Sub. rec_subtree(Term,Sub) :- Term = Sub.
rec_subtree(Term,Sub) :- subtree(Term,_,X), rec_subtree(X,Sub). rec_subtree(Term,Sub) :- subtree(Term,_,X), rec_subtree(X,Sub).
subnode(Sub,[shape/S, label/F],Formula) :- subnode(Sub,[shape/S, label/F],Formula) :-
rec_subtree(Formula,Sub), % any sub-formula Sub of Formula is a node in the graphical rendering rec_subtree(Formula,Sub), % any sub-formula Sub of Formula is a node in the graphical rendering
functor(Sub,F,_), (atom(Sub) -> S=egg ; number(Sub) -> S=oval ; S=rect). functor(Sub,F,_), (atom(Sub) -> S=egg ; number(Sub) -> S=oval ; S=rect).
``` ```
%% Cell type:code id:d7e68593 tags: %% Cell type:code id:d7e68593 tags:
``` prolog ``` prolog
jupyter:print_table(subnode(Node,Dot,and(p,or(q,not(p))))) jupyter:print_table(subnode(Node,Dot,and(p,or(q,not(p)))))
``` ```
%% Output %% Output
Node | Dot | Node | Dot |
:- | :- | :- | :- |
and(p,or(q,not(p))) | [shape/rect,label/and] | and(p,or(q,not(p))) | [shape/rect,label/and] |
p | [shape/egg,label/p] | p | [shape/egg,label/p] |
or(q,not(p)) | [shape/rect,label/or] | or(q,not(p)) | [shape/rect,label/or] |
q | [shape/egg,label/q] | q | [shape/egg,label/q] |
not(p) | [shape/rect,label/not] | not(p) | [shape/rect,label/not] |
p | [shape/egg,label/p] | p | [shape/egg,label/p] |
%% Cell type:code id:3646e3ee tags: %% Cell type:code id:3646e3ee tags:
``` prolog ``` prolog
jupyter:show_graph(subnode(_,_,and(p,or(q,not(p)))),subtree/3) jupyter:show_graph(subnode(_,_,and(p,or(q,not(p)))),subtree/3)
``` ```
%% Output %% Output
%% Cell type:markdown id:11b3a8ad tags: %% Cell type:markdown id:11b3a8ad tags:
Below we will study how one can assign a truth-value to logical formulas like the one above. Below we will study how one can assign a truth-value to logical formulas like the one above.
## Truth tables ## Truth tables
Every logical connective has a truth-table, indicating how it maps the truth of its arguments to its own truth value. Every logical connective has a truth table, indicating how it maps the truth of its arguments to its own truth value.
For example, `and` maps inputs `true` and `false` to `false`. For example, `and` maps inputs `true` and `false` to `false`.
Below we encode the truth table for five connectives as Prolog facts and rules.
%% Cell type:code id:350b9756 tags: %% Cell type:code id:350b9756 tags:
``` prolog ``` prolog
not(true,false). not(true,false).
not(false,true). not(false,true).
and(true,V,V) :- truth_value(V). and(true,V,V) :- truth_value(V).
and(false,_,false). and(false,V,false) :- truth_value(V).
or(true,_,true). or(true,V,true) :- truth_value(V).
or(false,V,V) :- truth_value(V). or(false,V,V) :- truth_value(V).
implies(A,B,Res) :- not(A,NotA), or(NotA,B,Res). implies(A,B,Res) :- not(A,NotA), or(NotA,B,Res).
equiv(A,B,Res) :- implies(A,B,AiB), implies(B,A,BiA), and(AiB,BiA,Res). equiv(A,B,Res) :- implies(A,B,AiB), implies(B,A,BiA), and(AiB,BiA,Res).
truth_value(true). truth_value(true).
truth_value(false). truth_value(false).
truth_table(A,B,NotA,AandB,AorB,AiB,AeB) :- truth_table(A,B,NotA,AandB,AorB,AiB,AeB) :-
truth_value(A), truth_value(B), truth_value(A), truth_value(B),
not(A,NotA), and(A,B,AandB), or(A,B,AorB), not(A,NotA), and(A,B,AandB), or(A,B,AorB),
implies(A,B,AiB), equiv(A,B,AeB). implies(A,B,AiB), equiv(A,B,AeB).
``` ```
%% Cell type:markdown id:41cad0bc tags:
We can now use the predicates `and/3`, ... to compute the truth value of the connectives for a particular input:
%% Cell type:code id:3101448b tags:
``` prolog
?- and(true,false,X).
```
%% Output
%% Cell type:code id:922004e9 tags:
``` prolog
?- or(true,false,X).
```
%% Output
%% Cell type:markdown id:78c0eda3 tags:
We can also display the whole truth table using a Jupyter command:
%% Cell type:code id:54b57ff8 tags: %% Cell type:code id:54b57ff8 tags:
``` prolog ``` prolog
jupyter:print_table(truth_table(A,B,NotA,AandB,AorB,AimpliesB,AequivB)) jupyter:print_table(truth_table(A,B,NotA,AandB,AorB,AimpliesB,AequivB))
``` ```
%% Output %% Output
A | B | NotA | AandB | AorB | AimpliesB | AequivB | A | B | NotA | AandB | AorB | AimpliesB | AequivB |
:- | :- | :- | :- | :- | :- | :- | :- | :- | :- | :- | :- | :- | :- |
true | true | false | true | true | true | true | true | true | false | true | true | true | true |
true | false | false | false | true | false | false | true | false | false | false | true | false | false |
false | true | true | false | true | true | false | false | true | true | false | true | true | false |
false | false | true | false | false | true | true | false | false | true | false | false | true | true |
%% Cell type:markdown id:ce32b1d0 tags:
An <b>interpretation</b> is an assignment of all relevant proposition to truth values (true or false).
For example, given the formula `(p∧(q∨(¬p)))` an interpretation needs to assign a truth value to `p` and `q`.
In the Prolog code below we will represent an interpretation as a list of bindings, each binding is a term of the form `Proposition/TruthValue`.
For example, one of the four possible interpretations for the formula above is `[p/true, q/false]`.
Using the built-in `member/2` predicate we can inspect an interpretation in Prolog. For example, here we retrieve the truth value of `q`:
%% Cell type:code id:8f6d804b tags:
``` prolog
?- Interpetation=[p/true, q/false], member(q/Q,Interpetation).
```
%% Output
%% Cell type:markdown id:0d236e48 tags:
Given an interpretation we can now compute the truth value for an entire formula in a recursive fashion.
For propositions we look up the truth value in the interpretation (done using `member` below).
For logical connectives we recursively compute the truth value of its arguments and then apply the truth tables we defined above.
%% Cell type:code id:175c00d0 tags: %% Cell type:code id:175c00d0 tags:
``` prolog ``` prolog
value(X,Interpretation,Value) :- value(X,Interpretation,Value) :-
atomic(X), % we could also use: proposition(X), atomic(X), % we have a proposition
member(X/Value,Interpretation). member(X/Value,Interpretation).
value(and(A,B),I,Val) :- value(A,I,VA), value(B,I,VB), value(and(A,B),I,Val) :- value(A,I,VA), value(B,I,VB),
and(VA,VB,Val). and(VA,VB,Val).
value(or(A,B),I,Val) :- value(A,I,VA), value(B,I,VB), value(or(A,B),I,Val) :- value(A,I,VA), value(B,I,VB),
or(VA,VB,Val). or(VA,VB,Val).
value(not(A),I,Val) :- value(A,I,VA), value(not(A),I,Val) :- value(A,I,VA),
not(VA,Val). not(VA,Val).
value(implies(A,B),I,Val) :- value(or(not(A),B),I,Val). value(implies(A,B),I,Val) :- value(or(not(A),B),I,Val).
value(equiv(A,B),I,Val) :- value(equiv(A,B),I,Val) :-
value(and(implies(A,B),implies(B,A)),I,Val). value(and(implies(A,B),implies(B,A)),I,Val).
``` ```
%% Cell type:markdown id:aa50ec0e tags:
Using the above we can compute the truth value of `(p∧(q∨(¬p)))` for the interpretation `[p/true, q/false]`:
%% Cell type:code id:eee17774 tags: %% Cell type:code id:eee17774 tags:
``` prolog ``` prolog
?- value(and(p,or(q,not(p))), [p/true, q/false],Res). ?- value(and(p,or(q,not(p))), [p/true, q/false],Res).
``` ```
%% Output %% Output
%% Cell type:markdown id:4387b4a2 tags:
The truth value of `(p∧(q∨(¬p)))` for the interpretation `[p/true, q/true]` is true.
In this case the interpretation is called a <b>model</b> of the formula.
%% Cell type:code id:fec75f65 tags:
``` prolog
?- value(and(p,or(q,not(p))), [p/true, q/true],Res).
```
%% Output
%% Cell type:markdown id:3aa46665 tags:
We can also compute the truth table of the entire formula, by trying out all possible interpretations.
Below we leave P and Q as Prolog variable which is instantiated by the code above:
%% Cell type:code id:78473da0 tags: %% Cell type:code id:78473da0 tags:
``` prolog ``` prolog
jupyter:print_table(value(and(p,or(q,not(p))), [p/P, q/Q],Res)) jupyter:print_table(value(and(p,or(q,not(p))), [p/P, q/Q],Res))
``` ```
%% Output %% Output
P | Q | Res | P | Q | Res |
:- | :- | :- | :- | :- | :- |
true | true | true | true | true | true |
true | false | false | true | false | false |
false | true | false | false | true | false |
false | false | false | false | false | false |
%% Cell type:markdown id:5b4ee42b tags:
Below we visualise graphically this computation, by displaying the syntax tree of a logical formula
as a dag and by colouring the nodes using the `value` predicate:
%% Cell type:code id:2ee60c15 tags: %% Cell type:code id:2ee60c15 tags:
``` prolog ``` prolog
subnode_val(Sub,[shape/S, label/F, style/filled, fillcolor/C],Formula,Interpretation) :- subnode_val(Sub,[shape/S, label/F, style/filled, fillcolor/C],Formula,Interpretation) :-
rec_subtree(Formula,Sub), % any sub-formula Sub of Formula is a node in the graphical rendering rec_subtree(Formula,Sub), % any sub-formula Sub of Formula is a node in the graphical rendering
functor(Sub,F,_), (atom(Sub) -> S=egg ; number(Sub) -> S=oval ; S=rect), functor(Sub,F,_), (atom(Sub) -> S=egg ; number(Sub) -> S=oval ; S=rect),
(value(Sub,Interpretation,true) -> C=olive ; C=sienna1). (value(Sub,Interpretation,true) -> C=olive ; C=sienna1).
``` ```
%% Cell type:code id:2b497dad tags: %% Cell type:code id:2b497dad tags:
``` prolog ``` prolog
jupyter:show_graph(subnode_val(_,_,and(p,or(q,not(p))),[p/true,q/false]),subtree/3) jupyter:show_graph(subnode_val(_,_,and(p,or(q,not(p))),[p/true,q/false]),subtree/3)
``` ```
%% Output %% Output
%% Cell type:code id:0fd23f05 tags: %% Cell type:code id:0fd23f05 tags:
``` prolog ``` prolog
jupyter:show_graph(subnode_val(_,_,and(p,or(q,not(p))),[p/true,q/true]),subtree/3) jupyter:show_graph(subnode_val(_,_,and(p,or(q,not(p))),[p/true,q/true]),subtree/3)
``` ```
%% Output %% Output
%% Cell type:markdown id:013fda69 tags:
A formula for which all interpretations are models is called a <b>tautology</b>:
%% Cell type:code id:23775624 tags: %% Cell type:code id:23775624 tags:
``` prolog ``` prolog
?- use_module(library(clpfd)). jupyter:print_table(value(or(p,not(p)), [p/P],Res))
``` ```
%% Output %% Output
P | Res |
:- | :- |
true | true |
false | true |
%% Cell type:code id:7a6e29ed tags: %% Cell type:code id:7a6e29ed tags:
``` prolog ``` prolog
jupyter:print_table(value(or(p,or(q,not(q))), [p/P, q/Q],Res))
```
%% Output
P | Q | Res |
:- | :- | :- |
true | true | true |
false | true | true |
true | false | true |
false | false | true |
%% Cell type:markdown id:9ff1936a tags:
A formula which has no models is called a <b>contradiction</b>:
%% Cell type:code id:6bd292f4 tags:
``` prolog
jupyter:print_table(value(and(p,not(p)), [p/P],Res))
```
%% Output
P | Res |
:- | :- |
true | false |
false | false |
%% Cell type:markdown id:fc920c04 tags:
A formula which has at least one model is called <b>satisfiable</b>.
Two formulas are called <b>equivalent</b> iff they have the same models:
%% Cell type:code id:b912acd3 tags:
``` prolog
jupyter:print_table(value(or(not(p),q), [p/P, q/Q],Res))
```
%% Output
P | Q | Res |
:- | :- | :- |
true | true | true |
true | false | false |
false | true | true |
false | false | true |
%% Cell type:code id:f4c9823d tags:
``` prolog
jupyter:print_table(value(implies(p,q), [p/P, q/Q],Res))
```
%% Output
P | Q | Res |
:- | :- | :- |
true | true | true |
true | false | false |
false | true | true |
false | false | true |
%% Cell type:code id:aaf46953 tags:
``` prolog
``` ```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment