### Question:
SemiJoinStatsCalculator { public static PlanNodeStatsEstimate computeAntiJoin(PlanNodeStatsEstimate sourceStats, PlanNodeStatsEstimate filteringSourceStats, Symbol sourceJoinSymbol, Symbol filteringSourceJoinSymbol) { return compute(sourceStats, filteringSourceStats, sourceJoinSymbol, filteringSourceJoinSymbol, (sourceJoinSymbolStats, filteringSourceJoinSymbolStats) -> max(sourceJoinSymbolStats.getDistinctValuesCount() * MIN_ANTI_JOIN_FILTER_COEFFICIENT, sourceJoinSymbolStats.getDistinctValuesCount() - filteringSourceJoinSymbolStats.getDistinctValuesCount())); } private  SemiJoinStatsCalculator(); static PlanNodeStatsEstimate computeSemiJoin(PlanNodeStatsEstimate sourceStats, PlanNodeStatsEstimate filteringSourceStats, Symbol sourceJoinSymbol, Symbol filteringSourceJoinSymbol); static PlanNodeStatsEstimate computeAntiJoin(PlanNodeStatsEstimate sourceStats, PlanNodeStatsEstimate filteringSourceStats, Symbol sourceJoinSymbol, Symbol filteringSourceJoinSymbol);  }### Answer:
@Test public void testAntiJoin() { assertThat(computeAntiJoin(inputStatistics, inputStatistics, u, x)) .symbolStats(u, stats -> stats .lowValue(uStats.getLowValue()) .highValue(uStats.getHighValue()) .nullsFraction(0) .distinctValuesCount(uStats.getDistinctValuesCount() - xStats.getDistinctValuesCount())) .symbolStats(x, stats -> stats.isEqualTo(xStats)) .symbolStats(z, stats -> stats.isEqualTo(zStats)) .outputRowsCount(inputStatistics.getOutputRowCount() * uStats.getValuesFraction() * (1 - xStats.getDistinctValuesCount() / uStats.getDistinctValuesCount())); assertThat(computeAntiJoin(inputStatistics, inputStatistics, x, u)) .symbolStats(x, stats -> stats .lowValue(xStats.getLowValue()) .highValue(xStats.getHighValue()) .nullsFraction(0) .distinctValuesCount(xStats.getDistinctValuesCount() * 0.5)) .symbolStats(u, stats -> stats.isEqualTo(uStats)) .symbolStats(z, stats -> stats.isEqualTo(zStats)) .outputRowsCount(inputStatistics.getOutputRowCount() * xStats.getValuesFraction() * 0.5); assertThat(computeAntiJoin(inputStatistics, inputStatistics, unknown, u)) .symbolStats(unknown, stats -> stats .nullsFraction(0) .distinctValuesCountUnknown() .unknownRange()) .symbolStats(u, stats -> stats.isEqualTo(uStats)) .symbolStats(z, stats -> stats.isEqualTo(zStats)) .outputRowsCountUnknown(); assertThat(computeAntiJoin(inputStatistics, inputStatistics, x, unknown)) .symbolStats(x, stats -> stats .nullsFraction(0) .lowValue(xStats.getLowValue()) .highValue(xStats.getHighValue()) .distinctValuesCountUnknown()) .symbolStatsUnknown(unknown) .symbolStats(z, stats -> stats.isEqualTo(zStats)) .outputRowsCountUnknown(); assertThat(computeAntiJoin(inputStatistics, inputStatistics, emptyRange, emptyRange)) .outputRowsCount(0); assertThat(computeAntiJoin(inputStatistics, inputStatistics, fractionalNdv, fractionalNdv)) .outputRowsCount(500) .symbolStats(fractionalNdv, stats -> stats .nullsFraction(0) .distinctValuesCount(0.05)); }