J.doe
J.doe

Reputation: 373

Get the minimum value

I have a function 'getMin' which should return the minimum value. This function uses another function 'urvalFun' in order to determine this minimim value. Here is a demonstration of 'urvalFun'

get1:: (String,String,Double ) -> String
get1  (x,_,_ )  = x

get2 :: (String,String,Double)-> String
get2 (_,x,_) = x

get3:: (String,String,Double)->Double
get3 (_,_,x) = x

distDiff:: String-> String->[(String,String,Double)] ->Double  
distDiff a b diMat = sum [z |(x,y,z)<- diMat, (x == a && y /= b)
|| (y == a && x /= b)  ]

urvalFun:: Int -> (String,String,Double)->[(String,String,Double) ]->Double
urvalFun size triple diMat  =  ((fromIntegral size)-2)*(get3 triple)
         -  ( (distDiff (get1 triple) (get2 triple) diMat ) + (distDiff (get2 triple) 
        (get1 triple) diMat ))

Its not necessary to understand this chunck of code, the only thing that is important is that if i evaluate:

urvalFun 3 ("a","b",0.304)  [("a","b",0.304),("a","d",0.52),("a","e",0.824)]

this will evaluate to -1.03999

 urvalFun 3 ("a","d",0.52)  [("a","b",0.304),("a","d",0.52),("a","e",0.824)]

this will evaluate to - 0.60799

urvalFun 3 ("a","e",0.824)  [("a","b",0.304),("a","d",0.52),("a","e",0.824)]

this will evaluate to 1.1e^-16

now we know that calling urvalFun with ("a","b",0.304) and [("a","b",0.304),("a","d",0.52),("a","e",0.824)] will get the value which is the smallest. I want to create a function 'getMin' which will return this minimum value (with the same vector as in the above examples as a parameter) ,as shown above. The problem is that it won't work I have no clue why

getMin:: [(String,String,Double)]->Double
getMin diMat  = inner 0 diMat 2000
  where
  inner 3 diMat min = min
  inner n diMat min
    |current > min = inner (n + 1)  (diMatMinus ++ [(head diMat) ])  min
    |otherwise = inner (n+1) (diMatMinus ++ [(head diMat) ]) current
  current = urvalFun (length diMat) (head diMat) diMat
  diMatMinus = tail diMat

try to evaluate for example

getMin  [("a","e",0.824),("a","d",0.52),("a","b",0.304)]

which will evaluate to -1.1e^-16

which is not want i intended because I want this to return -1.03999

Could someone help me out here?

(this code is a little bit ad hoc but it is under construction, I am just doing some tests right now)

notice that i have rearranged the vector so that the triple ("a","b",0.304) is the last element in the vector.

Upvotes: 0

Views: 1077

Answers (3)

ErikR
ErikR

Reputation: 52039

Note that for a list of size 3 your getMin function may be written:

getMin' [x,y,z]
  = minimum [  urvalFun 3 x [x,y,z]
            ,  urvalFun 3 y [y,z,x]
            ,  urvalFun 3 z [z,x,y]
            ]

You can create the sequence of arguments to the urvalFun function with zip and and a helper function:

rotate (x:xs) = xs ++ [x]

zip "xyzw" (iterate rotate "xyzw")
  = [ ('x', "xyzw"),
      ('y', "yzwx"),
      ('z', "zwxy"),
      ('w', "wxyz") ]

Thus:

import Data.List

getMin tuples = minimum (zipWith go tuples (iterate rotate tuples))
  where n = length tuples
        go (x,xs) = urvalFun n x xs

Upvotes: 1

chi
chi

Reputation: 116139

You want to find the value in a given list which minimizes your function.

I'll work with a simpler example than yours: finding the string with minimum length. You'll be able to adapt this to your case by replacing the length function.

> import Data.Foldable
> let list = ["hello", "world!", "here", "is", "fine"]
> minimumBy (comparing length) list
"is"

The above works, but it will call length every time it performs a comparison, i.e. roughly twice the length of the list. It is also possible to avoid this, and use length only once per element, by precomputing it:

> snd $ minimumBy (comparing fst) [ (length x, x) | x <- list ]

We first pair each string with its length, take the minimum length-string pair according to the length only, and finally take only the string in such pair.

By the way, I'd recommend you avoid functions such as get1 to access tuples: they are not idiomatic in Haskell code, which usually exploits pattern matching for the same effect: for instance

urvalFun:: Int -> (String,String,Double)->[(String,String,Double) ]->Double
urvalFun size (s1,s2,d) diMat =
   (fromIntegral size - 2)*d - distDiff s1 s2 diMat + distDiff s2 s1 diMat

looks more readable.

head,tail are also particularly dangerous since they are partial: they will crash your program if you ever use them on a empty list, without providing much explanation.

In general, when working with lists, using indexes, or counter variables to count up to the length of the list, is typically not needed and not idiomatic. One can often simply resort to pattern matching and recursion, or even to standard fold/map functions.

Upvotes: 1

pdexter
pdexter

Reputation: 811

First you need a way to get the minimum element to pass to urvalFun. This can be done with minimumBy.

Observe the following

λ> let ls = [("a","d",0.52),("a","e",0.824),("a","b",0.304)]                                                                                                                                                        
λ> let min = minimumBy (\(_,_,c) (_,_,c') -> compare c c') ls                                                                                                                                                       
λ> urvalFun 3 min ls                                                                                                                                                                                                
-1.0399999999999998 

Or maybe this is what you intended:

λ> minimum [ urvalFun 3 x ls | x <- ls]                                                                                                                                                                             
-1.0399999999999998

If you also want to alter n from 0 to 3 or something, then this can be further modified. I'd suggest stating in english what you want your function to do.

Upvotes: 3

Related Questions