1

I need to apply a function on elements of a vector in Haskell in an efficient way, which implies that i am not looking for something like this:

sigmoid :: [Float] -> [Float]
sigmoid [] = []
sigmoid (z:zs) = ( 1/(1+exp (-z)) ):(sigmoid zs) 

To be more specific, are there exp, log, ... etc for element-wise vector operations in hmatrix using Haskell, similarly to their counterparts in numpy using Python? My code runs very slowly if I am not using vector processing capabilities.

duplode
  • 33,731
  • 7
  • 79
  • 150
mahmoud fathy
  • 361
  • 1
  • 7
  • 17
  • 1
    Don't translate performance considerations from Python (or Matlab etc.) to Haskell. What these languages call _vectorisation_ is only sensible because they are slow, dynamic languages, so the overhead of looping over individual elements within the language is greater than the overhead of a few intermediate array allocations. But that's not the case in fast, statically compiled languages like Rust, C, Java and, indeed, Haskell. – leftaroundabout Mar 25 '18 at 18:12
  • (That doesn't mean just using Haskell lists is a good idea, of course – these introduce cache-locality issues which make the language much slower than C etc.. And yes, there is also a kind of vectorisation that always makes sense, namely parallelisation either on a large scale or with small chunks that can be processed in a single AVX instruction.) – leftaroundabout Mar 25 '18 at 18:15
  • @leftaroundabout that's what I mean by vectorization. I want my Haskell code to utilize SIMD executions. – mahmoud fathy Mar 26 '18 at 11:36
  • Interesting, but I wouldn't expect too much from this for something like this sigmoid. There is no exponential function in the AVX instruction set. To really speed up something like this with SIMD, you'd need to run it on a GPU; check out [accelerate-llvm-ptx](http://hackage.haskell.org/package/accelerate-llvm-ptx). – leftaroundabout Mar 26 '18 at 12:06

1 Answers1

6

If you are using hmatrix, you are probably looking for cmap:

cmap :: (Element b, Container c e) => (e -> b) -> c e -> c b

like fmap (cannot implement instance Functor because of Element class constraint)

sigmoid :: Vector Double -> Vector Double
sigmoid = cmap (\z -> 1/(1+exp (-z)))
duplode
  • 33,731
  • 7
  • 79
  • 150
  • This seems very sound, I will try assess the computation once I get back to my machine. I hope it doesn't take the same amount of time as regular pattern matching, I am doing that for machine learning. – mahmoud fathy Mar 26 '18 at 11:33
  • So .. Does this utilize SIMD, because that's what I mean Technically ? – mahmoud fathy Mar 26 '18 at 11:37
  • "I hope it doesn't take the same amount of time as regular pattern matching" -- I suggest not focusing your attention literally on pattern matching, as it, at most, a symptom of whatever else is going on. On the surface, `map (\z -> 1/(1+exp (-z))) :: [Double] -> [Double]` doesn't *seem* to be doing any pattern matching, yet it boils down to essentially the same code in your question. What truly matters is that the `[Double]` data structure isn't well suited to your use case. – duplode Mar 26 '18 at 18:19
  • "So .. Does this utilize SIMD, because that's what I mean Technically ?" -- [*hmatrix* uses BLAS, which exploits SIMD](https://hackage.haskell.org/package/hmatrix-0.18.2.0), but cf. [leftaroundabout's comment](https://stackoverflow.com/questions/49478373/apply-element-wise-mathematical-function-using-hmatrix-with-vectorization/49478712?noredirect=1#comment85985143_49478373) (and also note that he knows a lot more about this kind of issue than I do). By the way, as usual, the best way of finding out whether something provides good enough performance for your use case is by testing it. – duplode Mar 26 '18 at 18:22
  • 1
    I tested it and it's obviously way faster than using the ordinary haskell lists – mahmoud fathy Mar 28 '18 at 00:49