class IgniteColocatedAggregateBase extends IgniteAggregate implements TraitsAwareIgniteRel {
    /** */
    protected IgniteColocatedAggregateBase(
        RelOptCluster cluster,
        RelTraitSet traitSet,
        RelNode input,
        ImmutableBitSet groupSet,
        List<ImmutableBitSet> groupSets,
        List<AggregateCall> aggCalls
    ) {
        super(cluster, traitSet, input, groupSet, groupSets, aggCalls);
    }

    /** */
    protected IgniteColocatedAggregateBase(RelInput input) {
        super(TraitUtils.changeTraits(input, IgniteConvention.INSTANCE));
    }

    /** {@inheritDoc} */
    @Override public Pair<RelTraitSet, List<RelTraitSet>> passThroughDistribution(
        RelTraitSet nodeTraits,
        List<RelTraitSet> inTraits
    ) {
        IgniteDistribution distr = TraitUtils.distribution(nodeTraits);

        if (distr == IgniteDistributions.single() || distr.function().correlated())
            return Pair.of(nodeTraits, Commons.transform(inTraits, t -> t.replace(distr)));

        return null;
    }

    /** {@inheritDoc} */
    @Override public List<Pair<RelTraitSet, List<RelTraitSet>>> deriveRewindability(
        RelTraitSet nodeTraits,
        List<RelTraitSet> inputTraits
    ) {
        return ImmutableList.of(Pair.of(nodeTraits, ImmutableList.of(inputTraits.get(0))));
    }

    /** {@inheritDoc} */
    @Override public List<Pair<RelTraitSet, List<RelTraitSet>>> deriveDistribution(
        RelTraitSet nodeTraits,
        List<RelTraitSet> inputTraits
    ) {<FILL_FUNCTION_BODY>}

    /** {@inheritDoc} */
    @Override public List<Pair<RelTraitSet, List<RelTraitSet>>> deriveCorrelation(
        RelTraitSet nodeTraits,
        List<RelTraitSet> inTraits
    ) {
        return ImmutableList.of(Pair.of(nodeTraits.replace(TraitUtils.correlation(inTraits.get(0))),
            inTraits));
    }
}

        IgniteDistribution inDistribution = TraitUtils.distribution(inputTraits.get(0));

        if (inDistribution.satisfies(IgniteDistributions.single()))
            return ImmutableList.of(Pair.of(nodeTraits.replace(IgniteDistributions.single()), inputTraits));

        if (inDistribution.getType() == RelDistribution.Type.HASH_DISTRIBUTED) {
            for (Integer key : inDistribution.getKeys()) {
                if (!groupSet.get(key))
                    return ImmutableList.of();
            }

            // Group set contains all distribution keys, shift distribution keys according to used columns.
            IgniteDistribution outDistribution = inDistribution.apply(Commons.mapping(groupSet, rowType.getFieldCount()));

            return ImmutableList.of(Pair.of(nodeTraits.replace(outDistribution), inputTraits));
        }

        return ImmutableList.of();
    
<methods>public RelOptCost computeSelfCostHash(RelOptPlanner, RelMetadataQuery) ,public RelOptCost computeSelfCostSort(RelOptPlanner, RelMetadataQuery) ,public double estimateMemoryForGroup(RelMetadataQuery) ,public double estimateRowCount(RelMetadataQuery) <variables>