Java tutorial
// @formatter:off /******************************************************************************* * * This file is part of tensorics. * * Copyright (c) 2008-2011, CERN. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ // @formatter:on package org.tensorics.core.tensor; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static java.util.stream.Collectors.toSet; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.common.collect.Sets.SetView; /** * Contains utility methods for position objects. * * @author kfuchsbe */ public final class Positions { /** * private constructor to avoid instantiation */ private Positions() { /* Only static methods */ } /** * Constructs a position, whose coordinates are the union of the coordinates of the two individual positions. This * is only correctly defined, if the two given positions do not have any dimensional overlap (i.e. Any coordinate of * a certain type (class) is only present in either the left or the right position.) * * @param left the first position to use construct the union position * @param right the second position to construct the union position * @return a position, which contains the union of the coordinates of the two input positions. * @throws NullPointerException if one of the arguments is {@code null} * @throws IllegalArgumentException if the given aguments have an overlap of dimensions and therefor the union of * the position is not well defined */ public static Position union(Position left, Position right) { checkNotNull(left, "left position must not be null."); checkNotNull(right, "right position must not be null."); checkArgument(Sets.intersection(left.dimensionSet(), right.dimensionSet()).isEmpty(), "Positions have overlapping dimensions. It is not possible to create the union of them."); SetView<Object> coordinates = Sets.union(left.coordinates(), right.coordinates()); return Position.of(coordinates); } /** * Copies the given positions to a set, to be sure that each element is contained only once * * @param positions the positions, which shall be ensured that they are unique * @return a set of unique positions */ public static Set<Position> unique(Iterable<Position> positions) { return ImmutableSet.copyOf(positions); } /** * Factory method for a dimension stripper. * * @param dimensionsToStrip the dimensions which shall be stripped from the positions passed to the stripper. * @return a function object that can strip the given dimensions from positions. */ public static Positions.DimensionStripper stripping(final Set<? extends Class<?>> dimensionsToStrip) { return new Positions.DimensionStripper(dimensionsToStrip); } /** * Factory method for a dimension stripper with one dimension to strip only * * @param dimensionsToStrip the dimension to strip * @return a dimension stripper stripping exactly one dimension * @see #stripping(Set) */ public static Positions.DimensionStripper stripping(Class<?> dimensionsToStrip) { return new Positions.DimensionStripper(ImmutableSet.of(dimensionsToStrip)); } /** * Convenience delegation method to {@link #stripping(Class)}, for a bit more fluent syntax. * * @param dimensionsToStrip the dimension to strip * @return a dimension stripper stripping exactly one dimension * @see #stripping(Class) */ public static Positions.DimensionStripper strip(Class<?> dimensionsToStrip) { return stripping(dimensionsToStrip); } /** * A functional object to transform positions to other positions with the dimensions stripped as given in the * constructor. * * @author kaifox */ public static class DimensionStripper implements Function<Position, Position> { private final Set<? extends Class<?>> dimensionsToStrip; DimensionStripper(Set<? extends Class<?>> dimensionsToStrip) { this.dimensionsToStrip = ImmutableSet.copyOf(dimensionsToStrip); } @Override public Position apply(Position position) { Builder<Object> builder = ImmutableSet.builder(); for (Object coordinate : position.coordinates()) { if (!dimensionsToStrip.stream().anyMatch(dts -> dts.isInstance(coordinate))) { builder.add(coordinate); } } return Position.of(builder.build()); } public Position from(Position position) { return apply(position); } } /** * Checks if the given position is conform with the given coordinate and throws an exception, if not. * * @param position the position for which to check the consistency * @param dimensions the dimensions for which the conformity has to be verified. * @throws IllegalArgumentException if the position is not conform * @see Position#isConsistentWith(Set) */ public static void assertConsistentDimensions(Position position, Set<Class<?>> dimensions) { if (!position.isConsistentWith(dimensions)) { throw new IllegalArgumentException( "The given coordinates are not consistent with the dimensions of the tensor! position='" + position + "'; required dimensions='" + dimensions + "'."); } } /** * Searches if given position coordinates match acceptable dimensions. * * @param dimensions * @param position * @return */ public static boolean areDimensionsConsistentWithCoordinates(Set<Class<?>> dimensions, Position position) { if (position.coordinates().size() != dimensions.size()) { return false; } Preconditions.checkArgument(dimensions != null, "Argument '" + "dimensions" + "' must not be null!"); Set<Class<?>> positionCoordinatesToCheck = position.dimensionSet(); return areDimensionsConsistent(dimensions, positionCoordinatesToCheck); } public static boolean areDimensionsConsistent(Set<Class<?>> dimensions, Set<Class<?>> positionCoordinatesToCheck) { if (dimensions.equals(positionCoordinatesToCheck)) { return true; } for (Class<?> one : positionCoordinatesToCheck) { Coordinates.checkClassRelations(one, dimensions); } return true; } /** * Combines the both positions of the pair in such a way, that for each coordinate of the types given in the given * set of dimensions have to be * <ul> * <li>either present in both positions of the pair, and then have to be the same * <li>or be present in only one of the both positions * </ul> * * @param pair the pair, whose dimensions should be united * @param targetDimensions the dimension in which the positions shall be united * @return a new position, containing the coordinates of the pair, merged by the above rules */ /* Similar to union ... maybe to be unified at some point */ public static Position combineDimensions(PositionPair pair, Set<Class<?>> targetDimensions) { Position left = pair.left(); Position right = pair.right(); return combineDimensions(left, right, targetDimensions); } /** * Combines the both positions in such a way, that for each coordinate of the types given in the given set of * dimensions have to be * <ul> * <li>either present in both positions of the pair, and then have to be the same * <li>or be present in only one of the both positions * </ul> * * @param left the first of the two positions, whose dimensions should be united * @param right the second of the two positions whose dimensions should be combined * @param targetDimensions the dimension in which the positions shall be united * @return a new position, with the coordinates merged according to the above rules */ public static Position combineDimensions(Position left, Position right, Set<Class<?>> targetDimensions) { ImmutableSet.Builder<Object> builder = ImmutableSet.builder(); for (Class<?> dimension : targetDimensions) { Object leftCoordinate = left.coordinateFor(dimension); Object rightCoordinate = right.coordinateFor(dimension); if (Objects.equal(leftCoordinate, rightCoordinate) || oneIsNull(leftCoordinate, rightCoordinate)) { builder.add(MoreObjects.firstNonNull(leftCoordinate, rightCoordinate)); } else { throw new IllegalArgumentException("Coordinates for dimension '" + dimension + "' are neither the same in both positions (" + left + " and " + right + "), nor present only in one. Cannot consistently combine."); } } return Position.of(builder.build()); } public static <T> boolean oneIsNull(T left, T right) { return ((left == null) || (right == null)); } /** * Combines all position pairs into positions containing the given dimensions and returns a map from the combined * positions to the original position pairs. * * @param positionPairs the position pairs to combine the final positions * @param targetDimensions the dimensions in which to combine the positions * @return a map from the combined dimensions to the original pairs */ public static ImmutableSetMultimap<Position, PositionPair> combineAll(Set<PositionPair> positionPairs, Set<Class<?>> targetDimensions) { ImmutableSetMultimap.Builder<Position, PositionPair> builder = ImmutableSetMultimap.builder(); for (PositionPair pair : positionPairs) { builder.put(combineDimensions(pair, targetDimensions), pair); } return builder.build(); } public static Multimap<Position, Position> mapByStripping(Iterable<Position> positions, Set<Class<?>> dimensionsToStrip) { DimensionStripper stripper = stripping(dimensionsToStrip); ImmutableMultimap.Builder<Position, Position> builder = ImmutableMultimap.builder(); for (Position position : positions) { builder.put(stripper.apply(position), position); } return builder.build(); } /** * Extracts the provided class of the coordinate from the set of the positions. * * @param positions * @param ofClass a class of the coordinate to be extracted * @return a set of the extracted coordinates from provided positions */ public static <T> Set<T> coordinatesOfType(Set<Position> positions, Class<T> ofClass) { Set<T> toReturn = new HashSet<>(); for (Position onePosition : positions) { T coordinate = onePosition.coordinateFor(ofClass); if (coordinate != null) { toReturn.add(coordinate); } } return toReturn; } /** * Returns all positions which can be built from all combinations of the values of the given enum classes. * * @param enumClasses the enum classes from which to get the values from * @return positions containing all possible combinations of enum values */ @SafeVarargs public static final Iterable<Position> cartesianProduct(Class<? extends Enum<?>>... enumClasses) { return cartesianProduct(checkedToSet(enumClasses)); } /** * Returns one position for each value of the given enum. Functionally, this is equivalent to * {@link #cartesianProduct(Class...)} with only one class given. * * @param enumClass the class of the enum from which to take the values as coordinates * @return an iterable of positions, containing the values oif the given enum class as (one-dimensional) positions. */ public static final Iterable<Position> from(Class<? extends Enum<?>> enumClass) { return cartesianProduct(enumClass); } /** * Returns all positions which can be built from the values of the passed in classes that are assumed to be enum * classes. This is basically the runtime-checked version of {@link #cartesianProduct(Class...)} * * @param enumClasses the enum classes from which to get their values * @return an iterable containing the positions which are constructed from the values of the enums * @throws IllegalArgumentException in case not all clases are enums */ public static final Iterable<Position> cartesianEnumProduct(Class<?>... enumClasses) { return cartesianEnumProduct(checkedToSet(enumClasses)); } /** * Returns all positions which can be built from all combinations of the values of the given enum classes. * * @param enumClasses the enums whose values will be used to create the positions * @return an iterable with positions containing all possible combinations of the enum values */ public static Iterable<Position> cartesianProduct(Set<Class<? extends Enum<?>>> enumClasses) { List<Set<?>> valueSets = enumClasses.stream().map(c -> ImmutableSet.copyOf(c.getEnumConstants())) .collect(Collectors.toList()); return cartesianProduct(valueSets); } /** * Returns all positions which can be built from the values of the passed in classes that are assumed to be enum * classes. This is basically the runtime-checked version of {@link #cartesianProduct(Set)} * * @param classes the enum classes from which to get their values * @return an iterable containing the positions which are constructed from the values of the enums * @throws IllegalArgumentException in case not all clases are enums */ public static Iterable<Position> cartesianEnumProduct(Set<Class<?>> classes) { return cartesianProduct(checkedToEnumClassSet(classes)); } private static Set<Class<? extends Enum<?>>> checkedToEnumClassSet(Set<Class<?>> classes) { Set<Class<? extends Enum<?>>> enumClasses = new HashSet<>(); for (Class<?> aClass : classes) { if (!aClass.isEnum()) { throw new IllegalArgumentException( "All provided classes have to be enum classes. However (at least) " + aClass.getCanonicalName() + "is not!"); } @SuppressWarnings("unchecked") Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) aClass; enumClasses.add(enumClass); } return enumClasses; } private static <T> Set<T> checkedToSet(T[] enumClasses) { Set<T> classesSet = ImmutableSet.copyOf(enumClasses); if (classesSet.size() != enumClasses.length) { throw new IllegalArgumentException("The number of passed in classes is " + enumClasses.length + ", but there seem to be only " + classesSet.size() + "different ones."); } return classesSet; } private static Iterable<Position> cartesianProduct(List<Set<?>> coordinateSets) { Set<List<Object>> cartesianProduct = Sets.cartesianProduct(ImmutableList.copyOf(coordinateSets)); return cartesianProduct.stream().map(l -> Position.of(new HashSet<>(l))).collect(toSet()); } /** * Returns a position which contains the coordinates which are contained in the left position but not in the right * position. The right position might also contain coordinates not contained in the left position, which are simply * ignored. * * @param left the position from which the coordinates of the right position shall be substracted * @param right the position whose coordinates shall be substracted from the left position * @return a position containing all coordinates from the left position, which are not present in the right position */ public static final Position difference(Position left, Position right) { SetView<?> diffCoordinates = Sets.difference(left.coordinates(), right.coordinates()); return Position.of(diffCoordinates); } }