Must SHIFT argument to CSHIFT/EOSHIFT have lower bounds == 1?

When CSHIFT/EOSHIFT are called for an array with rank >= 2, their SHIFT argument is allowed to be an array, and the elements of sections of the result are defined in terms of shift counts retrieved by indexing into that SHIFT argument array.

Question: do these definitions assume that the lower bounds of the SHIFT argument array (if it be one) are all one? Are they implicitly required to be all one (in which case the standard should probably mention it) or should the definitions be changed to take LBOUND(SHIFT,d) into account?

No, there is no such restriction. The way the standard words it, the elements of the array are taken in order without regard to the lower bound.

16.9.58:

Case (ii): If ARRAY has rank greater than one,
section (s1, s2, . . . , sDIM−1, :, sDIM+1, . . . ., sn) of the result has a value
equal to CSHIFT (ARRAY (s1, s2, . . . , sDIM−1, :, sDIM+1, . . . ., sn), sh, 1),
where sh is SHIFT or SHIFT (s1, s2, . . . , sDIM−1, sDIM+1, . . . , sn).

The same subscripts s1, s2, &c. are being used to index into the result array and into the SHIFT array. That’s not going to be meaningful unless they have the same lower bounds – and the lower bounds of the result are one.

I don’t agree. s1, s2, etc. are NOT subscripts, they are “sections”, and don’t have a requirement of a LBOUND of 1.

I don’t agree. s1, s2, etc. are NOT subscripts, they are “sections”, and don’t have a requirement of a LBOUND of 1.

While the subscripts s1, s2, &c. are used to define sections of the result, source, and shift arrays, they are not each themselves “sections”; that would make no sense. They’re just scalar integers, and their interpretation as subscripts in these sections that they define are dependent on the various lower bounds of the arrays from which those sections are being isolated.

The specification of EOSHIFT is a little closer to being correct – there’s at attempt to incorporate the values of LBOUND() and UBOUND() of the various dimensions of the source array in the text that defines when that array supplies values to the result, as opposed to the boundary value(s). And that text is using the values of s1, s2, &c. as scalar integer subscripts.

It seems pretty clear that the text for CSHIFT and EOSHIFT is just neglecting to index into the SHIFT array in a way that will work if its lower bounds aren’t one (assuming that they can be so).

You are welcome to submit a request for interpretation, but I don’t think your reading is the correct one.

You are welcome to submit a request for interpretation, but I don’t think your reading is the correct one.

If that’s the case, I’d obviously just be wasting more of my time. I’ll just implement CSHIFT/EOSHIFT to allow non-unitary lower bounds on all of their arguments, and do the right thing no matter what the documents say. Thanks for the responses.

You would not be wasting your time - though Malcolm Cohen would have the first cut at an answer. You could email him and ask his opinion. I’ll agree that the answer isn’t immediately obvious - at least it wasn’t to me. I had to stare at the words for a while, but I became convinced that it is saying the right thing. There is no reference to subscripts in the definition, only shapes and sections.

Phrases like “Element (s1, s2, . . . , sn) of the result has the value …” are obviously using s1, s2, &c. as subscripts.

Is the problem of interpretation essentially the same as that used in the description of sum(), e.g. in this ifort page?

The value of element (s_1, s_2, \ldots, s_{dim-1}, s_{dim+1}, \ldots, s_n) of SUM( array, dim ) is equal to SUM( array( s_1, s_2, \ldots, s_{dim-1}, :, s_{dim+1}, \ldots, s_n) ).

(In the excerpt I have dropped the MASK part for simplicity.)

If the lower bounds of array are not all 1, the above description gives a wrong result unless s_k etc have an implicit meaning of “section” (when appearing as an array index) defined somewhere (which is not given in this page). When I read this kind of page, I always imagined the case of 1-based indexing and implicitly assumed the actual argument to be “re-indexed” to 1-based internally (though there is no such explanation in this page…)

Peter thanks for asking the question for clarification and thank you Steve for answering. We can ask at the J3 mailinglist “informally”, usually Malcolm answers such interpretation requests even if they are not formal.

1 Like

Yes, and there’s other instances as well. The case of EOSHIFT is especially interesting, since it has to use LBOUND/UBOUND to define the result and is clearly calculating subscripts. Fixing these all up would be messy but straightforward.

At this point, I don’t have any question left about whether arrays with lower bounds other than one can be used for the SHIFT= argument and others, and I know what I’m implementing will match the intent of the document, though not the letter.

(This is actually the second time I’ve implemented these transformationals in my career, the last time being almost thirty years ago; this problem in the text was in F’90 too but I don’t recall noticing.)

1 Like

As I wrote above, I find the case (ii) text for CSHIFT (EOSHIFT is similar) not obvious. I am pretty sure I understand the intent but have written to Malcolm to see if he can shed some light on it. I did write a test case based on the examples in the standard (shown below) and got the standard-specified result in both nagfor and ifort, which was reassuring.

integer :: v(7:12) = [1,2,3,4,5,6]
integer :: m(-2:0,4:6) = reshape([1,4,7,2,5,8,3,6,9],[3,3])
integer :: b(3,3)
integer :: s(7:9) = [-1,1,0]
integer :: i

print '(6I2)', cshift(v,2)

b = cshift(m,shift=s,dim=2)

do i=1,3
print '(3I2)',b(i,:)
end do
end
1 Like

I heard back from Malcolm. He correctly points out that this form of description is used in many other intrinsics - IALL/IANY are particularly relevant in having a MASK argument that is treated similarly to the SHIFT argument here.

Malcolm suggests that a note along the lines of “The result values of some functions are described using pseudo-subscripts (s_1 to s_n) of the argument array(s). These should be interpreted as if the lower bounds of the arrays were all equal to one.” might help readers understand what is being said.

“The result values of some functions are described using pseudo-subscripts (s_1 to s_n) of the argument array(s). These should be interpreted as if the lower bounds of the arrays were all equal to one.”

That won’t work for EOSHIFT, where the subscripts s1, s2, &c. need to be compared against values of LBOUND/UBOUND and really have to be in the reference frame of the array.