def __invert__(self):
        """

        :return:
        """
        operator = 'not'
        my_builder = self._get_band_graph_builder()
        new_builder = None
        extend_previous_callback_graph = my_builder is not None
        # TODO: why does these `add_process` calls use "expression" instead of "data" like the other cases?
        if not extend_previous_callback_graph:
            new_builder = GraphBuilder()
            # TODO merge both process graphs?
            new_builder.add_process(operator,
                                    expression={'from_argument': 'data'},
                                    result=True)
        else:
            current_result = my_builder.find_result_node_id()
            new_builder = my_builder.copy()
            new_builder.processes[current_result]['result'] = False
            new_builder.add_process(operator,
                                    expression={'from_node': current_result},
                                    result=True)

        return self._create_reduced_collection(new_builder,
                                               extend_previous_callback_graph)
    def _reduce_bands_binary_xy(self, operator, other: Union[ImageCollection,
                                                             Union[int,
                                                                   float]]):
        """
        Pixelwise comparison of this data cube with another cube or constant.

        :param other: Another data cube, or a constant
        :return:
        """
        if isinstance(other, int) or isinstance(other, float):
            my_builder = self._get_band_graph_builder()
            new_builder = None
            extend_previous_callback_graph = my_builder is not None
            if not extend_previous_callback_graph:
                new_builder = GraphBuilder()
                # TODO merge both process graphs?
                new_builder.add_process(operator,
                                        x={'from_argument': 'data'},
                                        y=other,
                                        result=True)
            else:
                current_result = my_builder.find_result_node_id()
                new_builder = my_builder.copy()
                new_builder.processes[current_result]['result'] = False
                new_builder.add_process(operator,
                                        x={'from_node': current_result},
                                        y=other,
                                        result=True)

            return self._create_reduced_collection(
                new_builder, extend_previous_callback_graph)
        elif isinstance(other, ImageCollection):
            return self._reduce_bands_binary(operator, other)
        else:
            raise ValueError("Unsupported right-hand operand: " + str(other))
    def _reduce_bands_binary_const(self, operator, other:Union[int,float]):
        my_builder = self._get_band_graph_builder()
        new_builder = None
        extend_previous_callback_graph = my_builder is not None
        if not extend_previous_callback_graph:
            new_builder = GraphBuilder()
            # TODO merge both process graphs?
            new_builder.add_process(operator, data=[{'from_argument': 'data'}, other], result=True)
        else:
            current_result = my_builder.find_result_node_id()
            new_builder = my_builder.copy()
            new_builder.processes[current_result]['result'] = False
            new_builder.add_process(operator, data=[{'from_node': current_result}, other], result=True)

        return self._create_reduced_collection(new_builder,extend_previous_callback_graph)