Blog do projektu Open Source JavaHotel

Pokazywanie postów oznaczonych etykietą Math. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą Math. Pokaż wszystkie posty

piątek, 15 listopada 2013

Clojure, tautology and logical expression

Introduction
I decided to create a simple Clojure project for verifying logical tautologies. The source code is available here.

For instance:

 ((A \land B) \to C) \Leftrightarrow (A \to (B \to C)).
The algorithm is simple:
  1. Parse the logical expression
  2. Generate all possible combination of values for literals in the expression
  3. Evaluate the results for any value
  4. If every result is true then we have a tautology
It is not an optimal method for proving the tautology because the complexity is exponential but if we have a small number of literals it can run pretty fast.

Definition
Grammar for logical expression to be analyzed:

<expression> ::=
    [~] < expression >
         | <literal>
         | ( < expression > <operator> <expression>)

< literal > ::= chain of letter and digits starting from letter
< operator > ::= 
    & : logical AND
    ^ : logical OR
    == : logical equivalence
    => : logical implication
    ~ : logical NOT

Remarks:
  • I assume that every subexpression (except literals) should be enclosed in parenthesis. For instance: (A & B) but not (A & B ^ C). This I'm avoiding a problem related to operator precedence. Because any logical expression can be "normalized" that way it is not a limitation which matters.
  • The tautology quoted above can be put down that way: (( A & B) => C) == (A => (B => C))
  • One of De Morgan's Laws: ~(A & B) == (~A ^ ~B)
Parser
The first thing to do is the "tokenizer" - creates a flow of separated components. It can be achieved simply by means of regular expression.

  [seqw (re-seq #"[A-Za-z][\w]*|[\^\(\)&~]|=>|==" str)]

Source code for parser is available here.
 
defn parse
"parse string expression
 returns three element vector (Polish notation: (operator, left operand, right operand)
 left/right operand can be an atomic operand (variable) or 
 subexpression (another triada vector)"
[str]

Parser decomposes input string to "Polish notation". Every part of the expression is transformed to a triad [operator, left operand, right operand]. In the case of negation (one parameter operator) the right operand is nil.

Evaluation

The evaluation (counting value) is very simple while the expression is decomposed.

(defn evaluate 
    [expr val]

"evaluate (calculate value) of the parsed expression using current values (as hash-map)
 returns true or false
"
    (defn getval [subexpr]
    (let 
      [operator (first subexpr)
       first (fnext subexpr)
       second (nth subexpr 2)
       firstval (if (vector? first) (getval first) (get val first))
       secondval (if (vector? second) (getval second) (get val second))
      ] 
     (cond 
        (= operator nil) firstval
        (= operator "&") (and firstval secondval)
        (= operator "^") (or firstval secondval)
        (= operator "==") (= firstval secondval)
        (= operator "=>") (if (and firstval (not secondval)) false true)
        (= operator "~") (not firstval)
        :else nil
     )
     )
     )
     (getval expr)
)
Just scan the parsed expression and calculate. "Values" is the map: { "literal" : true/false }.
Verify the tautology
 By "verifying the tautology" I mean calculating the value for every combination of literals and making sure that it evaluates as "true" all the time. First thing is to extract all literals from the parsed string. It is received by a simple statement (assuming that 'e' is parsed expression)
distinct (filter #(and (not (nil? %)) (Character/isLetter  (first %))) (flatten e))
The number of all literal combination is 2 power {number of literals}. So generating all combinations can be achieved by iterating all integers from 0 to 2 power {number of literal} and extracting literal values from binary representation of the current integer (1 as true and 0 as false.
(defn genvalues [lvals num ]
     (defn getsinglevalue [k]
        [ (nth lvals k) (odd? (bit-shift-right num k)) ]
     )
     (map getsinglevalue (range 0 (count lvals)))
  )

The last but not least is the main "verify" function. The function returns a vector of values producing false. So the expression is tautology if the output list is empty.
(defn varifytautology

"verify if logical expression is tautology
 returns the collection of values giving false result
 if list is empty then expression is tautology
"

  [str]
  (let [ vals (calculateall str)]
;    (seq (for [x vals] (println x)))
    (reduce #( if (not (second %2 )) (conj %1 %2) %1) [] vals)
  )
)

Unit tests
The series of unit tests is provided with the source. Example
; DeMorgan's Low
(deftest parse-taut2
  (let [sent "(~(p & q) == (~p ^ ~q))"
        lfalse (logical.expression/varifytautology sent)
       ]
;   (println lfalse)   
    (is (empty? lfalse))
  )
)

; DeMorgan's Low
(deftest parse-taut3
  (let [sent "(~(p ^ q) == (~p & ~q))"
        lfalse (logical.expression/varifytautology sent)
       ]
;   (println lfalse)   
    (is (empty? lfalse))
  )
)

(deftest parse-taut4
  (let [sent "((a&b)=>c) == (a=>(b=>c))))"
        lfalse (logical.expression/varifytautology sent)
       ]
;   (println lfalse)   
    (is (empty? lfalse))
  )
)

; the Distribution Law
(deftest parse-taut5
  (let [sent "(p^(q&r)) == ((p^q)&(p^r))"
        lfalse (logical.expression/varifytautology sent)
       ]
;   (println lfalse)   
    (is (empty? lfalse))
  )
)
I'm happy to announce the De Morgan's Laws still holds true.

środa, 28 sierpnia 2013

Clojure and polynomials

Introduction
I started reading through Clojure tutorial and found very interesting implementation of calculating polynomial and its first derivative. So I decided to stretch my math muscle and perform more polynomial arithmetic in Clojure basing on this article.
I'm assuming all the time that polynomial in Clojure is a list of coefficients from left to right (like in the written form). So list [2 8 9]  means 2x² + 8x + 9, [7 0 1 7] means: 7x³ + x + 7
Addition
Almost nothing more than (map + ...) function. The only problem is to expand shorter list (lower degree polynomial). Also improvement should be added to reduce the leading zeros from the result. Example:
(2x² + 8x + 9) + (-2x² + 2x + 4) = 0x² + 10x + 13

(defn addpol
  [pol1 pol2]
  ; degree of the sum polynomial 
  (let [nsize (max (count pol1) (count pol2) ) ]
  ; expand polynomial to the new degree by adding 0 coefficient at the frot
    (defn expandpol 
        [pol] 
            (concat ( repeat (max 0 (- nsize (count pol))) 0 ) pol )
    )
  )
  ; having both polynomials at the same degree just sum them
  (map + (expandpol pol1) (expandpol pol2))
)
Subtraction
Just use the previous function and negate the subtrahend.
(defn subtractpol
  [minuend subtrahend]
  ; negate subtrahend and run summing
  (addpol minuend ( map #(- 0 %) subtrahend))
)
Product
Multiply every coefficient of the first polynomial by every coefficient of the second polynomial. Recursion is used to iterate but this algorithm is a good candidate for loop->recur for better performance.

(defn mulpol
  [pol1 pol2]
  ( let
    ; level of the product
      [newlevel (- (+ (count pol1) (count pol2)) 1)]  
    ; multiply polynomial by digit and add zeros at the frond and end keeping it at the degree necessary
    (defn muldigit 
       [beg coeff end]
       (concat (repeat beg 0) (map #(* % coeff) pol2) (repeat end 0))
    )
    ; recursive as replacement for iteration
    (defn muladd
       ; 'beg' number of left zeros
       ; 'currentsum' list of coefficient multiplications peformed so far
       ; 'restpol1' list of coefficients not used yet
       ; 'end' number of right zeros
       [beg currentsum restpol1 end]
       (condp = restpol1
       ; end of recursion
       [] currentsum
       ; multiply and move to the next digit
       (
         map
            +
            currentsum
            (muladd 
               (+ beg 1)
               (muldigit beg (first restpol1) end)
               (rest restpol1)
               (- end 1)
            )
       )
       )
     )
  ; start of the recursion
  ( muladd 0 (repeat newlevel 0) pol1 (- newlevel (count pol2)))
  )
)
Division
Is more complicated because two results are expected: quotient and remainder. So to bring the result a map is used. Polynomial long division is implemented as easier. This function should be expanded to exclude division by zero (empty divisor) and reduce leading zeros from divisor. Example: (0 4 5)

; returns a map with two keys :quotient and :remainder
(defn divpol 
   [divident divisor]
   ; perform (lead(r)/lead(divisor)) * divisor
   (defn multerm
     [r resdiv]
       (concat (map #(* resdiv %) divisor) (repeat (- (count r) (count divisor)) 0))
   )
   ; recursive
   (defn div 
     [mapd]
   ( let [ q (get mapd :quotient)
           r (get mapd :remainder) 
           dv (/ (first r) (first divisor)) 
         ]
   ; end of recursion, pass down the result
   (if (or (< (count r) (count divisor)) (empty? r))
       mapd
   ; pull down the next digit from divident
       (div ( hash-map 
              :quotient (conj q dv)
              :remainder (rest (map - r (multerm r dv)))
            )
       )
   )
   )
   )   
   ; beginning of the recursion
   (div ( hash-map :quotient [], :remainder divident))
)   

czwartek, 5 listopada 2009

Equivalence class and linear subspace

(Białynicki-Birula, Algebra liniowa z geometrią, str 55)

Assume that we have a linear space Z33 and let V be a set of three vectors: {(0,0,0),(1,0,1), (2,0,2)} .

Prove that:
1) V is a linear subspace of Z33
2) There are exactly 9 equivalence classes of V.

Explanation:
Z3 is a set {0, 1, 2} having operations defined in the set of integers modulo 3. Z3 is a field.

Z33 is a set of all 3-tuples (ordered) of Z3. Examples: (1,1,2), (0,1,2) etc. Z33 is a linear space over Z3.

Equivalence class: http://en.wikipedia.org/wiki/Quotient_space_(linear_algebra)

Proof:

It is very easy to prove 1).

Let's look at 2).

Equivalence class (Polish: warstwa) is a set of all vectors being the sum of any vector of Z33 minus V and all vectors belonging to V.
Example:
Consider the vector (1,0,0). The equivalence class defined by this vector (tuple) is: {(1,0,0), (2,0,1), (0,0,2)}.
Every equivalence class is defined by a vector (tuple). So what we have to do is to find the minimal set E (subset of Z33) that every vector of Z33 is the sum of one vector of E and one vector of V.

Let Z1 be a set of all vectors (a,b,c) where a != c. Forget for a moment about b.

Let V1 be a set {(0,0), (1,1), (2,2)}. It is clear that every vector (a,c) is the sum of one of the vector of V1 and (0,1) or (0,2).
For instance:
(2,0) = (2,2) + (0,1) (modulo 3 arithmetic) (0,2) = (0,0) + (0,2) etc.
So, with respect to b, we have a set E1 of six vectors = { (0,0,1),(0,0,2),(0,1,1),(0,1,2),(0,2,1),(0,2,2)} and it defines all vectors of Z1.

Let Z2 be a set of vectors (a,b,c) where a=c and vector does not belong to V . It is clear that a set E2 of three vector = { (0,1,0), (0,2,0), (2,0,2) } is enough to define every vector belonging to Z2.
For instance:
(2,1,2) = (2,0,2) + (0,1,0)
(1,0,1) = (1,0,1) + (2,0,2)
So set E = E1 + E2 (containing 9 vectors) defines Z1 + Z2.

QAD.

czwartek, 29 października 2009

Google and eggs

One of the famous "google puzzle" - questions asked while applying for a job in Google.

There's a 100 stories building, and you have 2 eggs. You need to find out which is the highest story you can throw the egg from, and it will stay intact with the minimal throws possible. If you threw and egg and it did not break, you may throw it again. We assume that egg always breaks when throws from 100th story.

First solution
Simply throw an egg starting from 1th story and go up until egg breaks. In the worst case you need 99 throws.

Second solution
Start from 50th floor than go up (if egg does not break) or down (if breaks). In the worst case you need 50 throws (1+49).

General solution
Take number N  (N > 0 and N < 100) than start throwing the first egg by 100/N, 2 * (100/N), 3* (100/N) until 100 is reached or egg breaks (assume that it is k*(100/N) story). Than take the second egg (or first if still in one piece) and start throwing from (k-1)(100/N).

The number of trials in the worst case is (100/N) -1 + N-2.

The question : what is the minimum of this function ?

Solution, very simple using basic analysis




(derivative) 


The F is minimal when F'(N) is equal 0, so it is minimal for N=10.

Answer
The worst case takes place if the "breaking" store is 100.
So you throw egg starting from 10,20... to 90 (9 trials). Then start 91...98 (8 trials) - it is not necessary to throw egg when 98th store does not break.
The minimum number of throws is 17.

Addition remark.
The worst case takes place when the breaking store is 89.  In this case the number of throws is 16 (8+8). In the case of 99 floor we still have 2 eggs. So we can throw from 93 and 96th floor and go on accordingly using less than 16 throws

So the final answer is: 16 throws.

wtorek, 20 października 2009

Math exercise and proof

(Michał Krych - Analiza Matematyczna część 1)

Assume that we have N positive numbers and the sum of this numbers is not greater than N.



Prove that multiplication of this numbers is not greater than 1.


Proof                                                                                                        
Assume that all number are equal - obvious.
Assume that not all numbers are equal.

Induction proof.
The statement is satisfied for N=1 - obvious.

Inductive step.
Assume that statement holds true for all 1...N-1
Now consider a set of N positive numbers, call their sum as S(n) and assume that S(n) is less or equal N. Call the product if this numbers as P(n).
Because the numbers are not equal at least one should be greater than 1 and at least one should be less than 1.
Call them a1 = 1 + x and a2 = 1 - y.
Consider set of N-2 number (all numbers except a1 and a2) and call its product as P(n-2) and sum as S(n-2)
Than add to this set the number 1 + x - y. This number is positive and call the sum of this numbers (including 1 + x - y) as S(n-1).

Call the product as P(n-1). Using the induction hypothesis P(n-1) is less or equal 1.

Now let's calculate P(n). Keep in mind that x*y is greater than 0.

Q.E.D

niedziela, 4 października 2009

Math exercise and proof

Exercise from "Michał Krych, Analiza Matematyczna część 1".



Assume that we have an infinite grid filled with natural numbers. Every number P and four number a,b,c,d in adjacent cells should satisfy the equation 4*P <= a + b + c + d.
Prove that all numbers in grid are equal.






Proof                                                                                                                       

Notice that grid filed with equal numbers holds statement.

Assume that there exists a grid which satisfy equation and have different numbers.

Inductive proof.

Assume that P = 1. It involves that a,b,c,d should be also equal 1 because it is the only way to satisfy equation. The same can be applied for a, b,c d and their adjacent cells and on. So having number 1 in one cell cause all grid being filled with 1. So we have to exclude number 1 from grid.

Assume that all numbers from 1 to N are excluded. Look at the cell with number N+1 and having at least one number different than N+1 in adjacent cell (assume number a). "Different" means greater then N+1 because all number less than N are excluded. But if a > N and b, c and d  >= N then a+b+c+d > N which breaks equation.

That means that all natural number are excluded from the grid and the only grid holding statement must have all number equal.