public static FilterPredicate rewrite(FilterPredicate pred) {
    Objects.requireNonNull(pred, "pred cannot be null");
    return pred.accept(INSTANCE);
  }
@Test
  public void testBaseCases() {
    UserDefined<Integer, DummyUdp> ud = userDefined(intColumn, DummyUdp.class);

    assertNoOp(eq(intColumn, 17));
    assertNoOp(notEq(intColumn, 17));
    assertNoOp(lt(intColumn, 17));
    assertNoOp(ltEq(intColumn, 17));
    assertNoOp(gt(intColumn, 17));
    assertNoOp(gtEq(intColumn, 17));
    assertNoOp(and(eq(intColumn, 17), eq(doubleColumn, 12.0)));
    assertNoOp(or(eq(intColumn, 17), eq(doubleColumn, 12.0)));
    assertNoOp(ud);

    assertEquals(notEq(intColumn, 17), rewrite(not(eq(intColumn, 17))));
    assertEquals(eq(intColumn, 17), rewrite(not(notEq(intColumn, 17))));
    assertEquals(gtEq(intColumn, 17), rewrite(not(lt(intColumn, 17))));
    assertEquals(gt(intColumn, 17), rewrite(not(ltEq(intColumn, 17))));
    assertEquals(ltEq(intColumn, 17), rewrite(not(gt(intColumn, 17))));
    assertEquals(lt(intColumn, 17), rewrite(not(gtEq(intColumn, 17))));
    assertEquals(new LogicalNotUserDefined<>(ud), rewrite(not(ud)));

    FilterPredicate notedAnd = not(and(eq(intColumn, 17), eq(doubleColumn, 12.0)));
    FilterPredicate distributedAnd = or(notEq(intColumn, 17), notEq(doubleColumn, 12.0));
    assertEquals(distributedAnd, rewrite(notedAnd));

    FilterPredicate andWithNots = and(not(gtEq(intColumn, 17)), lt(intColumn, 7));
    FilterPredicate andWithoutNots = and(lt(intColumn, 17), lt(intColumn, 7));
    assertEquals(andWithoutNots, rewrite(andWithNots));
  }