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

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.

reduction_attribute_reference ::=

value_sequence'reduction_attribute_designator

| prefix'reduction_attribute_designator

value_sequence'reduction_attribute_designator

| prefix'reduction_attribute_designator

For the case of an iterated_component_association
of a value_sequence
having a discrete_choice_list,
there shall be exactly one discrete_choice
in the discrete_choice_list,
which shall be a *discrete_*subtype_indication
or a range.

The expected type for a reduction_attribute_reference
shall be a single nonlimited type.

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:

or is subtype
conformant with the following specification:

The expected type of an *initial_value_*expression
of a reduction_specification
is that of subtype *Accum_Type*.

For an iterated_component_association
of a value_sequence
that has a discrete_choice_list
comprising a single range,
the range
shall resolve to some discrete type; which discrete type shall be determined
without using any context other than the bounds of the range itself (plus
the preference for *root_integer* - see 8.6).
If the range resolves to *root_integer*; the type of the index parameter
of the iterated_component_association
(the *index type* of the value_sequence)
is Integer; otherwise the index type is the resolved type of the *discrete_*subtype_indication
or range of
the discrete_choice_list.
For an iterated_component_association
of a value_sequence
that has an iterator_specification,
the index type of the value_sequence
is Integer and the type of the loop parameter of the iterator_specification
is as defined in 5.5.2.

The *combiner_*name
of a reduction_specification
shall be specified if the subtypes of the parameters of the subprogram
denoted by the *reducer_*name
of the reduction_specification
do not statically match each other and the reduction_attribute_reference
has a value_sequence
with the reserved word **parallel**.

If the identifier
of a reduction_attribute_designator
is Parallel_Reduce then the *combiner_*name
of the reduction_specification
shall be specified if the subtypes of all the parameters of the subprogram
denoted by the *reducer_*name
of the reduction_specification
do not statically match.

The nominal subtype of the index parameter of a value_sequence
is that of the discrete_choice.
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 subprogram denoted by the *reducer_*name.

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_*name
also implicitly denotes the combiner subprogram.

For a reduction_attribute_reference
where the identifier
of the reduction_attribute_designator
is Parallel_Reduce, if the *combiner_*name
is not specified, then the subprogram denoted by the *reducer_*name
also implicitly denotes the combiner subprogram.

For
the evaluation of a value_sequence:

if the iterated_component_association
has an iterator_specification,
an iteration is performed for that iterator_specification
(as described in 5.5.2), and for each value
produced by the iterator, the associated expression
is evaluated with the loop parameter having this value, to produce a
result that is converted to Value_Type, and used to define the next value
in the sequence;

otherwise, the discrete_choice_list
of the iterated_component_association
is evaluated, and for each value, in increasing order, of the discrete
subtype or range defined by the discrete_choice_list,
the associated expression
is evaluated with the index parameter having this value, to produce a
result that is converted to Value_Type, and used to define the next value
in the sequence.

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.

For a value_sequence
V, the following attribute is defined:

V'Reduce(Reducer,
Initial_Value[, Combiner])

This attribute represents a

The evaluation of a
use of this attribute begins by evaluating the parts of the reduction_attribute_designator
(the *reducer_*name
Reducer, the *initial_value_*expression
Initial_Value, and the *combiner_*name
Combiner, if any), 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.

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. Combiner, if specified,
is ignored for such a (sequential) reduction expression.

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.

Each logical thread of control creates
a local accumulator for processing its subsequence. If there is a separate
Combiner subprogram specified, then the accumulator for each subsequence
is initialized to the initial value, and Reducer is called in sequence
order with each value of the subsequence as the second (Value) parameter,
and with this local accumulator as the first (Accumulator) parameter,
saving the result back into this local accumulator. If there is no separate
combiner specified, then 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). In either case, the result
for the subsequence is the final value of its local accumulator.

After all logical threads of control of
a parallel reduction expression have completed, Combiner (or Reducer,
if Combiner is not specified) 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.

If the evaluation of the value_sequence
yields an empty sequence of values, the reduction expression yields the
initial value.

If an exception is propagated by one of
the calls on Reducer or Combiner, 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.

For a prefix
X of an array type (after any implicit dereference), or denotes an iterable
container object (see 5.5.1), the following
attributes are defined:

X'Reduce(Reducer,
Initial_Value[, Combiner])

X'Reduce is a reduction expression that yields a result equivalent to replacing the prefix of the attribute with the value_sequence:

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

X'Parallel_Reduce(Reducer,
Initial_Value[, Combiner])

X'Parallel_Reduce is a reduction expression that yields a result equivalent to replacing the attribute identifier with Reduce and the prefix of the attribute with the value_sequence:

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

If a parallel reduction expression
has a combiner subprogram specified, then it is a bounded error if the
initial value is not the (left) identity of the combiner subprogram.
That is, the result of calling the combiner subprogram with the Accumulator
being the initial value and the Value being any arbitrary value of subtype
*Accum_Type* should produce a result equal to the Value parameter.
The possible consequences are Program_Error, or a result that does not
match the equivalent sequential reduction expression due to multiple
uses of the non-identity initial value in the overall reduction.

An expression function
that returns its result as a Reduction Expression:

([

An expression function
that computes the Sin of X using Taylor expansion:

([

'Reduce("+", 0.0));

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([

An expression function
to compute the value of Pi:

-- *See 3.5.7.*

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

(1.0 / Number_Of_Steps *

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

(4.0 / (1.0 + ((Real (I) - 0.5) * (1.0 / Number_Of_Steps))**2))]

'Reduce("+", 0.0));

(1.0 / Number_Of_Steps *

[

(4.0 / (1.0 + ((Real (I) - 0.5) * (1.0 / Number_Of_Steps))**2))]

'Reduce("+", 0.0));

Calculate the sum of
elements of an array of integers:

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

Determine if all elements
in a two dimensional array of booleans are set to true:

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

Calculate the minimum
value of an array of integers in parallel:

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

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