Java tutorial
/* * Copyright (C) 2010-2015, Danilo Pianini and contributors * listed in the project's pom.xml file. * * This file is part of Alchemist, and is distributed under the terms of * the GNU General Public License, with a linking exception, as described * in the file LICENSE in the Alchemist distribution's top directory. */ package it.unibo.alchemist.language.protelis.util; import static com.google.common.collect.ImmutableList.of; import static java.lang.Double.NEGATIVE_INFINITY; import static java.lang.Double.NaN; import static java.lang.Double.POSITIVE_INFINITY; import static org.apache.commons.math3.util.Pair.create; import it.unibo.alchemist.language.protelis.datatype.Field; import it.unibo.alchemist.language.protelis.datatype.Tuple; import it.unibo.alchemist.language.protelis.datatype.Tuples; import it.unibo.alchemist.language.protelis.java7.functionals.BiFunction; import it.unibo.alchemist.language.protelis.java7.functionals.BinaryOperator; import it.unibo.alchemist.language.protelis.java7.functionals.Function; import it.unibo.alchemist.language.protelis.java7.functionals.Supplier; import java.util.Arrays; import java.util.List; import org.apache.commons.math3.util.Pair; /** * @author Danilo Pianini * */ public enum HoodOp { /** * Minimum. */ MIN(new BiFunction<Field, DeviceUID, Object>() { @Override public Object apply(Field f, DeviceUID n) { return HoodOp.min(f, n); } }, new Supplier<Object>() { @Override public Object get() { return POSITIVE_INFINITY; } }, (List) of(create(Number.class, new Supplier<Object>() { @Override public Object get() { return POSITIVE_INFINITY; } })), (List) of(create(Tuple.class, new Function<Object, Object>() { @Override public Object apply(Object t) { return fTup(POSITIVE_INFINITY, (Tuple) t); } }))), /** * Maximum. */ MAX(new BiFunction<Field, DeviceUID, Object>() { @Override public Object apply(Field f, DeviceUID n) { return HoodOp.max(f, n); } }, new Supplier<Object>() { @Override public Object get() { return NEGATIVE_INFINITY; } }, (List) of(create(Number.class, new Supplier<Object>() { @Override public Object get() { return NEGATIVE_INFINITY; } })), (List) of(create(Tuple.class, new Function<Object, Object>() { @Override public Object apply(Object t) { return fTup(NEGATIVE_INFINITY, (Tuple) t); } }))), /** * Any value. */ ANY(new BiFunction<Field, DeviceUID, Object>() { @Override public Object apply(Field f, DeviceUID n) { return HoodOp.any(f, n); } }, new Supplier<Object>() { @Override public Object get() { return HoodOp.no(); } }, (List) of(create(Boolean.class, new Supplier<Object>() { @Override public Object get() { return false; } })), (List) of()), /** * All values. */ ALL(new BiFunction<Field, DeviceUID, Object>() { @Override public Object apply(Field f, DeviceUID n) { return HoodOp.all(f, n); } }, new Supplier<Object>() { @Override public Object get() { return HoodOp.no(); } }, (List) of(create(Boolean.class, new Supplier<Object>() { @Override public Object get() { return true; } })), (List) of()), /** * Mean of values. */ MEAN(new BiFunction<Field, DeviceUID, Object>() { @Override public Object apply(Field f, DeviceUID n) { return HoodOp.mean(f, n); } }, new Supplier<Object>() { @Override public Object get() { return NaN; } }, (List) of(create(Number.class, new Supplier<Object>() { @Override public Object get() { return NaN; } })), (List) of(create(Tuple.class, new Function<Object, Object>() { @Override public Object apply(Object t) { return fTup(NaN, (Tuple) t); } }))), /** * Sum of values. */ SUM(new BiFunction<Field, DeviceUID, Object>() { @Override public Object apply(Field f, DeviceUID n) { return HoodOp.sum(f, n); } }, new Supplier<Object>() { @Override public Object get() { return 0d; } }, (List) of(create(Number.class, new Supplier<Object>() { @Override public Object get() { return 0d; } })), (List) of(create(Tuple.class, new Function<Object, Object>() { @Override public Object apply(Object t) { return fTup(0d, (Tuple) t); } }))), /** * Union of values. */ UNION(new BiFunction<Field, DeviceUID, Object>() { @Override public Object apply(Field f, DeviceUID n) { return HoodOp.union(f, n); } }, new Supplier<Object>() { @Override public Object get() { return Tuples.create(new Object[0]); } }, (List) of(create(Object.class, new Supplier<Object>() { @Override public Object get() { return Tuples.create(new Object[0]); } })), (List) of()); private final BiFunction<Field, DeviceUID, Object> f; private final Function<Field, Object> defs; /** * @param fun * @param empty * function that generates a default in case of empty field * @param suppliers * list of pairs mapping classes to 0-ary functions that provide * a default * @param cloners * list of pairs mapping classes to 1-ary functions that, given * an element of the field as input, provide a comparison. Such * functions are used in case there is no supplier that can * provide a specific value-agnostic default */ private HoodOp(final BiFunction<Field, DeviceUID, Object> fun, final Supplier<Object> empty, final List<Pair<Class<?>, Supplier<Object>>> suppliers, final List<Pair<Class<?>, Function<Object, Object>>> cloners) { f = fun; defs = new Function<Field, Object>() { @Override public Object apply(Field field) { /* * Field empty: generate a default. */ if (field.isEmpty()) { return empty.get(); } final Class<?> type = field.getExpectedType(); for (Pair<Class<?>, Supplier<Object>> sup : suppliers) { if (sup.getFirst().isAssignableFrom(type)) { /* * Field has compatible type */ return sup.getSecond().get(); } } for (Pair<Class<?>, Function<Object, Object>> cloner : cloners) { if (cloner.getFirst().isAssignableFrom(type)) { return cloner.getSecond().apply(field.valIterator().iterator().next()); } } return no(type); } }; } private <T> T no(final Class<?> c) { throw new UnsupportedOperationException(this + " cannot compute on " + c); } private static Object no() { throw new UnsupportedOperationException("Unsupported operation on empty fields."); } private static Tuple fTup(final Object defVal, final Tuple in) { return cTup(defVal, in.size()); } private static Tuple cTup(final Object v, final int size) { final Object[] r = new Object[size]; Arrays.fill(r, v); return Tuples.create(r); } /** * @param reducer the desired operator * @return the corresponding {@link HoodOp} */ public static HoodOp get(final String reducer) { for (HoodOp ho : values()) { if (ho.name().equalsIgnoreCase(reducer)) { return ho; } } return null; } /** * @param o * the field * @param n * the node on which the field is sampled * @return the Object resulting in the hood application */ public Object run(final Field o, final DeviceUID n) { return f.apply(o, n); } private static Object min(final Field f, final DeviceUID n) { return f.reduceVals(Op2.MIN.getFunction(), n, MIN.defs.apply(f)); } private static Object max(final Field f, final DeviceUID n) { return f.reduceVals(Op2.MAX.getFunction(), n, MAX.defs.apply(f)); } private static Object any(final Field f, final DeviceUID n) { return f.reduceVals(Op2.OR.getFunction(), n, ANY.defs.apply(f)); } private static Object all(final Field f, final DeviceUID n) { return f.reduceVals(Op2.AND.getFunction(), n, ALL.defs.apply(f)); } private static Object sum(final Field f, final DeviceUID n) { return f.reduceVals(Op2.PLUS.getFunction(), n, SUM.defs.apply(f)); } private static Object mean(final Field f, final DeviceUID n) { if (f.isEmpty()) { return Double.NaN; } return Op2.DIVIDE.getFunction().apply(sum(f, n), f.size()); } private static Object union(final Field f, final DeviceUID n) { return f.reduceVals(new BinaryOperator<Object>() { @Override public Object apply(Object a, Object b) { final Tuple at = a instanceof Tuple ? (Tuple) a : Tuples.create(a); final Tuple bt = b instanceof Tuple ? (Tuple) b : Tuples.create(b); return Tuples.union(at, bt); } }, n, UNION.defs.apply(f)); } }