CS 313 - Homework 9 - Prolog

Due: Wednesday 12/1 at 10am

This assignment consists of several programming problems in Prolog. Installation instructions for SWI-Prolog are here.

The assignment has two parts; the first part you have to solve individually, but on the second part you are strongly encouraged to work in groups of two. Please submit your code for this homework as a single file hw9.pl containing all your code. For part two, if you work on a team, only one person should have the code in their hw9.pl file, the other person should just have a comment indicating the name of the team member submitting the code.

As always, include sample output (as comments in your file). Upload your file via the HW 9 submission page by 10am on Wednesday.

Part 1 - to be done individually

  1. (Sethi, problem 11.3) Define relations to determine:
    1. Is a list a permutation of another list? (You may use a helper function.)
    2. Does a list have an even number of elements? (Without using any helpers, like length.)
    3. Is a list formed by merging two lists? (Let "merging" mean interleaving the elements of the two lists while keeping them in order.)
    4. Is a list a palindrome; that is, does it read the same from left to right as it does from right to left?

    Sample output:

    1. ?- permute([a, b, c], [b, a, c]).
      true .
      
      ?- permute([1, 2, 2], [2, 1, 1]).
      false.
      
      ?- permute([1, 2, 2], [2, 2, 1]).
      true .
      
    2. ?- evenLength([1,2,3]).
      false.
      
      ?- evenLength([1,2,3,4]).
      true.
      
      ?- evenLength([1,2,3,4,5]).
      false.
      
    3. ?- mergeLists([a,b],[c,d,e],[a,c,d,e,b]).
      true .
      
      ?- mergeLists([a,b],[1,2,3],[1,a,2,b,3]).
      true .
      
      ?- mergeLists([a,b],[1,2],[1,2,a,b]).
      true .
      
      ?- mergeLists([a,b],[1,2],[1,2,b,a]).
      false.
      
      ?- mergeLists([1,2], [3], X).
      X = [1, 2, 3] ;
      X = [1, 3, 2] ;
      X = [3, 1, 2] ;
      false.
      
    4. ?- palindrome([1,2,3]).
      false.
      
      ?- palindrome([1,2,3,2,1]).
      true.
      
      ?- palindrome([1,2|T]).
      T = [1] ;
      T = [2, 1] ;
      T = [_G318, 2, 1] .
      
  2. (Sethi, problem 11.4a) Define a relation to remove adjacent duplicates.
    Sample output:
        ?- removeDup([1,2,2,3,3,3,4,5,5], X).
        X = [1, 2, 3, 4, 5] .
    
        ?- removeDup([2,2,1,1,2,2,a,a,1,1,1], X).
        X = [2, 1, 2, a, 1] .
    
  3. (Sethi, problem 11.6b) Define a relation to compute factorial in tail-recursive fashion.
    Sample output:
        ?- factorial(10, X).
        X = 3628800 .
    

Part 2 - can (should!) be done in groups of two

  1. Extend the file bst.pl (here's a .txt version) to handle insertion and deletion in binary search trees.

    1. Insertion:
            insert(N, T, Result)
      
      should insert the number N into tree T and return the result in Result. If N is already contained in T, nothing should happen (i.e., Result = T). Sample output:
        ?- insert(3, nil, Result).
        Result = node(3, nil, nil) .
        
        ?- insert(3, node(2, nil, nil), Result), show(Result).
            3
        2
        
        Result = node(2, nil, node(3, nil, nil)) 
        
        ?- insert(3, node(3, nil, nil), Result).
        Result = node(3, nil, nil) .
        
        ?- mytree1(T), insert(6, T, Result), show(Result).
                9
            8
                7
          	      6
        5
            3
        
        T = node(5, node(3, nil, nil), node(8, node(7, nil, nil), node(9, nil, nil)))
        Result = node(5, node(3, nil, nil), node(8, node(7, node(6, nil, nil), nil), node(9, nil, nil))) .
      
    2. Deletion:
            remove(N, T, Result)
      
      should remove the number N from tree T and return the result in Result. If N is not contained in T, nothing should happen (i.e., Result = T). The algorithm for deletion is as follows (let N be the node to be deleted):
      • if N is a leaf, return nil
      • if N has only one child, return that child
      • if N has two children, replace N's value with the maximum value in the left subtree, and remove that value from the left subtree.
      Sample output:
           ?- remove(3, node(3, nil, nil), Result).
           Result = nil .
           
           ?- remove(3, node(3, node(2, nil, nil), nil), Result).
           Result = node(2, nil, nil) .
           
           ?- remove(2, node(3, node(2, nil, nil), nil), Result).
           Result = node(3, nil, nil) .
           
           ?- remove(1, node(3, node(2, nil, nil), nil), Result).
           Result = node(3, node(2, nil, nil), nil) .
           
           ?- mytree1(T), show(T).                           
      	     9
      	 8
      	     7
           5
      	 3
           
           ?- mytree1(T), remove(5, T, Result), show(Result).
      	     9
      	 8
      	     7
           3
           
           ?- mytree1(T), remove(8, T, Result), show(Result).
      	     9
      	 7
           5
      	 3
           
           ?- T=node(4,node(2,node(1,nil,nil),node(3,nil,nil)),node(5,nil,nil)),show(T).
      	 5
           4
      	     3
      	 2
      	     1
           
           ?- T=node(4,node(2,node(1,nil,nil),node(3,nil,nil)),node(5,nil,nil)),
           |    remove(4, T, Result), show(Result).
      	 5
           3
      	 2
      	     1
           
  2. Extend Pete's puzzle solver pete1.pl (here's a .txt version) to handle expressions in which the equal sign is not in the middle. E.g.,
          ?- solve(6,2,7,8).
          6=2*7-8
    
          ?- solve(3,6,1,1).
          3=6/ (1+1)
    
          ?- solve(1,2,3,9).
          (1+2)*3=9
    
          ?- solve(5,6,3,7).
          5+6/3=7
    
  3. Extend Pete's puzzle solver again, this time to handle the unary operators "-" and square root ("sqrt") in each subexpression. If your program does not always come up with the simplest expressions first - that's ok.

    Sample output (if yours is slightly different, that's ok too - as long as it finds an answer):

         ?- solve(1,2,3,9).
         1+2=sqrt(3*sqrt(9))
         
         ?- solve(2,4,3,1).
         - (2+ (-4))=sqrt(3+1)
         
         ?- solve(2,4,3,8).
         2+sqrt(4)*3=8
         
         ?- solve(4,2,6,7).
         sqrt(4)/2= - (6+ (-7))
         
         ?- solve(8,6,3,7).
         8+ (-6)=sqrt(-3+7)
    
    Your program should also be able to solve the following puzzles:
         9 4 6 8
         3 7 8 6
         4 4 5 2
         6 4 7 2
    
    
  4. Extra credit (varying amounts, depending on difficulty): Extend Pete's puzzle solver further. Possibilities include: exponentiation, nth root, factorial, and an arbitrary number of unary operators (but trying the fewest number first). (Let's not use "mod" as a valid operation.) Most of these are quite tricky - some (like factorial) require defining new arithmetic functions, others (like exponentiation) require several checks on valid parameters. Ask me for help if you get stuck.

    Which of the following puzzles can your program solve?

         3 5 2 2
         3 5 7 0
         4 6 5 0
         1 7 4 1
         1 7 5 7
         3 5 2 5
         4 7 3 7
         7 4 7 9
         8 6 8 0
         5 8 5 7