CVS difference for ai12s/ai12-0262-1.txt

Differences between 1.5 and version 1.6
Log of other versions for file ai12s/ai12-0262-1.txt

--- ai12s/ai12-0262-1.txt	2018/11/13 05:47:40	1.5
+++ ai12s/ai12-0262-1.txt	2019/01/11 05:59:53	1.6
@@ -1,220 +1,408 @@
-!standard 5.5.2(2/3)                                  18-10-18  AI12-0262-1/03
-!standard 5.5.2(5/4)
-!standard 5.5.2(7/3)
+!standard 4.1.4(1)                                    19-01-10  AI12-0262-1/04
+!standard 4.1.4(11)
+!standard 4.5.9(0)
 !class Amendment 18-03-01
 !status work item 18-03-01
 !status received 18-03-01
 !priority Medium
 !difficulty Hard
-!subject Map/Reduce attribute
+!subject Map-Reduce attribute
 !summary
 
-The capabilities of Reduction Expressions are expanded to allow the
-programmer to stream values into the reduction by writing the attribute
-reference with a new syntactic construct called a value_generator, which is very
-similar to an iterated_component_association, except instead of associating
-values to components of an array, the values are streamed into the reduction.
+Reduction Expressions are defined to allow the programmer to apply the
+Map-Reduce paradigm to map/transform a set of values to a new set of values,
+and then summarize/reduce the transformed values into a single result value.
 
 !problem
 
-This proposal depends on the facilities for aspect Global (AI12-0079-1) and for
-aspect Nonblocking (AI12-0064-2). Those proposals allow the compiler to
-statically determine where parallelism may be introduced without introducing
-data races. This proposal also depend on parallel iteration support for
-containers (AI12-0266-1), and reduction expressions (AI12-0242-1)
-
-AI12-0242-1 defines a reduction operation for existing objects. However,
-in cases where there is no existing type that matches the objects to reduce,
-this is less than convenient. Moreover, if the stream of objects to reduce
-is indefinite, it isn't possible in Ada to declare an array type that matches
-it. One could instantiate an indefinite container, but that would have to be
-materialized (since it is made up of calls to user-defined operations).
+A common problem in computing is the Map-Reduce paradigm where a set of
+values possibly needs to be mapped or transformed to another set of values
+and the new values then need to be summarized or reduced to produce a single
+final result.
+
+Currently in Ada, one generally has to write a subprogram to do this, which
+involves writing a loop to iterate through the set of values, and a global
+accumulator variable or set of variables that get updates through each iteration
+of the loop.
 
 What is needed is a way to directly process a stream of objects without
 declaring a type and without forcing the materialization of an object.
 
+To further illustrate the need, one of the most important additions to Ada 2012
+is contract specifications for subprograms. However to write pre and post
+conditions that attempt to summarize inputs or outputs, one has
+to write a subprogram to express the summary result, which can add clutter to
+an API for an abstraction and injects a level of indirection. If a client
+then wants to understand the requirements of the pre condition or the effects
+of the post condition, one has to find and examine the body of the subprogram
+named in the contract specification.
+
+It would be useful if such summarizations could be expressed in a simpler, more
+concise and localized manner, such as an expression, without always having to
+write another subprogram.
+
+Ada 83 was already a pretty good language for "hybrid" functional/imperative
+programming, because you can have a sequence of declarations that progressively
+compute a desired result.  Often it was only because you needed to enter a loop
+that you had to do any significant amount of computing after the "begin".  In
+today's Ada, with conditional expressions, quantified expressions, the recently
+approved iterated component association, and our newly proposed container
+aggregates, the need for explicit ifs and loops after the "begin" is continuing
+to decrease. There appears to be a shift in the a balance between functional
+and imperative features, more towards the functional side.  There is a
+resurgence of interest in functional programming these days, but going all the
+way to "pure functional" programming, with "monads" instead of assignment
+statements, and recursion only with no iteration, would be too going too far
+towards the functional side. Nonetheless, it is important to "complete" the
+functional primitives, if only to give the desired power to Ada's contract-based
+programming.
+
+Some of the existing syntax in Ada already can provide forms of summarization.
+For example, a quantified expression can be viewed as being a special purpose
+Reduction Expression that applies an operation, the Predicate, to a set of
+values to reduce the predicate results to a single Boolean result. Similarly, an
+array aggregate in the form of an iterated_component_association can also be
+viewed as being a special purpose Reduction Expression that applies an
+operation, in-place concatenation, to a set of values to reduce into an array
+result. What is needed is a more general syntactic form where there is
+less constraint on the type of operation to be applied to summarize the set of
+values, and the operation can produce result values of types other than
+Boolean values, or array objects.
+
+Such a reduction capability is the last remaining major component needed to
+complete the "iterated" operations. There are many applications of reduction
+capabilities, that apply to both sequential and parallelism use cases.  It will often be
+the right way to define, in a postcondition, the final value of one
+output of the subprogram, even though the subprogram might have multiple outputs
+and might do many other things.
+
+Such a capability can allow programmers to express algorithms more concisely,
+which tends to also make the algorithms easier to read, debug, understand, and
+maintain.
+
+Another need is to be able to perform reductions in parallel. Modern computing
+platforms typically provide support for multicore computing, yet it can be
+considerably difficult to write algorithms that take advantage of these
+multicore platforms. Such algorithms tend to be very error prone, and are
+difficult to debug. Many of the divide and conquer algorithms involve reduction,
+commonly known as Map-Reduce, in the parallelism world.
+
+The challenge with such algorithms when looping constructs are employed, is that
+a global accumulator value is typically needed, which normally would imply a data
+race if multiple threads of execution end up updating the global variable in
+parallel.
+
+Parallel reduction is in many ways a separate issue, when compared to sequential
+reduction, and where (and whether) it is best inserted depends heavily on the
+amount of computing done within a single iteration, the independence of those
+computations, and the number of iterations.  The advantage of the notations like
+quantified expressions, and container aggregates, is that they are self-contained,
+and can often be analyzed holistically by the compiler to determine whether and
+where to insert parallelism.
+
+It is important to also allow the programmer to indicate explicitly whether
+parallelism should be applied, as it documents to the reader that performance
+is important to the user, and makes it clear that parallel execution is likely
+to be worthwhile.
+
+For instance, a compiler might choose to conservatively apply parallelism,
+only in cases where it can statically determine that the performance would
+be guaranteed to benefit from the parallelism. A programmer might want to
+override the conservatism of the compiler and experiment with parallelism to
+measure the benefits, and then deploy the code in the form that provided the
+optimal performance.
+
 !proposal
+
+This proposal depends on parallel iteration support for
+containers (AI12-0266-1) and support for container aggregates (AI12-0212-1).
 
-The proposal is to define a new syntactic construct called a value_generator,
-that is very similar to an iterated_component_association and allow that
-to be specified as the left hand side of the attribute reference for
-a reduction expression. The basic idea is that during the evaluation
-of the value_generator, as each value is produced during evaluation of the
-value_generator, it is reduced into the result. Thus there is no need to create
-storage to hold all the values prior to the reduction.
-If the parallel keyword is present in the prefix, then the
+The goals of this proposal are to provide a mechanism for expressing a
+summarization of a set of values. Such a summarization is known as a reduction.
+It is desired that such a mechanism;
+
+- is easy to understand
+- is easy to write/express
+- allows parallelization
+- provides safety by eliminating data races and logic errors.
+- fits in well with existing Ada syntax
+
+The proposal defines a new type of attribute reference called a
+reduction expression that allows a special form of iterated_component_association
+called a value_sequence to be specified as the left hand side of the "'", and where
+the attribute designator, Reduce, defines a reduction specification that indicates
+how the reduction is to be applied. The basic idea is that during the evaluation
+of the value_sequence, as each value is produced, it is reduced into
+the result by calling a reducer subprogram that is named by the reduction
+specification. Thus there is no need to create storage to hold all the values
+generated by the value_sequence prior to the reduction, since they are
+streamed into the result as they are produced.
+
+A reducer subprogram is a subprogram that combines two input values into
+a single result value.
+
+Another part of the reduction specification is the Initial_Value, which
+is a value of the result type of the reduction_attribute_reference. This
+value is used to initialize the result of the reduction expression prior
+to the iteration of the value_sequence. It also serves as the result value
+when the value_sequence does not produce any values.
+
+If the parallel keyword is specified on the value sequence, then the
 reduction expression is a parallel construct and the iteration is
-divided among multiple logical threads of control as appropriate for
-array or container iteration depending on the iterator of the value_generator.
-In the parent AI, AI12-0242-1, two attributes are needed
-because there is otherwise no way for the programmer to explicity specify
-whether parallelism should be applied for an array or container object.
-For this AI, the parallel keyword can be specified in the value_generator,
-so only one attribute is needed. Reduce is chosen as the Identifier of the
-attribute designator.
-
-To be more consistent with the Reduce attribute for a reduction expression with
-a value_generator, we relax the rules to allow a combiner subprogram to be
-specified if the Reduce attribute has a prefix. In this case, the
-combiner_subprogram is not expected to be called, since only one logical thread
-of control is presumed. It does make it easier for the programmer to switch back
-and forth between sequential and parallel execution by simply removing or adding
-the parallel keyword if the prefix is an iterated_component_association or
-iterated_element_association.
+divided among multiple logical threads of control. In this case, another
+subprogram may be specified as part of the reduction specification, called the
+combiner_subprogram, to combine the final results of the multiple logical
+threads of control. This may be necessary, if different parameter types are
+needed than specified in the profile of the reducer subprogram.
+
+If the parallel keyword is not specified, then the combiner subprogram
+need not be specified, and likely will not be called even
+if specified, since only one logical thread of control is presumed, and
+so there is no need to combine multiple results.
 
 !wording
 
+Modify 4.1.4(1):
+
+An attribute is a characteristic of an entity that can be queried via an
+attribute_reference [or]{,} a range_attribute_reference{, or a
+reduction_attribute_reference (see 4.5.9)}.
 
-attribute_reference ::= prefix'attribute_designator {| [value_generator]'attribute_designator}
 
-[Editor's note: literal [] around value_generator.]
+Modify AARM 4.1.4(9.b/3):
+Discussion: The nominal subtype is primarily a concern when an
+attribute_reference, {reduction_attribute_reference,} or a call on an
+attribute_reference, is used as the expression of a case statement, due to the
+full coverage requirement based on the nominal subtype. For nondiscrete cases,
+we define the nominal subtype mainly for completeness. Implementations may
+specify otherwise for implementation-defined attribute functions.
 
-Modify 4.1.4(11)
 
-The evaluation of an attribute_reference (or range_attribute_reference)
-consists of the evaluation of the prefix {or value_generator (see 4.5.9)}.
+Modify 4.1.4(11):
 
-Modify 4.5.9 (1)
+The evaluation of an attribute_reference {,}[(or] range_attribute_reference[)]
+{, or reduction_attribute_reference} consists of the evaluation of the prefix
+{or value_sequence (see 4.5.9)}.
 
-A Reduction expression provides a way to write a value that denotes a
-combination of the component values of an array or of the
-element values stored in an /iterable container object/ (see 5.5.1)
-{or the values assigned to loop parameters during the evaluation of a
-value_generator}.
+New Section 4.5.9
 
+4.5.9 Reduction Expressions
+
+Reduction expressions provides a way to map or transform a collection of
+values into a new set of values, and then summarize the values produced by
+applying an operation to reduce the set to a single value result.
+
 Syntax
+
+reduction_expression ::= reduction_attribute_reference
 
-Add just after Syntax in 4.5.9
+reduction_attribute_reference ::= value_sequence'reduction_attribute_designator
 
-value_generator ::=
-    [parallel] for defining_identifier in discrete_choice_list => expression
-  | [parallel] for iterator_specification => expression
+value_sequence ::= [ [parallel] iterated_component_association ]
 
-Modify definition of Reduction Expression in 4.5.9 Syntax
+reduction_attribute_designator ::= identifier(reduction_specification)
 
-A /Reduction Expression/ is an attribute reference where the identifier
-of the attribute_designator is Reduce or Parallel_Reduce and the [expression
-of the] attribute_designator [is]{has} a reduction_specification.
+reduction_specification ::= /reducer_/name, /initial_value_/expression[, /combiner_/name]
 
+
 Name Resolution Rules
 
-Modify 4.5.9 (?)
+The expected type for a reduction_attribute_reference shall be a single
+nonlimited type.
 
-For a subtype S [of a component of an array type A or element of an
-iterable container object C and a corresponding object O of the
-array or iterable container object, which is denoted
-by the prefix of a reduction_expression]:
+Given nonlimited subtypes I and R, where R is a subtype of the expected type:
 
-Add after Name Resolution Rules for reduction_specification
+A /reducer_/subprogram is either subtype conformant with the following
+specification:
 
-The defining_identifier of a value_generator declares one or more
-instances of a /loop parameter/ where the nominal subtype of each loop
-parameter is a subtype that shall statically matches S.
+   function Reducer(Accumulator : R; Value : I) return R;
 
-The loop parameters of the iterator_specification of a value_generator
-shall statically match S.
+or is subtype conformant with the following specification:
 
-Legality Rules
+   procedure Reducer(Accumulator : in out R; Value : I);
+
+A /combiner_/subprogram is a /reducer_/subprogram where subtypes I and R
+statically match.
+
+The reducer_name of a reduction_specification denotes a reducer_subprogram.
+
+The combiner_name of a reduction_specification denotes a combiner_subprogram.
+
+The expected type of an initial_value_expression of a reduction_specification
+is that of subtype R.
+
+The expected type of the expression of a value_sequence is that of
+subtype I.
 
-Modify 4.5.9 (?)
+The expected type of the index parameter of a value_sequence is that of the
+discrete_choice. Otherwise the expected type of the loop parameter of a
+value_sequence is as defined for an iterator_specification (See 5.5.2).
 
-For a reduction_expression where the {identifier of the attribute_designator}
-[attribute_reference] is Reduce, [there shall not be a combiner_name specified]
-{the combiner_name shall be specified if subtype S and subtype R do not
-statically match and the attribute reference has a value_generator with the
-parallel keyword.}
-
-Modify 4.5.9 (?)
-
-For a reduction_expression where the {identifier of the attribute_designator}
-[attribute_reference] is Parallel_Reduce,
-{the attribute reference shall have a prefix and}
-the combiner_name shall be specified if subtype S and subtype R do not
-statically match. {The prefix of the attribute shall denote either an
-object of an array type or an /iterated container object/.}
+The expected type for a value_sequence shall be a single one-dimensional array
+type. The component type of this array type is the expected type of the index
+parameter or loop parameter for the value_sequence.
 
-Modify 4.5.9 (?)
 
+Legality Rules
+
+[For a reduction_attribute_reference for a value_sequence with the parallel
+keyword, the Nonblocking aspect of the /reducer_/subprogram shall be statically
+True, and the Global aspect of the /reducer_/subprogram shall be statically
+null.]
+
+ [Author's note: Randy says this rule is unnecessary, as it is covered by
+  parallel constructs in AI12-0267-01, is it worth keeping here?]
+
+The combiner_name of a reduction_specification shall be specified
+if the subtypes of the parameters of the /reducer_/subprogram denoted by the
+reduction_specification do not statically match each other and the
+reduction_attribute reference has a value_sequence with the reserved work
+parallel.
+
+The discrete_choice_list of a value_sequence shall have a single discrete_choice
+and the discrete_choice shall not be the reservered word others.
+
+The discrete_choice_list of a value_sequence is allowed to have a discrete_choice
+that is a nonstatic choice_expression or that is a subtype_indication or
+range that defines a nonstatic or null range.
+
 AARM Note
+
+For a reduction_attribute_reference with a value_sequence that does not
+have the parallel keyword, the combiner_name of the reduction_specification
+is optional because only one logical thread of control is presumed so there
+is no need to provide a way to combine multiple results.
 
-The combiner_name is [always] optional [for] {when the identifier of the
-attribute_designator is} [having an] Reduce {if the attribute reference has a
-value_generator without the parallel keyword or if the attribute reference has a
-prefix}, because only one logical thread of control is presumed so there is no
-need to provide a way to combine multiple results.
 
 Static Semantics
 
-Modify 4.5.9 (?)
+The nominal subtype of the index parameter of a value_sequence
+is that of the discrete_choice. Otherwise the nominal subtype of the
+loop parameter of a value_sequence is as defined for an iterator_specification
+(See 5.5.2).
+
+A reduction_attribute_reference denotes a value, with nominal subtype
+being the subtype of the first parameter of the reducer subprogram.
+
+For a reduction_attribute_reference that has a value_sequence with the
+reserved word parallel, if the combiner_name is not specified, then the
+subprogram denoted by the reducer_subprogram also implicitly denotes the
+combiner_subprogram.
+
+AARM Note:
+For a reduction_attribute_reference that has a value_sequence without the
+parallel keyword, if the combiner_name is not specified, then sequential
+execution is presumed if the subtypes of the parameters of the
+reducer_subprogram denoted by the reduction_specification do not statically
+match, since there is no subprogram identified in the construct that could be
+used for combining the results in parallel.
+
+AARM Ramification: If the subtypes of the parameters of reducer_subprogram
+do statically match, then sequential execution is presumed but the determination
+of whether to apply parallel execution is made by the compiler, dependent on
+the usual guarantees for delivering results that are equivalent to that which
+would be produced by sequential execution.
 
-For a reduction_expression where the attribute_designator is Parallel_Reduce,
-{or if the attribute_reference has a value_generator with the
-parallel keyword, }
-if the combiner_name is not specified[,] then the subprogram denoted by
-the reducer_subprogram also implicitly denotes the combiner_subprogram.
 
 Dynamic Semantics
 
-Add after 4.5.9 (?)
+For a reduction_attribute_reference, the value_sequence is first evaluated.
+For a value_sequence with or without the reserved word parallel, the evaluation
+of a value_sequence is as defined for an array aggregate (See 4.3.3).
+The reduction_attribute_designator is then evaluated.
+
+AARM Note:
+The presence of the parallel keyword does not effect the evaluation of
+the value_sequence. Conceptually, an array aggregate is produced, as though
+the parallel keyword were not present.
+
+AARM Suggested Implementation
+The intended implementation model is that a value_sequence generally avoids
+producing a temporary array aggregate object, and instead issue calls to
+the Reducer as values are produced by the evaluation of the value_sequence.
 
-The following attribute is defined for a value_generator V
+The following attribute is defined for a value_sequence V
 
 V'Reduce(Reducer, Initial_Value[, Combiner])
 
-   V'Reduce is a reduction expression that initializes the result of the
-   expression to the Initial_Value, and then evaluates the value_generator of
-   the attribute. If the value_generator does not have the parallel keyword,
-   then as each value of the value_generatr is produced, a call is made to the
-   Reducer passing the value as the second (Value) parameter to the call, and
-   using the result of the previous iteration as the first (Accumulator)
-   parameter. Yields the final result of the iteration.
-
-   If the value_generator of the attribute does have the parallel key word, then
-   the reduction expression is a parallel construct and the iterations are
-   divided among multiple logical threads of control. Each logical thread of
-   control generates a local copy of the result of its iteration, which is
-   initialized to the value of the loop parameter or loop cursor associated with
-   the first assigned iteration. As each value of the value_generator is
-   produced, a call is made to the Reducer passing the value as the second
-   (Value) parameter to the call, and using the result of the previous iteration
-   as the first (Accumulator) parameter. As each logical thread of control
+   V'Reduce evaluates the Initial_Value,
+   then initializes the result of the reduction expression to the value
+   of the Initial_Value expression. If the value_sequence does not have
+   the reserved word parallel, the value of each component of the array
+   aggregate produced by the value_sequence is passed in ascending order as the
+   second (Value) parameter to execute a call to Reducer, using the result of
+   the previous iteration as the first (Accumulator) parameter of the call.
+   Yields the final result of the iteration. If the reserved word parallel is
+   present in a value_sequence (a parallel reduction), then the reduction
+   expression is a parallel construct and the iterations are partitioned into
+   one or more chunks, each with its own separate logical thread of control (see
+   clause 9).  Each logical thread of control generates a local copy of the
+   result of its iteration, which is initialized to the value of the expression
+   produced by the first assigned iteration. As each logical thread of control
    completes its assigned iterations, the Combiner is called using the value of
-   the local result as the second (Value) parameter of the call,  and using the
+   the local result as the second (Value) parameter of the call, and using the
    previous final result value, as the the first (Accumulator) parameter for the
    call. Once all logical threads of control have completed, yields the result
-   of the last call to Combiner. The calls to Combiner are issued sequentially
-   in increasing iteration order. The Combiner may be omitted if the Reducer is
+   of the last call to Combiner. The calls to Combiner are executed in
+   increasing iteration order. The Combiner may be omitted if the Reducer is
    also a combiner_subprogram. In that case, the Reducer is implicitly used also
    as the Combiner argument.
 
-   V'Reduce yields the Initial_Value if the prefix of the attribute reference
-   denotes a null range of values.
+[**allow a tree evaluation??** - Tucker's comment, which the author does not understand]
 
-Add to 4.5.9 examples
+   V'Reduce yields the value of the Initial_Value expression if the
+   value_sequence of the reduction_attribute reference produces an empty
+   sequence.
+
+NOTES
+
+The Initial_Value of a reduction expression is only evaluated once.
+
+The /reducer_/subprogram and the /combiner_/subprogram /potentially conflict/
+with other actions.
+
+AARM Note:
+
+We say the calls to Combiner are sequentially ordered in increasing order
+because certain reductions, such as vector concatentation,
+can be non-commutative operations. In order to return a
+deterministic result for parallel execution that is consistent with
+sequential execution, we need to specify an order
+for the iteration, and for the combination of results from the logical
+threads of control.
+
+For the parallel version of 'Reduce, calls to Combiner are executed in
+increasing iteration order to provide determinism and results that are
+consistent with sequential execution. This can be important for certain
+reduction operations that are non-commutative, such as concatentation.
+This also implies that calls to Combiner are issued sequentially with
+respect to each other, which may require extra synchronization if
+the calls to Combiner are being executed by different logical threads of
+control.
 
 Examples
 
-  Determine how many integers in an array are prime numbers
+  --  Determine how many integers in an array are prime numbers
 
   Prime_Count : constant Natural := [for P of A when Is_Prime(P) => 1]'Reduce("+",0);
 
-  An expression function that returns its result as a Reduction Expression
+  --  An expression function that returns its result as a Reduction Expression
 
   function Factorial(N : Natural) return Natural is
      ([for J in 1..N => J]'Reduce("*", 1));
 
-  An expression function that computes the Sin of X using Taylor expansion
+  --  An expression function that computes the Sin of X using Taylor expansion
 
   function Sin(X : Float; Num_Terms : Positive := 5) return Float is
-     ([for I in 1..Num_Terms => (-1.0)**I * X**(2*I-1)/Float(Fact(2*I-1))]
+     ([for I in 1..Num_Terms => (-1.0)**(I-1) * X**(2*I-1)/Float(Fact(2*I-1))]
         'Reduce("+", 0.0));
 
-   A reduction expression that outputs the sum of squares
+   --  A reduction expression that outputs the sum of squares
 
    Put_Line ("Sum of Squares is" &
              Integer'Image([for I in 1 .. 10 => I**2]'Reduce("+", 0));
 
-   An expression function to compute the value of Pi
+   --  An expression function to compute the value of Pi
 
    --  See 3.5.7(21)
    function Pi (Number_Of_Steps : Natural := 10_000) return Real is
@@ -281,6 +469,105 @@
 expression. The initial value plays an important role, since the Identity for
 "and" must be true, and false for "or".
 
+We considered whether the syntax should be based on an
+iterated_element_association rather than an iterated_component_association. That
+would allow us to use the reverse keyword in the value_sequence. It was felt
+that the iterated_component_association and the model of an array aggregate is
+conceptually easier to understand than a container aggregate. Further, it was
+noted that the use of the order in reduction is rare, and only applies to
+certain reductions such as non-commutative reductions like concatenation. For
+such reductions, it is likely better to use an array aggregate rather than a
+reduction expression. Further the need for reverse ordering is even rarer and
+can be achieved easily enough using some simple math in the map applied in the
+value_sequence.
+
+e.g.
+
+ Success := Rockets.Blastoff (Countdown_Sequence => [for I in 1 .. 10 => (11-I)]'Reduce("&", []));
+
+
+We considered whether the combiner_subprogram should be disallowed if the
+parallel keyword is not present. We decided to allow it to be specified,
+even though it likely will not be called in this case, since only one logical
+thread of control is presumed. It does make it easier for the programmer to
+switch back and forth between sequential and parallel execution by simply
+removing or adding the parallel keyword.
+
+We considered defining an Associative aspect that could be specified on
+subprograms, and then having the compiler check that the reducer_subprogram
+and combiner_subprogram have that aspect specified as True when the parallel
+keyword is specified. Although it is true that the reducer_subprogram and
+combiner_subprogram need to be associative operations for parallelism
+to be applied, there are a number of problems with this. First of all,
+the compiler cannot verify if a particular call is truly associative,
+so the compiler would have to have faith in the programmer to get this right.
+Secondly, associativity can sometimes be in the eye of the beholder.
+For example, integer addition is normally considered an associative
+operation, but if integer overflow is a possibility, then technically
+the operation is not associative. That might be an important consideration
+for some users, and unimportant to others. Similarly, floating point math
+is not associative, due to the rounding errors that get introduced, but
+for many users, the results are good enough to consider as being associative.
+Thirdly, this added a lot of complexity and wording changes to the AI,
+which was deemed to not be worthwhile.
+
+We considered whether the initial_value was always needed or not. We could
+alternatively overload the attribute names to provide versions that do not
+accept a second argument.
+
+This however, means that there can be a question about what the expression
+should evaluate to, if the prefix of the attribute specifies a null range of
+values. Likely, an exception would need to be raised, but that can add
+complexity for uses such as contracts, since handling the exception case would
+need to be considered. We decided that for now at least, it is better to keep
+the interface simple. If an exception is needed for a null range, there are
+other ways to do that already in the language.
+
+Another concern might be about the need to perform multiple reductions at the
+same time.
+
+Consider:
+
+   Sum : Integer := [for Item of A => Item]'Reduce("+", 0):
+   Min : Integer := [for Item of A => Item]'Reduce(Integer'Min, Integer'Last);
+   Max : Integer := [for Item of A => Item]'Reduce(Integer'Max, Integer'First);
+
+Here we have three calculations that might ideally occur in parallel, but here
+would normally be expected to execute sequentially with respect to each other.
+
+One might want to calculate these three results iterating only once through the
+array.
+
+This can be accomplished by creating a composite result type, and writing a
+user-defined reducer function.
+
+   type Summary is
+      record
+         Sum : Integer;
+         Min : Integer;
+         Max : Integer;
+      end record;
+
+   -- Identity value for the Reduce function
+   Identity : constant Summary := Summary'(Sum => 0,
+                                           Min => Integer'Last,
+                                           Max => Integer'First);
+
+   -- Reducer function for the Reduction expression
+   function Reduce (L, R : Summary)
+       return Summary with Nonblocking, Globals => null is
+     (Summary'(Sum => L.Sum + R.Sum,
+               Min => Integer'Min (L.Min, R.Min),
+               Max => Integer'Max (L.Max, R.Max)));
+
+   -- Reduction expression to compute all 3 results at once
+   Result : constant Summary := [for Item of A => Item]'Reduce(Reduce, Identity);
+
+It was also noted here during performance testing that better times were
+collected by actually writting 3 separate reductions, however in other more
+complicated examples, it was found that writing a composite object as above
+provided better performance.
+
 !ASIS
 
 ** Unknown.
@@ -525,5 +812,86 @@
 
 OK, it makes sense to now when I think less of the underlying semantics, and
 more of it being a set of values to be reduced.
+
+****************************************************************
+
+From: Brad Moore
+Sent: Wednesday, January  9, 2019  12:37 AM
+
+Here is my homework update for AI12-0262-01 Map-Reduce attribute (Reduction
+Expressions) [This is version /04 of the AI - Editor.]
+
+There is a fair number of updates to the AI, but here is the main summary
+
+- Renamed value_generator term to value_sequence
+- Reworked the value_generator syntax to be based on
+  iterated_component_association rather than iterated_element_association.
+
+The main ramification of this change, is that we cannot use the reverse keyword
+to iterate in reverse order.
+
+For reductions, order is mostly unimportant, and only applies in certain types
+of reductions such as non-commutative reductions like concatenation.
+
+For concatenation, it is likely a better choice to use array aggregate syntax,
+rather than as a reduction
+
+If reverse order is needed, one can apply some simple math in the map function
+of the expression to get that effect.
+
+e.g.
+
+ Success := Rockets.Blastoff (Countdown_Sequence => [for I in 1 .. 10 => (11-I)]'Reduce("&", []));
+
+It was felt that basing the model on an array aggregate, rather than a container
+aggregate would be conceptually simpler to understand, and possibly implement.
+
+- More details on the dynamic semantics are provided.
+The conceptual model is that the value_sequence first produces an array
+aggregate object, then those values are passed in ascending order into
+successive calls to the Reducer subprogram.
+
+This is only the conceptual model. An AARM note recommends that the temporary
+array object not be created, and instead, calls are streamed into calls to the
+reducer subprogram as values are produced by the value sequence.
+
+- Most of the wording was moved into the new section for Reduction Expressions
+
+Thats pretty much it, other than numerous editorial changes.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, January 10, 2019  11:55 PM
+
+I've changed the wording instructions as I've commented on repeatedly tonight.
+
+Shortened a bunch overlong lines.
+
+----
+
+Technical comment, only noticed because my name is on it:
+
+>[For a reduction_attribute_reference for a value_sequence with the
+>parallel keyword, the Nonblocking aspect of the /reducer_/subprogram
+>shall be statically True, and the Global aspect of the
+>/reducer_/subprogram shall be statically null.]
+>
+> [Author's note: Randy says this rule is unnecessary, as it is covered
+> by  parallel constructs in AI12-0267-01, is it worth keeping here?]
+
+That's only true if you have wording that says a parallel
+reduction_attribute_reference is a parallel construct.  And you don't have that
+(it appears in the !proposal and !discussion, but not the actual wording.
+
+And here you are insisting on the strictest checks all of the time, whereas once
+you say this is a parallel constrcut, the rules allow users to turn off these
+checks (via a policy setting) if they think they know what they're doing.
+
+So since this isn't our intent, it's just wrong. You probably ought to have
+wording early on that says this is a parallel construct (in Static Semantics or
+even the introduction, not Legality Rules).
+
+I didn't make this change (maybe I should have).
 
 ****************************************************************

Questions? Ask the ACAA Technical Agent