{-#####################################################

   HOMEWORK 10

   ALAIN V. DE LARA

#####################################################-}

 

module HW10 where

import Hugs.Prelude

 

{-#####################################################

  exercise 17.2 

  SUBSEQUENCES AND SUBLISTS

 

* nonsubsequences are obtained by omitting elements inside the string

 

* subsequences are obtained by removing strings of various length in the

  original strings respecting the order

 

* LIST= nonsubsequences  + subsequences

#####################################################  -}

 

{-

pairs::[a]->[b]->[(a,b)]

pairs xs ys=[ (x,y) | x<-xs, y<-ys ]

-}

 

-- mixup does the same as "pairs" but for list of list

-- mixup [[1,2],[3,4]]  [[5,6],[7,8]] ==>                                                                        

-- [[1,2,5,6],[1,2,7,8],[3,4,5,6],[3,4,7,8]]

 

mixup::[[a]]->[[a]]->[[a]]

mixup xs ys =[ x++y | x<-xs,y<-ys]

 

-- genleft [1,2,3,4]=> [4],[3,4],[2,3,4],[1,2,3,4]

genleft::[a]->[[a]]

genleft ls=[ subtake (s-l) l ls | l<-[1..s] ]

  where s=(length ls)

 

-- genright [1,2,3,4]=> [1],[1,2],[1,2,3],[1,2,3,4]

 

genright::[a]->[[a]]

genright ls=[ subtake 0 l ls | l<-[1..s] ]

  where s=(length ls)

 

getr::Int->[a]->[a]

getr pos ls=drop pos ls

 

getl::Int->[a]->[a]

getl pos ls= take (pos-1) ls

 

-- this algorithm omit the [first,last] case

 

nonsub::[a]->[[[a]]]

nonsub ls=[[head ls,last ls]:mixup(genleft(getl i ls)) (genright(getr i ls)) |i<-[2..s-1]]

    where s=(length ls)

 

-- ***************************************************************

-- subtake: get sub-string eg: 

-- subtake 2 3 "abcdefgh" => "cde" ( string "cde" returned )

-- ***************************************************************

 

subtake= (\ start len ls->take len (drop start ls) )

 

subseq::[a]->[[a]]

subseq ls=[subtake i j ls| i<-[0..(s-1)], j<-[1..(s-i)]]

   where s=(length ls)

 

-- ***************************************************************

-- cutoff : return the remaning string, eg:

-- cutoff 2 3 "abcdefgh" => "abfgh" ( cut "cde" from string )

-- ***************************************************************

 

sublists::[a]->[[[a]]]

sublists ls=[(subseq ls)] ++ (nonsub ls)

 

{-#####################################################

  exercise 17.23 

  FACTORS AND HAMMING NUMBERS 

####################################################### -}

 

{- ******* Sample of Hamming numbers *********

1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,

48,50,54,60,64,72,75,80,81,90,96,100,108,120,125,128,135,

144,150,160,162,180,192,.........

 

definition of hamming number=2^i*3^j*5^k for i, j, k >0

 

other definition of hamming number=a number that does  have

                                   prime factors other than 2,3,5

********************************************** -}

 

-- ####### FIRST VERSION #######

 

-- slowest version of isprime

 

isprime1::Int->Bool

isprime1 n=(factors1 n==[1,n])

 

factors1::Int->[Int]

factors1 n=1:[q | q<-[2..n],(mod n q)==0]

 

-- does a list have prime numbers other than 2,3,5 ?

-- return true if list has prime numbers 7,11,13,19,23,29.....

 

badprime1::[Int]->Bool

badprime1 []=False

badprime1 (x:xs)

   | x==2 || x==3 || x==5 =badprime1 xs

   | (isprime1 x)=True                -- primality test  

   | otherwise=badprime1 xs

 

ham1=1:[ i | i<-[2..] , not(badprime1(factors1 i)) ]

 

-- reaches 4320 (138th) in 30 seconds

 

-- ####### OPTIMIZED VERSION ######

 

-- fast isprime

-- return [] if the number is prime >=7

-- if n=a x b then either a or b must be <sqrt(n+1)

-- only checks odd numbers

 

isprime2 ::Int->[Int]

isprime2 n

 |(n>2) && not(mod n 2==0)=[i |i<-[3,5..floor(sqrt (fromInt n))+1],(mod n i)==0]  -- test for oddness

 | otherwise=[n]

 

-- modified factors to improve speed

-- only checks odd factors

 

factors2::Int->[Int]

factors2 n=[q | q<-[3,5..n],(mod n q)==0]

 

-- does a list have prime numbers other than 2,3,5 ?

-- return true if list has prime numbers 7,11,13,19,23,29.....

-- use fast version of isprime

 

badprime2::[Int]->Bool

badprime2 []=True

badprime2 (x:xs)

   | x==2 || x==3 || x==5 =badprime2 xs

   | (isprime2 x)==[]=False                -- primality test  

   | otherwise=badprime2 xs

 

ham2=1:2:3:4:5:[ i | i<-[6..] , badprime2(factors2 i) ]

 

-- reaches 10000 (175th) in 30 seconds

 

{-#####################################################

  exercise 17.24 

  INFINITE RUNNING SUMS 

  differents solutions for finite and infinite running sums

####################################################### -}

 

-- special case "[0..]"

-- implementation with function mapping

 

runsum1 x= if (x==0) then 0

           else x + runsum1 (x-1)

 

runningsum1 = map runsum1 [0,1..]

 

-- COMMENTS about runningsum1, very slow

-- reaches 3,260,181 in 15 seconds

 

-- ************************************************************

 

-- Implementation of the running sum the recursive way

-- still for special case "[0..]"

 

runsum2 x y= x:  runsum2 (x+y) (y+1)

runningsum2=runsum2 0 1

 

-- COMMENTS about runningsum2, very fast

-- about 200 times faster than "runningsum1"

 

-- ************************************************************

-- If the list is finite and with few elements

-- eg runsum3 [1,2,3,4,5,6]=>[1,3,6,10,15,21]

-- using substring of a list: sum(subtake 0 3 [1,2,3,4,5,6])=>sum([1,2,3])=>6

 

runsum3::[Int]->[Int]

runsum3 ls=[sum (subtake 0 index ls) | index<-[1..s] ]

  where s=length ls

 

-- ************************************************************

-- If the list is infinite

-- the algorithm slows down when the list become "big"

 

runsum4::[Int]->[Int]

runsum4 ls=[sum (subtake 0 len ls) | len<-[1..] ]

 

-- ************************************************************

-- final solution

-- same algorithm like "runsum2"

-- the processing speed remain the "same" at any moment

 

runsum5::[Int]->[Int]

runsum5 []=[0]

runsum5 (s:ls)=runsumrecursiv s  ls

 

runsumrecursiv::Int->[Int]->[Int]

runsumrecursiv s []=[s]

runsumrecursiv s ls =s: runsumrecursiv (s+head(ls)) (tail ls)

 

{-#####################################################

   LIST OF FOUR SQUARES PROBLEM

####################################################### -}

 

{-

 

page 365:

pythagtriples=[(x,y,z) | z<-[2..],y<-[2..z-1], x<-[2..y-1], x*x+y*y==z*z]

 

-}

 

-- first solution with squares,but there are problems

-- EG:squares 23  give [4,2,1,1,1] for 23

-- because the answer should be (23, [3, 3, 2, 1]).

 

squares 0 = []

squares n =

  let m = (floor (sqrt (fromInt n))) in

    m : squares (n - m*m)

 

foursquares=[(k,squares k) | k<-[0..] ]

 

-- ######## FIXED #########################################

 

-- makeclean: cleanup the zeros:

-- makeclean [1,2,3,4]=>[1,2,3,4]

-- makeclean [0,1,2,3]=>[1,2,3]

-- makeclean [0,0,1,2]=>[1,2]

-- makeclean [0,0,0,1]=>[1]

-- makeclean [0,0,0,0]=>[]

 

makeclean::[Int]->[Int]

makeclean [0]=[]

makeclean (x:xs)

 | x==0=makeclean  xs

 | otherwise =x:xs

 

-- will return lots of solution==> only take the first one

 

fsq n=head[makeclean[s,t,u,v] | s<-[0..(sqint n)],t<-[0..(sqint n)],u<-[0..(sqint n)],v<-[0..(sqint n)],n==s*s+t*t+u*u+v*v]

       where sqint x= floor(sqrt(fromInt x))

 

lfsq=[(k,fsq k) |k<-[0..]]

 

{-######################################################-}

{-######################################################-}