arrayfire / arrayfire-haskell

Haskell bindings to ArrayFire
http://hackage.haskell.org/package/arrayfire
BSD 3-Clause "New" or "Revised" License
59 stars 5 forks source link

Strong types for logical operators #20

Closed noughtmare closed 4 years ago

noughtmare commented 4 years ago

For example lt, gt, le, ge, eq, neq should have type AFType a => Array a -> Array a -> Array CBool.

And functions like and, or should have type Array CBool -> Array CBool -> Array CBool.

And not should have type Array CBool -> Array CBool.

By the way why is Bool not an instance of AFType? Would it be possible to write an instance that uses CBool under the hood?

dmjio commented 4 years ago

For example lt, gt, le, ge, eq, neq should have type AFType a => Array a -> Array a -> Array CBool.

Thanks, I can adjust this to make the types more narrow.

By the way why is Bool not an instance of AFType? Would it be possible to write an instance that uses CBool under the hood?

CBool maps more correctly to the ArrayFire C API.

http://hackage.haskell.org/package/base-4.12.0.0/docs/Foreign-C-Types.html#t:CBool

Note bool in

af_err af_lt    (af_array *out, const af_array lhs, const af_array rhs, const bool batch); 

The Storable on Bool is actually a 32-bit Int and not a C bool.

We could attempt to munge the two. That's more or less what I've done with the Eq and Ord instances.

instance (AFType a, Eq a) => Eq (Array a) where
  x == y = toEnum . fromIntegral $ A.getScalar @CBool @a $! A.eq x y
  x /= y = toEnum . fromIntegral $ A.getScalar @CBool @a $! A.neq x y

Come to think of it. I bet we should be using af_all_true after calling A.eq before fetching the scalar out, to ensure equality across all dimensions. Thanks for bringing this to light.

dmjio commented 4 years ago

Since Array a is not a Functor (and can't be), it's not as straightforward to map CBool to Bool. One thing we could try is to castArray from Array CBool to Array Int32 and then peek the values off as if they were Bool. Otherwise, calling fmap (toEnum . fromIntegral) . toList :: Array CBool -> [Bool] might be best

dmjio commented 4 years ago

image

The spec says only the output is b8, I'll return CBool. Similarly, not sure what logical and would be on floating point numbers, but its technically allowed.

> (8 :: Array Double) `A.and` (2 :: Array Double)
[1 1 1 1] 
        1
dmjio commented 4 years ago

https://github.com/arrayfire/arrayfire-haskell/pull/24 should solve all our problems, please review and re-open this issue if it does not.