From: Richard Maine on
Ragu <ssragunath(a)gmail.com> wrote:

> I am trying to code whether all non-zero values of a DIM=1 array are
> equal. My intention is to avoid writing a O(n**2) loop. I thought of
> using intrinsic's pack() and any(). However, I can't seem to get past
> the first step. I am not able to select the first element of the array
> returned by pack().

You can't subscript an expression. Ever. You can only subscript an array
variable. As for how to code what you want, well...

I'd say you are working too hard to try to force the whole thing into a
single line of code using array expressions. I'll let others try to
suggest tricks for that if they want. There's probably a way, but I
wouldn't bet on it being either efficient or easy to read. Even if
something like

> tempval = pack(array, MASK=(array/=0))(1)

would work (it won't, for the reason cited above, and as you noted),
odds are that it would do something like create the whole temporary
array and then pick the first element of it. Heck, it wouldn't be
completely implausible for it to create two temporary arrays.

Oh, and even if it would otherwise work, that method ignores an obvious
"edge condition". Always look for such conditions when coding. If you
don't make a habit of looking for them, they will bite you. Think about
what would happen if there were no non-zero elements.

The "old-fashioned" ways do still exist and are often the best. I'd
write it as (untested)

tempval = 0.
loop_1: do i = 1 , size(array)
if (array(i)/=0.) exit loop_1
end do loop_1
if (i<=size(array)) tempval = array(i)

all_the_same = all((array==0.) .or. (array==tempval))

I might even be tempted to write that last line as a loop if I was hot
for efficiency, but I'm guessing that a decent compiler has at least
half a chance of doing it without creating a temporary array. Your odds
seem much worse with PACK. (I haven't tested that; its just a
speculation). At least it reads clearly.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
From: glen herrmannsfeldt on
Richard Maine <nospam(a)see.signature> wrote:
(snip)

> The "old-fashioned" ways do still exist and are often the best. I'd
> write it as (untested)

> tempval = 0.
> loop_1: do i = 1 , size(array)
> if (array(i)/=0.) exit loop_1
> end do loop_1
> if (i<=size(array)) tempval = array(i)

I might have tried one loop, but it might be faster as two.

> all_the_same = all((array==0.) .or. (array==tempval))

> I might even be tempted to write that last line as a loop if I was hot
> for efficiency, but I'm guessing that a decent compiler has at least
> half a chance of doing it without creating a temporary array. Your odds
> seem much worse with PACK. (I haven't tested that; its just a
> speculation). At least it reads clearly.

You mean like two LOGICAL temporary arrays, and then OR together?

All these seem to require many passes through the array. How about:

logical flag
flag=.false.
do i=1,size(array)
if(flag) then
if(array(i).ne.0.and.array(i).ne.temp) ...
elseif(array(i).ne.0) then
flag=.true.
temp=array(i)
endif
enddo
if(.not.flag) ...

One pass, and the branch prediction logic might do pretty
well on it, too. If the array is small enough to fit in
cache, then it probably doesn't matter so much.

or, for extra challenge:

temp=0
do i=1,size(array)
if(array(i).ne.temp) then
if(temp.ne.0) ...
temp=array(i)
endif
enddo
if(temp.eq.0) ...

Also, both of these will stop as soon as two non-equal, non-zero
array elements are found. That could be close to the beginning
of a large array. Ones that use array intrinsics likely scan
through the whole array at least once, likely two or three times.

-- glen
From: Ragu on
Thanks Glenn and Richard. The array expression lesson is a good one
for me. Good old is still golden.