Esempio n. 1
0
 def sequence_reduce(self, value, zero, op):
   """Implements `sequence_reduce` as defined in `api/intrinsics.py`."""
   value = value_impl.to_value(value, None, self._context_stack)
   zero = value_impl.to_value(zero, None, self._context_stack)
   op = value_impl.to_value(op, None, self._context_stack)
   # Check if the value is a federated sequence that should be reduced
   # under a `federated_map`.
   if value.type_signature.is_federated():
     is_federated_sequence = True
     value_member_type = value.type_signature.member
     value_member_type.check_sequence()
     zero_member_type = zero.type_signature.member
   else:
     is_federated_sequence = False
     value.type_signature.check_sequence()
   value = value_impl.ValueImpl.get_comp(value)
   zero = value_impl.ValueImpl.get_comp(zero)
   op = value_impl.ValueImpl.get_comp(op)
   if not is_federated_sequence:
     comp = building_block_factory.create_sequence_reduce(value, zero, op)
     comp = self._bind_comp_as_reference(comp)
     return value_impl.ValueImpl(comp, self._context_stack)
   else:
     ref_type = computation_types.StructType(
         [value_member_type, zero_member_type])
     ref = building_blocks.Reference('arg', ref_type)
     arg1 = building_blocks.Selection(ref, index=0)
     arg2 = building_blocks.Selection(ref, index=1)
     call = building_block_factory.create_sequence_reduce(arg1, arg2, op)
     fn = building_blocks.Lambda(ref.name, ref.type_signature, call)
     fn_value_impl = value_impl.ValueImpl(fn, self._context_stack)
     args = building_blocks.Struct([value, zero])
     return self.federated_map(fn_value_impl, args)
Esempio n. 2
0
    def sequence_reduce(self, value, zero, op):
        """Implements `sequence_reduce` as defined in `api/intrinsics.py`."""
        value = value_impl.to_value(value, None, self._context_stack)
        zero = value_impl.to_value(zero, None, self._context_stack)
        op = value_impl.to_value(op, None, self._context_stack)
        # Check if the value is a federated sequence that should be reduced
        # under a `federated_map`.
        if value.type_signature.is_federated():
            value_sequence_type = value.type_signature.member
            needs_map = True
        else:
            value_sequence_type = value.type_signature
            needs_map = False
        value_sequence_type.check_sequence()
        element_type = value_sequence_type.element
        op_type_expected = type_factory.reduction_op(zero.type_signature,
                                                     element_type)
        if not op_type_expected.is_assignable_from(op.type_signature):
            raise TypeError('Expected an operator of type {}, got {}.'.format(
                op_type_expected, op.type_signature))

        value = value_impl.ValueImpl.get_comp(value)
        zero = value_impl.ValueImpl.get_comp(zero)
        op = value_impl.ValueImpl.get_comp(op)
        if not needs_map:
            comp = building_block_factory.create_sequence_reduce(
                value, zero, op)
            comp = self._bind_comp_as_reference(comp)
            return value_impl.ValueImpl(comp, self._context_stack)
        else:
            ref = building_blocks.Reference('arg', value_sequence_type)
            call = building_block_factory.create_sequence_reduce(ref, zero, op)
            fn = building_blocks.Lambda(ref.name, ref.type_signature, call)
            fn_impl = value_impl.ValueImpl(fn, self._context_stack)
            return self.federated_map(fn_impl, value)
Esempio n. 3
0
    def sequence_reduce(self, value, zero, op):
        """Implements `sequence_reduce` as defined in `api/intrinsics.py`.

    Args:
      value: As in `api/intrinsics.py`.
      zero: As in `api/intrinsics.py`.
      op: As in `api/intrinsics.py`.

    Returns:
      As in `api/intrinsics.py`.

    Raises:
      TypeError: As in `api/intrinsics.py`.
    """
        value = value_impl.to_value(value, None, self._context_stack)
        zero = value_impl.to_value(zero, None, self._context_stack)
        op = value_impl.to_value(op, None, self._context_stack)
        if isinstance(value.type_signature, computation_types.SequenceType):
            element_type = value.type_signature.element
        else:
            py_typecheck.check_type(value.type_signature,
                                    computation_types.FederatedType)
            py_typecheck.check_type(value.type_signature.member,
                                    computation_types.SequenceType)
            element_type = value.type_signature.member.element
        op_type_expected = type_factory.reduction_op(zero.type_signature,
                                                     element_type)
        if not type_utils.is_assignable_from(op_type_expected,
                                             op.type_signature):
            raise TypeError('Expected an operator of type {}, got {}.'.format(
                op_type_expected, op.type_signature))

        value = value_impl.ValueImpl.get_comp(value)
        zero = value_impl.ValueImpl.get_comp(zero)
        op = value_impl.ValueImpl.get_comp(op)
        if isinstance(value.type_signature, computation_types.SequenceType):
            return building_block_factory.create_sequence_reduce(
                value, zero, op)
        else:
            value_type = computation_types.SequenceType(element_type)
            intrinsic_type = computation_types.FunctionType((
                value_type,
                zero.type_signature,
                op.type_signature,
            ), op.type_signature.result)
            intrinsic = building_blocks.Intrinsic(
                intrinsic_defs.SEQUENCE_REDUCE.uri, intrinsic_type)
            ref = building_blocks.Reference('arg', value_type)
            tup = building_blocks.Tuple((ref, zero, op))
            call = building_blocks.Call(intrinsic, tup)
            fn = building_blocks.Lambda(ref.name, ref.type_signature, call)
            fn_impl = value_impl.ValueImpl(fn, self._context_stack)
            if value.type_signature.placement is placements.SERVER:
                return self.federated_apply(fn_impl, value)
            elif value.type_signature.placement is placements.CLIENTS:
                return self.federated_map(fn_impl, value)
            else:
                raise TypeError('Unsupported placement {}.'.format(
                    value.type_signature.placement))
Esempio n. 4
0
    def sequence_reduce(self, value, zero, op):
        """Implements `sequence_reduce` as defined in `api/intrinsics.py`."""
        value = value_impl.to_value(value, None, self._context_stack)
        zero = value_impl.to_value(zero, None, self._context_stack)
        op = value_impl.to_value(op, None, self._context_stack)
        if value.type_signature.is_sequence():
            element_type = value.type_signature.element
        else:
            py_typecheck.check_type(value.type_signature,
                                    computation_types.FederatedType)
            py_typecheck.check_type(value.type_signature.member,
                                    computation_types.SequenceType)
            element_type = value.type_signature.member.element
        op_type_expected = type_factory.reduction_op(zero.type_signature,
                                                     element_type)
        if not op_type_expected.is_assignable_from(op.type_signature):
            raise TypeError('Expected an operator of type {}, got {}.'.format(
                op_type_expected, op.type_signature))

        value = value_impl.ValueImpl.get_comp(value)
        zero = value_impl.ValueImpl.get_comp(zero)
        op = value_impl.ValueImpl.get_comp(op)
        if value.type_signature.is_sequence():
            comp = building_block_factory.create_sequence_reduce(
                value, zero, op)
            comp = self._bind_comp_as_reference(comp)
            return value_impl.ValueImpl(comp, self._context_stack)
        else:
            value_type = computation_types.SequenceType(element_type)
            intrinsic_type = computation_types.FunctionType((
                value_type,
                zero.type_signature,
                op.type_signature,
            ), op.type_signature.result)
            intrinsic = building_blocks.Intrinsic(
                intrinsic_defs.SEQUENCE_REDUCE.uri, intrinsic_type)
            ref = building_blocks.Reference('arg', value_type)
            tup = building_blocks.Struct((ref, zero, op))
            call = building_blocks.Call(intrinsic, tup)
            fn = building_blocks.Lambda(ref.name, ref.type_signature, call)
            fn_impl = value_impl.ValueImpl(fn, self._context_stack)
            return self.federated_map(fn_impl, value)
Esempio n. 5
0
def sequence_reduce(value, zero, op):
    """Reduces a TFF sequence `value` given a `zero` and reduction operator `op`.

  This method reduces a set of elements of a TFF sequence `value`, using a given
  `zero` in the algebra (i.e., the result of reducing an empty sequence) of some
  type `U`, and a reduction operator `op` with type signature `(<U,T> -> U)`
  that incorporates a single `T`-typed element of `value` into the `U`-typed
  result of partial reduction. In the special case of `T` equal to `U`, this
  corresponds to the classical notion of reduction of a set using a commutative
  associative binary operator. The generalized reduction (with `T` not equal to
  `U`) requires that repeated application of `op` to reduce a set of `T` always
  yields the same `U`-typed result, regardless of the order in which elements
  of `T` are processed in the course of the reduction.

  One can also invoke `sequence_reduce` on a federated sequence, in which case
  the reductions are performed pointwise; under the hood, we construct an
  expression  of the form
  `federated_map(x -> sequence_reduce(x, zero, op), value)`. See also the
  discussion on `sequence_map`.

  Note: When applied to a federated value this function does the reduce
  point-wise.

  Args:
    value: A value that is either a TFF sequence, or a federated sequence.
    zero: The result of reducing a sequence with no elements.
    op: An operator with type signature `(<U,T> -> U)`, where `T` is the type of
      the elements of the sequence, and `U` is the type of `zero` to be used in
      performing the reduction.

  Returns:
    The `U`-typed result of reducing elements in the sequence, or if the `value`
    is federated, a federated `U` that represents the result of locally
    reducing each member constituent of `value`.

  Raises:
    TypeError: If the arguments are not of the types specified above.
  """
    value = value_impl.to_value(value, None)
    zero = value_impl.to_value(zero, None)
    op = value_impl.to_value(op, None)
    # Check if the value is a federated sequence that should be reduced
    # under a `federated_map`.
    if value.type_signature.is_federated():
        is_federated_sequence = True
        value_member_type = value.type_signature.member
        value_member_type.check_sequence()
        zero_member_type = zero.type_signature.member
    else:
        is_federated_sequence = False
        value.type_signature.check_sequence()
    if not is_federated_sequence:
        comp = building_block_factory.create_sequence_reduce(
            value.comp, zero.comp, op.comp)
        comp = _bind_comp_as_reference(comp)
        return value_impl.Value(comp)
    else:
        ref_type = computation_types.StructType(
            [value_member_type, zero_member_type])
        ref = building_blocks.Reference('arg', ref_type)
        arg1 = building_blocks.Selection(ref, index=0)
        arg2 = building_blocks.Selection(ref, index=1)
        call = building_block_factory.create_sequence_reduce(
            arg1, arg2, op.comp)
        fn = building_blocks.Lambda(ref.name, ref.type_signature, call)
        fn_value_impl = value_impl.Value(fn)
        args = building_blocks.Struct([value.comp, zero.comp])
        return federated_map(fn_value_impl, args)