[J3] New intrinsic XXX_PREFIX and XXX_SUFFIX procedures

Brad Richardson everythingfunctional at protonmail.com
Fri Jan 13 22:26:11 UTC 2023


Hi all,

First, thank you all for your comments and suggestions. They have
revealed some aspects that I had not initially considered. I would like
to try and address some of the various comments.

The most common suggestion has amounted to something like, "Why not
just do exactly what HPF did?"

Looking at what HPF did has been very valuable as a reference. I can
certainly understand vendors wanting to be able to reuse existing work,
but I want to still explore whether HPF necessarily did it perfectly,
or whether we could potentially do better now. If the way we choose to
do it now is slightly different than HPF, it doesn't mean that prior
work is not reusable, just that it may require some modification.

HPF provided the combinatorial set of operations with {PRE,SUF}FIX
specific procedures, with optional argument to determine inclusive or
exclusive. With the recent sentiments expressed that all new features
should have compelling use cases, there is much more burden to
justifying each one individually. By providing a generic procedure that
is applicable for all operations, only a few use cases are needed to
justify it, including use cases not covered by the operation specific
versions.

It has been suggested that the operation specific versions mean that
the code can be type checked, but the compiler absolutely could type
check the generic version. It is required the ARRAY and OPERATION have
the same types, which the compiler can see at the call site and
enforce. This is just like the generic REDUCE function. I will note
that this does mean COUNT_{PRE,SUF}FIX is not possible with the generic
version. A slight change to the description and arguments could re-
enable it though. I.e.

PURE FUNCTION OPERATION(x, y) RESULT(res)
  TYPE(<type_of_identity_argument>), INTENT(in) :: x
  TYPE(<type_of_array_argument>), INTENT(in) :: y
  TYPE(<type_of_identity_argument>) :: res
END FUNCTION

and make IDENTITY a required argument.

HPF provided {PRE/SUF}FIX functions, with an optional argument to do
inclusive vs exclusive. It would be reasonable to do the opposite
arrangement, have {IN/EX}CLUSIVE functions with an optional argument to
do forward vs backward iteration. Or even just single functions with
optional arguments for both, or individual functions for each. Each
option has certain advantages and disadvantages that should be
considered.

HPF defined that the result of a {PRE/SUF}FIX function has the same
shape as the array argument, regardless of the presence of a MASK
argument, and that elements of the result for which no elements of the
input contribute there is a "default" value with which that element is
defined. This works for the HPF functions because all the specified
operations either have a meaningful "default" value, or in the case of
COPY, don't allow a mask or exclusive argument (i.e. no chance of zero
elements contributing). This is not necessarily possible in the generic
case. The generic REDUCE function overcomes this with an IDENTITY
argument. My initial thought though was that the behavior would be more
like SUM_PREFIX(ARRAY, MASK) == SUM_PREFIX(PACK(ARRAY, MASK)). I'm not
sure I know enough about various use cases to decide which is more
appropriate. I'm open to suggestions here. I'll just note that I
believe most other intrinsics with a MASK argument do follow this
pattern (or a similar pattern with loops over dimensions other than
DIM). For example

res => MINLOC(ARRAY, MASK)
res(s1, ..., sdim-1, :, sdim+1, ..., sn) == MINLOC(PACK(ARRAY(s1, ...,
sdim-1, :, sdim+1, ..., sn), MASK(s1, ..., sdim-1, :, sdim+1, ...,
sn)))

HPF treated the SEGMENT argument as adjacent elements with .EQV.
corresponding elements in MASK being members of the same segment. I.e.
SUM_PREFIX([1, 2, 3, 4, 5], MASK=[.true., .true., .false., .true.,
.true.]) == [1, 3, 3, 4, 9]. However, many implementations in other
languages treat .true. values in the SEGMENT argument as signifying the
first element in a SEGMENT. I.e. SUM_PREFIX([1, 2, 3, 4, 5],
MASK=[.true., .false., .true., .true., .false.]) == [1, 3, 3, 4, 9]. Is
it better to be consistent with HPF or with other languages?

HPF did not provide collective subroutine versions for any of these
operations. Depending on the chose design, what operations should we
provide collective subroutines for?

For all of these various dimensions for the possible design of this
feature I of course have opinions, but I'm open to any considerations I
may not have thought of. Overall my "values" for the design would be,
in order:

* Is easy for users to understand and use correctly
* Allows for efficient implementations by vendors
* Doesn't add too much to the standard

I'm also open to the idea of starting with a restricted subset of the
above discussed functionality such that we can avoid having to settle
on certain aspects of the design initially.

Looking forward to hearing more ideas.

Regards,
Brad



More information about the J3 mailing list