2.1 Truth Tables 2.2 Satisfiability and universal validity of propositional sente3 Computing with the Propositional Calculus
3.1 Deciding whether a proposition is a tautology 3.2 The Resolution Principle4 Boolean Algebra in Computer Architecture
Beginning with the work of the English mathematician Boole, logical reasoning, which had classically been semi-formalised using syllogisms, has been made the subject of mathematical investigation. In the 20th century the formalisation of mathematical reasoning has made great progress; however it also has become apparent that there are limitations on what we can possibly know through mathematical reasoning.
The need for a tighter formalism, even for mathematics, became manifest when David Hilbert showed that to express in a purely algebraic style Euclid's Geometry, which had been regarded as a model of mathematical precision for over 2000 years, required an extension of Euclid's axioms - the traditional treatment of geometry had, in effect, hidden axioms embodied in the "correct" way of drawing the figures.
The kinds of problem that have been addressed by 20th century mathematical logicians are exemplified by:
In attacking these questions, which required the rigorous formalisation of logical reasoning, mathematicians were laying the foundations of the theory of computation, since what can be characterised formally can in principle be computed.
Conversely, we as computer scientists, may find it easier to understand aspects of mathematical logic from a computational viewpoint. Consider for example the question:
In the domain of arithmetic (the theory of the natural numbers) we translate this into computing terms quite easily. Suppose we have a proposition about natural numbers of the form
forall n P(n)
where the property P can be tested for given values of n by running a computation. Then let us write a Scheme function that systematically works through all possible values of n, checking if P(n) holds, and returning the value of the first n for which P does not hold. So if P is a theorem, our function never halts. So we have related the problem of deciding if a mathematical proposition is true or false to the problem of deciding whether a given program stops. Now we saw in Lecture 15 that we cannot in general determine whether a given program halts. So we may suspect that we cannot in general determine whether a given mathematical proposition is true or false.
Our argument is not watertight, for while we shown that the problem of determining the truth of a certain propositions in arithmetic is a halting problem, we haven't shown that it is a general halting problem. However a watertight linking of these two can be made, as was first done by Alan Turing, who showed, using an argument about computability, that determining the truth of a mathematical proposition is undecidable.
As a specific example, consider the Goldbach Conjecture which states that every even number greater than 2 is the sum of two primes. Now we could (quite) easily write a function goldbach? for which the call (goldbach? n) would evaluate to #t if the Goldbach hypothesis is true for the natural number n, and #f if it is false (since both of the primes must be less than n we don't have to search through the infinite set of primes to verify the conjecture for a given n). Thus, for a given n the Goldbach function will terminate. Now consider the function:
(define (test_goldbach n) (if (goldbach? n) (test_goldbach (+ n 2)) #f) )
The execution of (test_goldbach 4) will halt if and only if the Goldbach hypothesis is false. Does this execution halt? We don't know, since mathematicians have never found either a proof of or a counterexample to the Goldbach conjecture.
In general we may conclude that any mathematical system that is powerful enough to characterise a general computation is undecidable.
A system of mathematical logic is normally called a calculus. This usage must not be confused with the differential and integral calculus which is a separate branch of mathematics. There are 3 logical calculi of interest to computer scientists.
likes(John,Mary)might be a proposition encoding the idea that John likes Mary.
3 The Lambda Calculus: The functional subset of Scheme can be considered as an implementation of a variant of this calculus. The Lambda Calculus is a fully fledged logical calculus, which offers advantages in proving properties of computations. As exploited and developed by computer scientists, most notably Robin Milner, it is a viable alternative to the Predicate Calculus, and has been embodied in a semi-automatic proof system HOL (Higher Order Logic)
The propositional calculus is built from the following components, given below in an approximation to their conventional typeset form.
propositional variables p,q,r,... propositional connectives &, \/, ~, ->, <->We can represent sentences of the propositional calculus in Scheme by using the usual Scheme conventions
(and p q) (or p q) (not p) (-> p q) (<-> p q)
Given a sentence S in the propositional calculus, and a mapping from the
propositional variables occurring in S to the truth values T and F, we can
define an interpretation
of S under this mapping as being the value T or F
depending on how S is evaluated according to the following scheme of truth
tables:
A sentence S in the propositional calculus is said to be satisfiable if there is a mapping of variables to truth-values under which it S is interpreted as T.
A sentence S in the propositional calculus is said to be unsatisfiable if there is no mapping of variables to truth-values under which it S is interpreted as T.
A sentence S in the propositional calculus is said to be universally valid if for all mappings of variables to truth values S is interpreted as T. We also speak of such a sentence as being a tautology.
The prime observation that offers one approach to computing with the propositional calculus is working out an interpretation of a propositional calculus sentence is the same kind of problem as interpreting a Scheme expression
That is to say, the mapping of propositional variables to truth values can be represented in an environment, and we can use eval_env, with suitable entries for -> and <-> in the environment, to find interpretations (assuming that and and or and not are already in place. Note that we do not need to treat and and or as special forms for this purpose.
Now, given a sentence S, there are only a finite number n of propositional variables in S, so there are 2n possible environments binding the variables of S to have the values T and F.
So we can decide if a sentence in the Propositional Calculus is universally valid (the good news) but it may take us 2n evaluations of the sentence to do so (the bad news). Decidability is possible in the Propositional Calculus because it is a very limited formalism - too weak to construct arithmetic, for example.
So, we can decide whether a sentence in Propositional Logic is a tautology in exponential time. Can we do better? We can use a proof system which embodies rules of classical logic (e.g. modus ponens) to try to find a proof for a propositional sentence in less than exponential time. In practice such proof systems may work quite well, but it is believed that any (finitely statable) proof system for Propositional Logic will require exponential time to find proofs of some propositions. This has been shown to be the case for some proof systems.
The proof method that has had most influence on computing is the resolution principle. In the propositional calculus, this appears as follows.
Consider two sentences of the Propositional Calculus of the form:
~p \/ q p \/ r
from these we may infer
q \/ r
if we consider the tautology (~p \/ q) <-> (p -> q), so we have
p -> q p \/ r
from which we may infer
q \/ r
[Or in English, if proposition p implies proposition q and we know that either proposition p is true or proposition r is true, then we may infer that proposition q is true or proposition r is true.]
Now look at what we have done. From:
~p \/ q p \/ r
we have inferred
q \/ r
This is rather like cancellation of a term in ordinary algebra. This kind of "cancellation" between negated and non-negated terms in a disjunction is the essence of resolution. We can systematise the use of this principle in a way rather parallel to what we did for polynomials in our last programming problem. Remember that we defined a function to convert an arbitary expression whose only functions were + and * to the standard expression of a polynomial as a sum of monomials. Well, we can do something very similar to a sentence of the propositional calculus - we can convert it into a conjunction of disjunctions of literals. A literal is a propositional variable or its negation. So a disjunction of literals in logic plays the same role as a power product in polynomials. Because it doesn't matter how many times a given expression occurs in a disjunction, we don't need a distinction corresponding to the monomial/power-product distinction.
Such a disjunction of literals is called a clause.
An empty disjunction of literals is called the empty clause - it always evaluates to F. Thus the empty clause is unsatisfiable.
The process of converting a sentence of Propositional Calculus into a conjunction of clauses is called putting it into conjunctive normal form.
It proceeds as follows:
(1) Get rid of all connectives except &, \/ and ~ by using the following tautologies, left to right. [By using a tautology left-to-right I mean that we use what is to the left of the major <-> symbol as a pattern to match against any sub-expression of our sentence, and we replace it by the appropriate version of what is to the right of the major <-> symbol.]
(p <-> q) <-> ((p -> q) & (q -> p)) (p -> q) <-> (~p \/ q)(2) Now use the following tautologies left to right:
p \/ (q & r) <-> (p \/ q) & (p \/ r) (q & r) \/ p <-> (p \/ q) & (p \/ r) ~ (p \/ q) <-> ~p & ~q ~ (p & q) <-> ~p \/ ~q ~~p -> p(3) Finally we can eliminate redundant copies of the same literal occurring in the same clause [since (p\/p) <-> p], and also if a literal and its negation occur in the same clause, we delete them both [since (p\/-p <-> T)] The general case of the resolution principle in Propositional Calculus is to take two clauses, that is to say sentences of the form:
l1 \/ l2 \/ l3 ....\/ p \/....\/ ln k1 \/ k2 \/ k3 ....\/ ~p \/....\/ kmThese are equivalent, using the associativity and commutativity laws of Boolean algebra to:
p \/ (l1 \/ l2 \/ l3 ...\/ ln) ~p \/ (k1 \/ k2 \/ k3 ...\/ km)Recall that l1...ln are literals, that is they are either of the form q or of the form ~q for some propositional variable q. Then we may infer, from our earlier discussion, that:
l1 \/ l2 ...\/ ln \/ k1 \/ k2 \/ k3 .... \/....\/ kmthat is we have "cancelled out" a propositional variable and its negation.
The resolution principle provides a complete proof method for the propositional calculus, that is to say systematic application of resolution will always find a proof if one exists provided we use proof by reductio ad absurdum. That is to say we start with the negation of what we want to prove and proceed to resolve clauses against each other until we obtain an unsatisfiable clause, which is our demonstration of the "absurd".
To use resolution to prove a proposition S, do the following steps:
(1) Negate the sentence to be proved obtaining ~S (2) Express ~S as a conjunction of clauses (3) Systematically apply the resolution principle to infer new clauses until EITHER (a) the empty clause is found, In this case we know that ~S is unsatisfiable, so that S is a tautology. OR (b) until there are no more new resolutions to be done.
Since the only new clauses we get by resolution contain the same variables as the original sentence S, there are only a finite number of possible clauses that can be generated, so the above process MUST terminate. However there are O(2n)) many different clauses possible on n variables, so we could take exponential time to find a proof, or to fail to find a proof.
For example, consider the proposition:
((p -> q) & (q -> r)) -> (p -> r)
To prove this by resolution we negate it:
~( ((p -> q) & (q -> r)) -> (p -> r) )
And now replace all instances of the -> connective
~( ~((~p \/ q) & (~q \/ r)) \/ (~p \/ r) )
now we move the outermost "~" inwards (we have plenty of choice here, but I'm trying to make things look simpler).
~~((~p \/ q) & (~q \/ r)) & ~(~p \/ r) )
Now we can use the fact that double negation is affirmation, and also move the "~" at the right inwards:
((~p \/ q) & (~q \/ r)) & (~~p & ~r) )
Removing another double negation, we have a clausal form
((~p \/ q) & (~q \/ r)) & (p & ~r) )
that is the clauses
~p \/ q [1] ~q \/ r [2] p [3] ~r [4]Resolving [1] with [3] we obtain
q [5]Resolving [2] with [4] we obtain
~q [6]
Resolving [5] with [6] we obtain the empty clause (the hungry tiger) and our proof is done. But we might observe that [5] and [6] are manifestly contradictory.
Many of you will know that boolean algebra (equivalent to the Propositional Calculus) is used in the design of computers. Do we have a paradox here? We have seen that it is decidable whether a statement in the Propositional Calculus is a tautology, and yet if computers are built out of logic circuits, surely the behaviour of a program can ultimately be translated into Propositional Logic, and so should be decidable. But the halting problem is undecidable.
There is no real paradox, because any general purpose computing machine must have memory elements which give it state. The behaviour of these memory elements cannot be characterised in the Propositional Calculus, so there is no paradox.
Thus Boolean Algebra plays a significant role in the design of computers, but it is inadequate to analyse a design completely.