www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - simd comparison operator?

reply "monarch_dodra" <monarchdodra gmail.com> writes:
Are there any plans that would allow using opEqual or opCmp 
operators with simd?

My use case is that I have arrays, and I need to verify that ALL 
the elements in my array are comprised between two values (in 
this specific case 10 and 93).

I was hoping I would be able to use:
ubyte[] arr = ...
if (arr []< 10 || arr[]> 93) throw Exception();

But that doesn't seem to work.

Neither does simple opEqual comparison.
//Make sure arr is initialized to 0
if (arr[] != 0)

Is this a "never thought of this and not implemented" issue, or 
is there a reason that simd can't do this? I find it strange, 
since simd allows for straight up array to array opEquals, but 
not array to value?

--------

Anybody have any idea as a workaround? My program has very high 
data throughput, and never actually handles the array elements 
individually, just manipulates them simd chunks at once. 
Validating the content is important, but performance is taking a 
real toll...
Feb 19 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 is there a reason that simd can't do this? I find it strange, 
 since simd allows for straight up array to array opEquals, but 
 not array to value?

SIMD instructions support those operations, so it's mostly a matter of designing a good semantics for D and implementing it. Bye, bearophile
Feb 19 2013
prev sibling next sibling parent "Don" <don nospam.com> writes:
On Tuesday, 19 February 2013 at 14:03:54 UTC, monarch_dodra wrote:
 Are there any plans that would allow using opEqual or opCmp 
 operators with simd?

 My use case is that I have arrays, and I need to verify that 
 ALL the elements in my array are comprised between two values 
 (in this specific case 10 and 93).

 I was hoping I would be able to use:
 ubyte[] arr = ...
 if (arr []< 10 || arr[]> 93) throw Exception();

 But that doesn't seem to work.

 Neither does simple opEqual comparison.
 //Make sure arr is initialized to 0
 if (arr[] != 0)

 Is this a "never thought of this and not implemented" issue, or 
 is there a reason that simd can't do this? I find it strange, 
 since simd allows for straight up array to array opEquals, but 
 not array to value?

Simd comparison generally doesn't return a bool, it returns a bool array, one per element. Does (arr[] < 10) mean "is every element in arr less than 10" OR "is any element of arr less than 10" OR "create a bool array which is true for each element which is less than 10" ? All make sense. That's the problem.
Feb 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Don:

 Simd comparison generally doesn't return a bool, it returns a 
 bool array,
 one per element.

 Does  (arr[] < 10) mean "is every element in arr less than 10" 
 OR "is any element of arr less than 10" OR "create a bool array 
 which is true for each element which is less than 10" ?

 All make sense. That's the problem.

Right, it's a design problem. I think the right thing to do is to take a look at what's an efficient operation to do in hardware (and then look at what's the most commonly useful operation for users). I think the right design here is to return a bool[N]. So in this case monarch_dodra has to add some more code to test all/any. Bye, bearophile
Feb 19 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 19 February 2013 at 16:03:58 UTC, bearophile wrote:
 Don:

 Simd comparison generally doesn't return a bool, it returns a 
 bool array,
 one per element.

 Does  (arr[] < 10) mean "is every element in arr less than 10" 
 OR "is any element of arr less than 10" OR "create a bool 
 array which is true for each element which is less than 10" ?

 All make sense. That's the problem.

Right, it's a design problem. I think the right thing to do is to take a look at what's an efficient operation to do in hardware (and then look at what's the most commonly useful operation for users). I think the right design here is to return a bool[N]. So in this case monarch_dodra has to add some more code to test all/any. Bye, bearophile

There is significant opposition to any simd operators that allocate. The reasoning is that they appear fast but are in actual fact slow (for most normal size vectors, the allocation would be much slower than the calculation itself). I love the features of numpy and matlab etc. when it comes to array operations, many of which allocate implicitly, but Walter and others were quite adamant they they do not belong in D, a position I've come to agree with.
Feb 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
John Colvin:

 I think the right design here is to return a bool[N].


 There is significant opposition to any simd operators that 
 allocate. The reasoning is that they appear fast but are in 
 actual fact slow (for most normal size vectors, the allocation 
 would be much slower than the calculation itself).

 I love the features of numpy and matlab etc. when it comes to 
 array operations, many of which allocate implicitly, but Walter 
 and others were quite adamant they they do not belong in D, a 
 position I've come to agree with.

Can't D allocate that bool[N] on the stack? Bye, bearophile
Feb 19 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 19 February 2013 at 16:46:36 UTC, bearophile wrote:
 John Colvin:

 I think the right design here is to return a bool[N].


 There is significant opposition to any simd operators that 
 allocate. The reasoning is that they appear fast but are in 
 actual fact slow (for most normal size vectors, the allocation 
 would be much slower than the calculation itself).

 I love the features of numpy and matlab etc. when it comes to 
 array operations, many of which allocate implicitly, but 
 Walter and others were quite adamant they they do not belong 
 in D, a position I've come to agree with.

Can't D allocate that bool[N] on the stack? Bye, bearophile

Perhaps it could, but it would be: a) quite counter-intuitive. An operation between two normal, heap allocated arrays generating a stack allocated array, with the scoping rules that entails? b) very easy to cause stack overflow in a way that would be totally confusing to someone who wasn't aware of the implementation.
Feb 19 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
John Colvin:

 a) quite counter-intuitive. An operation between two normal, 
 heap allocated arrays generating a stack allocated array, with 
 the scoping rules that entails?

Then maybe: bool[4] res = a > b; Bye, bearophile
Feb 19 2013
prev sibling next sibling parent "tn" <no email.com> writes:
On Tuesday, 19 February 2013 at 16:28:15 UTC, John Colvin wrote:
 On Tuesday, 19 February 2013 at 16:03:58 UTC, bearophile wrote:
 Don:

 Simd comparison generally doesn't return a bool, it returns a 
 bool array,
 one per element.

 Does  (arr[] < 10) mean "is every element in arr less than 
 10" OR "is any element of arr less than 10" OR "create a bool 
 array which is true for each element which is less than 10" ?

 All make sense. That's the problem.

Right, it's a design problem. I think the right thing to do is to take a look at what's an efficient operation to do in hardware (and then look at what's the most commonly useful operation for users). I think the right design here is to return a bool[N]. So in this case monarch_dodra has to add some more code to test all/any. Bye, bearophile

There is significant opposition to any simd operators that allocate. The reasoning is that they appear fast but are in actual fact slow (for most normal size vectors, the allocation would be much slower than the calculation itself). I love the features of numpy and matlab etc. when it comes to array operations, many of which allocate implicitly, but Walter and others were quite adamant they they do not belong in D, a position I've come to agree with.

In many cases it would be nice, if "arr[] < x" translated to "map!(a => a < x)(arr)" and similarly "arr1[] < arr2[]" translated to "map!((a, b) => a < b)(arr1, arr2)" or equivalent (*). Then for example, if "all" and "any" had "a => a" as a default predicate, it would be possible to write for example "if (any(arr[] < 10)) ...". As far as I understand, this does not allocate. (*) Also, it would be nice if "map!((a, b) => a < b)(arr1, arr2)" was a valid syntax. (Or if it is, then it should be documented.)
Feb 19 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Tuesday, 19 February 2013 at 17:46:56 UTC, bearophile wrote:
 John Colvin:

 a) quite counter-intuitive. An operation between two normal, 
 heap allocated arrays generating a stack allocated array, with 
 the scoping rules that entails?

Then maybe: bool[4] res = a > b; Bye, bearophile

Yes, but it's quite restrictive to force it to be declared at the same place as it's assigned, if that's what you're implying. Essentially what's needed in order to allow all this and other simd operations that don't work in-place on the main operands is a guarantee that the memory has been pre-allocated. Then it really doesn't matter whether it's stack or heap.
Feb 19 2013
prev sibling next sibling parent "jerro" <a a.com> writes:
 Anybody have any idea as a workaround? My program has very high 
 data throughput, and never actually handles the array elements 
 individually, just manipulates them simd chunks at once. 
 Validating the content is important, but performance is taking 
 a real toll...

One possible workaround is to use simd operation eplicitly. I've played around a bit with this and came up with this: https://gist.github.com/jerro/4988229 This currently only works with GDC and LDC (but it probably could be made to work with DMD too). It uses std.simd (not in phobos yet) from here: https://github.com/TurkeyMan/phobos
Feb 19 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 19 February 2013 at 17:58:14 UTC, John Colvin wrote:
 On Tuesday, 19 February 2013 at 17:46:56 UTC, bearophile wrote:
 John Colvin:

 a) quite counter-intuitive. An operation between two normal, 
 heap allocated arrays generating a stack allocated array, 
 with the scoping rules that entails?

Then maybe: bool[4] res = a > b; Bye, bearophile

Yes, but it's quite restrictive to force it to be declared at the same place as it's assigned, if that's what you're implying. Essentially what's needed in order to allow all this and other simd operations that don't work in-place on the main operands is a guarantee that the memory has been pre-allocated. Then it really doesn't matter whether it's stack or heap.

Hum... so long story short, it is doable, but because the result of "[]<" is ambiguous, it is not built into the language. Gonna play around with core.simd then!
Feb 19 2013
prev sibling next sibling parent "jerro" <a a.com> writes:
 One possible workaround is to use simd operation eplicitly. 
 I've played around a bit with this and came up with this:

 https://gist.github.com/jerro/4988229

 This currently only works with GDC and LDC (but it probably 
 could be made to work with DMD too).

I've update the gist now so that it works with DMD too. To use it with DMD, you'll need this branch from my fork of std.simd: https://github.com/jerro/phobos/tree/simd-wip
Feb 19 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Tue, 19 Feb 2013 18:51:35 +0100
schrieb "tn" <no email.com>:

 In many cases it would be nice, if "arr[] < x" translated to 
 "map!(a => a < x)(arr)" and similarly "arr1[] < arr2[]" 
 translated to "map!((a, b) => a < b)(arr1, arr2)" or equivalent 
 (*).

This would make the compiler depend on std.algorithm ! -- Marco
Feb 22 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--e89a8fb1ebce6cdd2604d704e988
Content-Type: text/plain; charset=UTF-8

On 20 February 2013 02:03, bearophile <bearophileHUGS lycos.com> wrote:

 Don:

 Simd comparison generally doesn't return a bool, it returns a bool array,
 one per element.

 Does  (arr[] < 10) mean "is every element in arr less than 10" OR "is any
 element of arr less than 10" OR "create a bool array which is true for each
 element which is less than 10" ?

 All make sense. That's the problem.

Right, it's a design problem. I think the right thing to do is to take a look at what's an efficient operation to do in hardware (and then look at what's the most commonly useful operation for users). I think the right design here is to return a bool[N]. So in this case monarch_dodra has to add some more code to test all/any. Bye, bearophile

Don is on the money. I drafted: bool allEqual(a,b)/anyEqual(a,b) and friends in std.simd, but I haven't written them yet (been awol for a while). They're actually quite tricky to get right+fast in a portable way. all/any comparisons are often used in a boolean way, but they may not be super fast on some architectures. If you want to do component-wise logic, the typical approach is to use component-wise selection, eg: uint4 mask = compareGreater(a, b); // <- build a bit mask of 0's (false) or 1's (true) where components of a are greater than b. auto result = select(mask, c, d); // <- select components from c or d according to the bit mask. --e89a8fb1ebce6cdd2604d704e988 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 20 February 2013 02:03, bearophile <span dir=3D"ltr">&l= t;<a href=3D"mailto:bearophileHUGS lycos.com" target=3D"_blank">bearophileH= UGS lycos.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div clas= s=3D"gmail_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex">Don:<div> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> Simd comparison generally doesn&#39;t return a bool, it returns a bool arra= y,<br> one per element.<br> <br> Does =C2=A0(arr[] &lt; 10) mean &quot;is every element in arr less than 10&= quot; OR &quot;is any element of arr less than 10&quot; OR &quot;create a b= ool array which is true for each element which is less than 10&quot; ?<br> <br> All make sense. That&#39;s the problem.<br> </blockquote> <br></div> Right, it&#39;s a design problem.<br> I think the right thing to do is to take a look at what&#39;s an efficient = operation to do in hardware (and then look at what&#39;s the most commonly = useful operation for users). I think the right design here is to return a b= ool[N].<br> So in this case monarch_dodra has to add some more code to test all/any.<br=

Bye,<br> bearophile<br> </blockquote></div><br></div><div class=3D"gmail_extra">Don is on the money= .</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">I dr= afted: bool allEqual(a,b)/anyEqual(a,b) and friends in std.simd, but I have= n&#39;t written them yet (been awol for a while). They&#39;re actually quit= e tricky to get right+fast in a portable way.</div> <div class=3D"gmail_extra"><br></div> <div class=3D"gmail_extra">all/any comparisons are often used in a boolean = way, but they may not be super fast on some architectures. If you want to d= o component-wise logic, the typical approach is to use component-wise selec= tion, eg:</div> <div class=3D"gmail_extra">=C2=A0 uint4 mask =3D compareGreater(a, b); // &= lt;- build a bit mask of 0&#39;s (false) or 1&#39;s (true) where components= of a are greater than b.</div><div class=3D"gmail_extra">=C2=A0 auto resul= t =3D select(mask, c, d); // &lt;- select components from c or d according = to the bit mask.</div> </div> --e89a8fb1ebce6cdd2604d704e988--
Mar 03 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Manu:

 If you want to do component-wise logic,
 the typical approach is to use component-wise selection, eg:
   uint4 mask = compareGreater(a, b); // <- build a bit mask of 
 0's (false)

Isn't something like this better? uint4 mask = a > b; Bye, bearophile
Mar 03 2013
prev sibling parent Manu <turkeyman gmail.com> writes:
--e89a8ff1c30e7119ed04d70590de
Content-Type: text/plain; charset=UTF-8

I don't think opCmp can fit that model?

But aside from that, I think that's misleading, and suggests to the user
that it's a trivial operation.
Additionally, it's not necessarily even possible in a portable way.

I also think most users would expect that comparison operators produce a
boolean result.
They'll be surprised when: if(a > b) produces an error.


On 3 March 2013 23:39, bearophile <bearophileHUGS lycos.com> wrote:

 Manu:


  If you want to do component-wise logic,
 the typical approach is to use component-wise selection, eg:
   uint4 mask = compareGreater(a, b); // <- build a bit mask of 0's (false)

Isn't something like this better? uint4 mask = a > b; Bye, bearophile

--e89a8ff1c30e7119ed04d70590de Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div style>I don&#39;t think opCmp can fit that model?</di= v><div><br></div>But aside from that, I think that&#39;s misleading, and su= ggests to the user that it&#39;s a trivial operation.<div>Additionally, it&= #39;s not necessarily even possible in a portable way.</div> <div><br></div><div style>I also think most users would expect that compari= son operators produce a boolean result.</div><div style>They&#39;ll be surp= rised when: if(a &gt; b) produces an error.</div></div><div class=3D"gmail_= extra"> <br><br><div class=3D"gmail_quote">On 3 March 2013 23:39, bearophile <span = dir=3D"ltr">&lt;<a href=3D"mailto:bearophileHUGS lycos.com" target=3D"_blan= k">bearophileHUGS lycos.com</a>&gt;</span> wrote:<br><blockquote class=3D"g= mail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-l= eft:1ex"> Manu:<div class=3D"im"><br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> If you want to do component-wise logic,<br> the typical approach is to use component-wise selection, eg:<br> =C2=A0 uint4 mask =3D compareGreater(a, b); // &lt;- build a bit mask of 0&= #39;s (false)<br> </blockquote> <br></div> Isn&#39;t something like this better?<br> <br> uint4 mask =3D a &gt; b;<br> <br> Bye,<br> bearophile<br> </blockquote></div><br></div> --e89a8ff1c30e7119ed04d70590de--
Mar 03 2013