package reverse; import base.Named; import base.Selector; import base.TestCounter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.IntToLongFunction; import java.util.function.LongBinaryOperator; import java.util.stream.IntStream; import reverse.ReverseTester.Op; /** * Tests for {@code Reverse} homework. * * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) */ public final class ReverseTest { // === Base public static final Named REVERSE = Named.of( "", ReverseTester::transform ); // === Max public static final Named MAX_C = Named.of("MaxC", scan2((a, b) -> b)); public static final Named MAX = Named.of("Max", scan2(Math::max)); private static Op scan2(final LongBinaryOperator reduce) { return ints -> { // This code is intentionally obscure final int length = Arrays.stream(ints) .mapToInt(r -> r.length) .max() .orElse(0); final long[] cs = new long[length]; final long[] cc = new long[length + 1]; Arrays.fill(cs, Integer.MIN_VALUE); Arrays.fill(cc, Integer.MIN_VALUE); //noinspection NestedAssignment final long[][] rows = range(ints.length) .mapToObj(i -> { range(ints[i].length).forEachOrdered(j -> cc[j] = reduce.applyAsLong( cc[j + 1], cs[j] = Math.max(cs[j], ints[i][j]) ) ); return Arrays.copyOf(cc, ints[i].length); }) .toArray(long[][]::new); return range(ints.length) .mapToObj(i -> rows[i]) .toArray(long[][]::new); }; } private static IntStream range(final int length) { return IntStream.iterate(length - 1, i -> i >= 0, i -> i - 1); } // === Rotate public static final Named ROTATE = Named.of("Rotate", ints -> { final List rows = new ArrayList<>(List.of(ints)); return IntStream.range( 0, Arrays.stream(ints) .mapToInt(r -> r.length) .max() .orElse(0) ) .mapToObj(c -> { rows.removeIf(r -> r.length <= c); return range(rows.size()) .mapToObj(rows::get) .mapToLong(r -> r[c]) .toArray(); }) .toArray(long[][]::new); }); // === Even public static final Named EVEN = Named.of("Even", ints -> ReverseTester.transform( IntStream.range(0, ints.length) .mapToObj(i -> IntStream.range(0, ints[i].length) .filter(j -> (i + j) % 2 == 0) .map(j -> ints[i][j]) ) .map(IntStream::toArray) .toArray(int[][]::new) ) ); // Sum @FunctionalInterface interface LongTernaryOperator { long applyAsLong(long a, long b, long c); } public static final Named SUM = cross( "Sum", 0, Long::sum, (r, c, v) -> r + c - v ); private static long[][] cross( final int[][] ints, final IntToLongFunction map, final LongBinaryOperator reduce, final int zero, final LongTernaryOperator get ) { // This code is intentionally obscure final long[] rt = Arrays.stream(ints) .map(Arrays::stream) .mapToLong(row -> row.mapToLong(map).reduce(zero, reduce)) .toArray(); final long[] ct = new long[Arrays.stream(ints) .mapToInt(r -> r.length) .max() .orElse(0)]; Arrays.fill(ct, zero); Arrays.stream(ints).forEach(r -> IntStream.range(0, r.length).forEach(i -> ct[i] = reduce.applyAsLong(ct[i], map.applyAsLong(r[i])) ) ); return IntStream.range(0, ints.length) .mapToObj(r -> IntStream.range(0, ints[r].length) .mapToLong(c -> get.applyAsLong(rt[r], ct[c], ints[r][c])) .toArray() ) .toArray(long[][]::new); } private static Named cross( final String name, final int zero, final LongBinaryOperator reduce, final LongTernaryOperator get ) { return Named.of(name, ints -> cross(ints, n -> n, reduce, zero, get)); } public static final Named AVG = avg( "Avg", ints -> cross(ints, n -> n, Long::sum, 0, (r, c, v) -> r + c - v), ints -> cross(ints, n -> 1, Long::sum, 0, (r1, c1, v1) -> r1 + c1 - 1) ); private static Named avg(final String name, final Op fs, final Op fc) { return Named.of(name, ints -> avg(ints, fs.apply(ints), fc.apply(ints)) ); } private static long[][] avg( final int[][] ints, final long[][] as, final long[][] ac ) { return IntStream.range(0, ints.length) .mapToObj(i -> IntStream.range(0, ints[i].length) .mapToLong(j -> as[i][j] / ac[i][j]) .toArray() ) .toArray(long[][]::new); } // === Common public static final int MAX_SIZE = 10_000 / TestCounter.DENOMINATOR; public static final Selector SELECTOR = selector( ReverseTest.class, MAX_SIZE ); private ReverseTest() { // Utility class } public static Selector selector(final Class owner, final int maxSize) { return new Selector(owner) .variant("Base", ReverseTester.variant(maxSize, REVERSE)) .variant("3637", ReverseTester.variant(maxSize, MAX_C)) .variant("3839", ReverseTester.variant(maxSize, MAX)) .variant("3435", ReverseTester.variant(maxSize, ROTATE)) .variant("3233", ReverseTester.variant(maxSize, EVEN)) .variant("4142", ReverseTester.variant(maxSize, AVG)) .variant("4749", ReverseTester.variant(maxSize, SUM)); } public static void main(final String... args) { SELECTOR.main(args); } }