L13. Lazy dynamic programming

import Data.Array
 
t0 = [2,3,5,1,4]
t1 = [2,3,5,1,4,6,7,1,2,3,5,3,4,7,1,2,3,4,5,6,7,5,3,4,5,6,7,6,3,2]
t2 = [2,3,5,1,4,6,7,1,2,3,5,3,4,7,1,2,3,4,5,6]
 
-- recursive solution:
sol0 :: [Integer] -> Integer
sol0 prices = max_profit 0 ((length prices) - 1) 1
                where max_profit left right year
                            | left > right = 0
                            | otherwise = maximum [year*(prices !! left) + (max_profit (left+1) right (year+1)),
                                                   year*(prices !! right) + (max_profit left (right-1) (year+1))]
 
 
{-
 
We implement a DP matrix and populate it. In order to do so, we use "ListArray":
listArray :: Ix i => (i, i) -> [e] -> Array i e
 - i is an index-type
 - [e] is a list of 'e'
 - (i,i) designates the array bounds (start and stop)
 
In Haskell, indexing and bounds are not confined to integer. We can use anything to range over an array as long
as that anything can be mapped on a range of integers.
 
Example for using list-array:
-}
 
sol1 :: [Integer] -> Integer
sol1 l = max_profit 0 ((length prices) - 1) 1
                where prices = listArray (0, (length l) - 1) l
                      max_profit left right year
                            | left > right = 0
                            | otherwise = maximum [year*(prices ! left) + (max_profit (left+1) right (year+1)),
                                                   year*(prices ! right) + (max_profit left (right-1) (year+1))]
 
{- we can now use list-array to define a matrix: 
 
   max_profit 1 1      max_profit 1 2      max_profit 1 3
   max_profit 2 1      max_profit 2 2      max_profit 2 3
   max_profit 3 1      max_profit 3 2      max_profit 3 3
 
where each "profit" expression is unevaluated.
The start-of list must be:
[max_profit 1 1, max_profit 1 2, max_profit 1,3, max_profit 2 1, .... max_profit 3 3]
 
We also need to compute the year, because we will not store it in the matrix.
We compute it using the formula:
 year = n - (i-j)
 
Final modification is the matrix access:
    - when we have a single bottle, we need to return it's single profit with no access call.dynam
-}
 
--sol2 :: [Integer] -> Integer
sol2 l = matrix ! (0,n-1)
                where n = foldr (\_ acc->acc+1) 0 l
                      prices = listArray (0, n-1) l
                      bounds = ((0,0), (n-1,n-1))
                      --matrix = listArray bounds (map (\(l,r)->max_profit l r) (range bounds))
                      matrix = listArray bounds [max_profit l r | (l,r) <- range bounds]
                      year l r = n - (r - l) 
                      max_profit left right 
                            | left > right = 0
                            | left == right = (year left right) * (prices ! left)
                            | otherwise = maximum [(year left right)*(prices ! left) + (matrix ! (left+1,right)),
                                                   (year left right)*(prices ! right) + (matrix ! (left,right-1))]
 
r = take 3 str 
     where str = x:str
           x = 1 + 1
 
 
-- foldl (\y x-> if (x < 3) then x+y else x) 0 [2,1,0,4,5]
-- foldr (\x y-> if (x < 3) then x+y else x) 0 [2,1,0,4,5]