Ada Conformity Assessment Authority |
Home |
Conformity Assessment | Test Suite |
ARG | Ada Standard |

{*AI12-0242-1*}
{*AI12-0262-1*}
Reduction expressions
provide 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. A reduction expression is
represented as an attribute_reference
of the reduction attributes Reduce or Parallel_Reduce.

{*AI12-0242-1*}
{*AI12-0262-1*}
reduction_attribute_reference ::=

value_sequence'reduction_attribute_designator

| prefix'reduction_attribute_designator

value_sequence'reduction_attribute_designator

| prefix'reduction_attribute_designator

{*AI12-0262-1*}
{*AI12-0355-2*}
value_sequence ::=

'[' [**parallel**[(chunk_specification)] [aspect_specification]]

iterated_element_association ']'

'[' [

iterated_element_association ']'

{*AI12-0250-1*}
{*AI12-0262-1*}
The iterated_element_association
of a value_sequence
shall not have a *key_*expression,
nor shall it have a loop_parameter_specification
that has the reserved word **reverse**.

{*AI12-0262-1*}
The chunk_specification,
if any, of a value_sequence
shall be an *integer_*simple_expression.

{*AI12-0262-1*}
The expected type for a reduction_attribute_reference
shall be a single nonlimited type.

{*AI12-0262-1*}
In the remainder of this subclause, we will refer
to nonlimited subtypes *Value_Type* and *Accum_Type* of a reduction_attribute_reference.
These subtypes and interpretations of the names
and expressions
of a reduction_attribute_reference
are determined by the following rules:

{*AI12-0262-1*}
*Accum_Type* is a subtype of the expected
type of the reduction_attribute_reference.

{*AI12-0262-1*}
A *reducer subprogram*
is subtype conformant with one of the following specifications:

Value :

Value :

{*AI12-0262-1*}
The *reducer_*name
of a reduction_specification
denotes a reducer subprogram.

{*AI12-0262-1*}
The expected type of an *initial_value_*expression
of a reduction_specification
is that of subtype *Accum_Type*.

{*AI12-0250-1*}
{*AI12-0262-1*}
The expected type of the expression
of the iterated_element_association
of a value_sequence
is that of subtype *Value_Type*.

{*AI12-0262-1*}
{*AI12-0348-1*}
If the reduction_attribute_reference
has a value_sequence
with the reserved word **parallel**, the subtypes *Accum_Type*
and *Value_Type* shall statically match.

{*AI12-0262-1*}
{*AI12-0348-1*}
If the identifier
of a reduction_attribute_designator
is Parallel_Reduce, the subtypes *Accum_Type* and *Value_Type*
shall statically match.

{*AI12-0262-1*}
A reduction_attribute_reference
denotes a value, with its nominal subtype being the subtype of the first
parameter of the subprogram denoted by the *reducer_*name.

{*AI12-0250-1*}
{*AI12-0262-1*}
{*AI12-0327-1*}
{*AI12-0355-2*}
For the evaluation of a value_sequence,
the iterated_element_association,
the chunk_specification,
and the aspect_specification,
if any, are elaborated in an arbitrary order. Next an iteration is performed,
and for each value conditionally produced by the iteration (see 5.5
and 5.5.2), the associated expression
is evaluated with the loop parameter having this value, which produces
a result that is converted to Value_Type and is used to define the next
value in the sequence.

{*AI12-0262-1*}
If the value_sequence
does not have the reserved word **parallel**, it is produced as a
single sequence of values by a single logical thread of control. If the
reserved word **parallel** is present in the value_sequence,
the enclosing reduction_attribute_reference
is a parallel construct, and the sequence of values is generated by a
parallel iteration (as defined in 5.5, 5.5.1,
and 5.5.2), as a set of non-empty, non-overlapping
contiguous chunks (*subsequences*) with one
logical thread of control (see Clause 9) associated
with each subsequence. If there is a chunk_specification,
it determines the maximum number of chunks, as defined in 5.5;
otherwise the maximum number of chunks is implementation defined.

{*AI12-0262-1*}
For a value_sequence
V, the following attribute is defined:

V'Reduce(Reducer,
Initial_Value)

{

{*AI12-0262-1*}
{*AI12-0348-1*}
The evaluation of a use of
this attribute begins by evaluating the parts of the reduction_attribute_designator
(the *reducer_*name
Reducer and the *initial_value_*expression
Initial_Value), in an arbitrary order. It then initializes
the *accumulator* of the reduction expression to the value of the
*initial_value_*expression
(the *initial value*).
The value_sequence
V is then evaluated.

{*AI12-0262-1*}
{*AI12-0348-1*}
If the value_sequence
does not have the reserved word **parallel**, each value of the value_sequence
is passed, in order, as the second (Value) parameter to a call on Reducer,
with the first (Accumulator) parameter being the prior value of the accumulator,
saving the result as the new value of the accumulator. The reduction
expression yields the final value of the accumulator.

{*AI12-0262-1*}
If the reserved word **parallel** is present
in a value_sequence,
then the (parallel) reduction expression is a parallel construct and
the sequence has been partitioned into one or more subsequences (see
above) each with its own separate logical thread of control.

{*AI12-0262-1*}
{*AI12-0348-1*}
Each logical thread of control creates a local
accumulator for processing its subsequence. The accumulator for a subsequence
is initialized to the first value of the subsequence, and calls on Reducer
start with the second value of the subsequence (if any). The result for
the subsequence is the final value of its local accumulator.

{*AI12-0262-1*}
{*AI12-0348-1*}
After all logical threads of control of a parallel
reduction expression have completed, Reducer is called for each subsequence,
in the original sequence order, passing the local accumulator for that
subsequence as the second (Value) parameter, and the overall accumulator
[(initialized above to the initial value)] as the first (Accumulator)
parameter, with the result saved back in the overall accumulator. The
parallel reduction expression yields the final value of the overall accumulator.

{*AI12-0262-1*}
If the evaluation of the value_sequence
yields an empty sequence of values, the reduction expression yields the
initial value.

{*AI12-0262-1*}
{*AI12-0348-1*}
If an exception is propagated by one of the calls
on Reducer, that exception is propagated from the reduction expression.
If different exceptions are propagated in different logical threads of
control, one is chosen arbitrarily to be propagated from the reduction
expression as a whole.

{*AI12-0242-1*}
For a prefix
X of an array type[ (after any implicit dereference)], or that denotes
an iterable container object (see 5.5.1),
the following attributes are defined:

X'Reduce(Reducer,
Initial_Value)

{

[**for** Item **of** X => Item]

X'Parallel_Reduce(Reducer,
Initial_Value)

{

[**parallel for** Item **of** X => Item]

{*AI12-0262-1*}
{*AI12-0348-1*}
For a parallel reduction expression,
it is a bounded error if the reducer subprogram is not associative. That
is, for any arbitrary values of subtype *Value_Type* *A*, *B*,
*C* and a reducer function *R*, the result of *R* (*A*,
*R* (*B*, *C*)) should produce a result equal to *R*
(*R* (*A*, *B*), *C*)); it is a bounded error if
*R* does not. The possible consequences are Program_Error, or a
result that does not match the equivalent sequential reduction expression
due to the order of calls on the reducer subprogram being unspecified
in the overall reduction. Analogous rules apply in the case of a reduction
procedure.

{*AI12-0262-1*}
{*AI12-0429-1*}
*Example of an expression function that returns
its result as a reduction expression:*

([

{*AI12-0262-1*}
{*AI12-0429-1*}
*Example of a reduction expression that computes
the Sine of X using a Taylor expansion:*

([

(-1.0)**(I-1) * X**(2*I-1)/Float(Factorial(2*I-1))]

'Reduce("+", 0.0));

{*AI12-0262-1*}
{*AI12-0379-1*}
{*AI12-0429-1*}
*Example of 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)));

Integer'Image([

{*AI12-0262-1*}
{*AI12-0379-1*}
{*AI12-0429-1*}
*Example of a reduction expression used to compute
the value of Pi:*

-- *See 3.5.7.*

**function** Pi (Number_Of_Steps : Natural := 10_000) **return** Real **is**

(1.0 / Real (Number_Of_Steps) *

[**for** I **in** 1 .. Number_Of_Steps =>

(4.0 / (1.0 + ((Real (I) - 0.5) *

(1.0 / Real (Number_Of_Steps)))**2))]

'Reduce("+", 0.0));

(1.0 / Real (Number_Of_Steps) *

[

(4.0 / (1.0 + ((Real (I) - 0.5) *

(1.0 / Real (Number_Of_Steps)))**2))]

'Reduce("+", 0.0));

{*AI12-0242-1*}
{*AI12-0429-1*}
*Example of a reduction expression used to calculate
the sum of elements of an array of integers:*

A'Reduce("+",0) -- *See 4.3.3.*

{*AI12-0242-1*}
{*AI12-0429-1*}
*Example of a reduction expression used to determine
if all elements in a two-dimensional array of booleans are set to true:*

Grid'Reduce("and", True) -- *See 3.6.*

{*AI12-0242-1*}
{*AI12-0429-1*}
*Example of a reduction expression used to calculate
the minimum value of an array of integers in parallel:*

A'Parallel_Reduce(Integer'Min, Integer'Last)

{*AI12-0312-1*}
{*AI12-0429-1*}
*Example of a parallel reduction expression used
to calculate the mean of the elements of a two-dimensional array of subtype
Matrix (see 3.6) that are greater than 100.0:*

Sum : Real; --

Count : Integer;

(Sum => L.Sum + R.Sum,

Count => L.Count + R.Count);

(

Acc :

[

'Reduce(Accumulate, (Sum => 0, Count => 0));

Acc.Sum / Real(Acc.Count));

Ada 2005 and 2012 Editions sponsored in part by **Ada-Europe**