diff --git a/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.java b/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.java index e8cb4b250..ec2f21a27 100644 --- a/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.java +++ b/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.java @@ -45,13 +45,17 @@ * that operate on {@link Iterable}s of types. N.B. it is the user's * responsibility to pass {@link Iterable}s of the same length (otherwise the Op * will stop when one of the {@link Iterable}s runs out of {@link Object}s). - * + *

+ * Note the use of generic types for each of the {@link Iterable}s in the output + * Ops. This is particularly useful for matching the Ops themselves, outside of + * adaptation. + *

* @author Gabriel Selzer */ -public class ComputerToIterables implements OpCollection { +public class ComputerToIterables, II1 extends Iterable, II2 extends Iterable, II3 extends Iterable, II4 extends Iterable, II5 extends Iterable, II6 extends Iterable, II7 extends Iterable, II8 extends Iterable, II9 extends Iterable, II10 extends Iterable, II11 extends Iterable, II12 extends Iterable, II13 extends Iterable, II14 extends Iterable, II15 extends Iterable, II16 extends Iterable, IO extends Iterable> implements OpCollection { @OpField(names = "engine.adapt") - public final Function, Computers.Arity0>> liftComputer0 = + public final Function, Computers.Arity0> liftComputer0 = (computer) -> { return (out) -> { var itrout = out.iterator(); @@ -62,7 +66,7 @@ public class ComputerToIterables, Computers.Arity1, Iterable>> liftComputer1 = + public final Function, Computers.Arity1> liftComputer1 = (computer) -> { return (in, out) -> { var itrin = in.iterator(); @@ -74,7 +78,7 @@ public class ComputerToIterables, Computers.Arity2, Iterable, Iterable>> liftComputer2 = + public final Function, Computers.Arity2> liftComputer2 = (computer) -> { return (in1, in2, out) -> { var itrin1 = in1.iterator(); @@ -87,7 +91,7 @@ public class ComputerToIterables, Computers.Arity3, Iterable, Iterable, Iterable>> liftComputer3 = + public final Function, Computers.Arity3> liftComputer3 = (computer) -> { return (in1, in2, in3, out) -> { var itrin1 = in1.iterator(); @@ -101,7 +105,7 @@ public class ComputerToIterables, Computers.Arity4, Iterable, Iterable, Iterable, Iterable>> liftComputer4 = + public final Function, Computers.Arity4> liftComputer4 = (computer) -> { return (in1, in2, in3, in4, out) -> { var itrin1 = in1.iterator(); @@ -116,7 +120,7 @@ public class ComputerToIterables, Computers.Arity5, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer5 = + public final Function, Computers.Arity5> liftComputer5 = (computer) -> { return (in1, in2, in3, in4, in5, out) -> { var itrin1 = in1.iterator(); @@ -132,7 +136,7 @@ public class ComputerToIterables, Computers.Arity6, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer6 = + public final Function, Computers.Arity6> liftComputer6 = (computer) -> { return (in1, in2, in3, in4, in5, in6, out) -> { var itrin1 = in1.iterator(); @@ -149,7 +153,7 @@ public class ComputerToIterables, Computers.Arity7, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer7 = + public final Function, Computers.Arity7> liftComputer7 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, out) -> { var itrin1 = in1.iterator(); @@ -167,7 +171,7 @@ public class ComputerToIterables, Computers.Arity8, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer8 = + public final Function, Computers.Arity8> liftComputer8 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, out) -> { var itrin1 = in1.iterator(); @@ -186,7 +190,7 @@ public class ComputerToIterables, Computers.Arity9, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer9 = + public final Function, Computers.Arity9> liftComputer9 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, out) -> { var itrin1 = in1.iterator(); @@ -206,7 +210,7 @@ public class ComputerToIterables, Computers.Arity10, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer10 = + public final Function, Computers.Arity10> liftComputer10 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, out) -> { var itrin1 = in1.iterator(); @@ -227,7 +231,7 @@ public class ComputerToIterables, Computers.Arity11, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer11 = + public final Function, Computers.Arity11> liftComputer11 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, out) -> { var itrin1 = in1.iterator(); @@ -249,7 +253,7 @@ public class ComputerToIterables, Computers.Arity12, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer12 = + public final Function, Computers.Arity12> liftComputer12 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, out) -> { var itrin1 = in1.iterator(); @@ -272,7 +276,7 @@ public class ComputerToIterables, Computers.Arity13, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer13 = + public final Function, Computers.Arity13> liftComputer13 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, out) -> { var itrin1 = in1.iterator(); @@ -296,7 +300,7 @@ public class ComputerToIterables, Computers.Arity14, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer14 = + public final Function, Computers.Arity14> liftComputer14 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, out) -> { var itrin1 = in1.iterator(); @@ -321,7 +325,7 @@ public class ComputerToIterables, Computers.Arity15, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer15 = + public final Function, Computers.Arity15> liftComputer15 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15, out) -> { var itrin1 = in1.iterator(); @@ -347,7 +351,7 @@ public class ComputerToIterables, Computers.Arity16, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftComputer16 = + public final Function, Computers.Arity16> liftComputer16 = (computer) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15, in16, out) -> { var itrin1 = in1.iterator(); diff --git a/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.java b/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.java index 368ee2bd9..47f6ed6b7 100644 --- a/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.java +++ b/scijava-ops-engine/src/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.java @@ -48,122 +48,126 @@ * that operate on {@link Iterable}s of types. N.B. it is the user's * responsibility to pass {@link Iterable}s of the same length (otherwise the Op * will stop when one of the {@link Iterable}s runs out of {@link Object}s). - * + *

+ * Note the use of generic types for each of the {@link Iterable}s in the output + * Ops. This is particularly useful for matching the Ops themselves, outside of + * adaptation. + *

* @author Gabriel Selzer */ -public class FunctionToIterables implements OpCollection { +public class FunctionToIterables, II1 extends Iterable, II2 extends Iterable, II3 extends Iterable, II4 extends Iterable, II5 extends Iterable, II6 extends Iterable, II7 extends Iterable, II8 extends Iterable, II9 extends Iterable, II10 extends Iterable, II11 extends Iterable, II12 extends Iterable, II13 extends Iterable, II14 extends Iterable, II15 extends Iterable, II16 extends Iterable, IO extends Iterable> implements OpCollection { // NOTE: we cannot convert Producers since there is no way to determine the // length of the output Iterable @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Function, Iterable>> liftFunction1 = + public final Function, Function>> liftFunction1 = (function) -> { return (in1) -> lazyIterable(itrs -> function.apply((I) itrs[0].next()), in1); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, BiFunction, Iterable, Iterable>> liftFunction2 = + public final Function, BiFunction>> liftFunction2 = (function) -> { return (in1, in2) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next()), in1, in2); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity3, Iterable, Iterable, Iterable>> liftFunction3 = + public final Function, Functions.Arity3>> liftFunction3 = (function) -> { return (in1, in2, in3) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next()), in1, in2, in3); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity4, Iterable, Iterable, Iterable, Iterable>> liftFunction4 = + public final Function, Functions.Arity4>> liftFunction4 = (function) -> { return (in1, in2, in3, in4) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next()), in1, in2, in3, in4); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity5, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction5 = + public final Function, Functions.Arity5>> liftFunction5 = (function) -> { return (in1, in2, in3, in4, in5) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next()), in1, in2, in3, in4, in5); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity6, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction6 = + public final Function, Functions.Arity6>> liftFunction6 = (function) -> { return (in1, in2, in3, in4, in5, in6) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next()), in1, in2, in3, in4, in5, in6); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity7, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction7 = + public final Function, Functions.Arity7>> liftFunction7 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next()), in1, in2, in3, in4, in5, in6, in7); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity8, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction8 = + public final Function, Functions.Arity8>> liftFunction8 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next()), in1, in2, in3, in4, in5, in6, in7, in8); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity9, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction9 = + public final Function, Functions.Arity9>> liftFunction9 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity10, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction10 = + public final Function, Functions.Arity10>> liftFunction10 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next(), (I10) itrs[9].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9, in10); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity11, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction11 = + public final Function, Functions.Arity11>> liftFunction11 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next(), (I10) itrs[9].next(), (I11) itrs[10].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity12, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction12 = + public final Function, Functions.Arity12>> liftFunction12 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next(), (I10) itrs[9].next(), (I11) itrs[10].next(), (I12) itrs[11].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity13, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction13 = + public final Function, Functions.Arity13>> liftFunction13 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next(), (I10) itrs[9].next(), (I11) itrs[10].next(), (I12) itrs[11].next(), (I13) itrs[12].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity14, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction14 = + public final Function, Functions.Arity14>> liftFunction14 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next(), (I10) itrs[9].next(), (I11) itrs[10].next(), (I12) itrs[11].next(), (I13) itrs[12].next(), (I14) itrs[13].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity15, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction15 = + public final Function, Functions.Arity15>> liftFunction15 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next(), (I10) itrs[9].next(), (I11) itrs[10].next(), (I12) itrs[11].next(), (I13) itrs[12].next(), (I14) itrs[13].next(), (I15) itrs[14].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15); }; @SuppressWarnings("unchecked") @OpField(names = "engine.adapt") - public final Function, Functions.Arity16, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable, Iterable>> liftFunction16 = + public final Function, Functions.Arity16>> liftFunction16 = (function) -> { return (in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15, in16) -> lazyIterable(itrs -> function.apply((I1) itrs[0].next(), (I2) itrs[1].next(), (I3) itrs[2].next(), (I4) itrs[3].next(), (I5) itrs[4].next(), (I6) itrs[5].next(), (I7) itrs[6].next(), (I8) itrs[7].next(), (I9) itrs[8].next(), (I10) itrs[9].next(), (I11) itrs[10].next(), (I12) itrs[11].next(), (I13) itrs[12].next(), (I14) itrs[13].next(), (I15) itrs[14].next(), (I16) itrs[15].next()), in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15, in16); }; diff --git a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.list b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.list index a76145e4d..66c423e16 100644 --- a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.list +++ b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.list @@ -5,12 +5,14 @@ arities = (1..maxArity).collect() iterableGenerics = ``` { arity -> - '<' + String.join(', ', genericParamTypes(arity).stream().map{a -> 'Iterable<' + a + '>'}.collect()) + '>' + '<' + String.join(', ', genericParamTypes(arity).stream().map{a -> 'I' + a}.collect()) + '>' } ``` classGenerics = ``` { arity -> - '' + gpt = genericParamTypes(arity) + itr_gpt = gpt.stream().map{a -> 'I' + a + ' extends Iterable<' + a + '>'}.collect() + ', ' + String.join(', ', itr_gpt) + '>' } ``` iteratorsHaveNext = ``` diff --git a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.vm b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.vm index 62b66bc64..143dadabb 100644 --- a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.vm +++ b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/ComputerToIterables.vm @@ -17,7 +17,11 @@ import org.scijava.ops.spi.OpCollection; * that operate on {@link Iterable}s of types. N.B. it is the user's * responsibility to pass {@link Iterable}s of the same length (otherwise the Op * will stop when one of the {@link Iterable}s runs out of {@link Object}s). - * + *

+ * Note the use of generic types for each of the {@link Iterable}s in the output + * Ops. This is particularly useful for matching the Ops themselves, outside of + * adaptation. + *

* @author Gabriel Selzer */ public class ComputerToIterables$classGenerics.call($maxArity) implements OpCollection { diff --git a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.list b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.list index bd8ef86e0..bb712524b 100644 --- a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.list +++ b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.list @@ -5,12 +5,16 @@ arities = (1..maxArity).collect() iterableGenerics = ``` { arity -> - '<' + String.join(', ', genericParamTypes(arity).stream().map{a -> 'Iterable<' + a + '>'}.collect()) + '>' + gpt = genericParamTypes(arity) + gpt.remove(gpt.size() - 1) + '<' + String.join(', ', gpt.stream().map{a -> 'I' + a}.collect()) + ', Iterable>' } ``` classGenerics = ``` { arity -> - '' + gpt = genericParamTypes(arity) + itr_gpt = gpt.stream().map{a -> 'I' + a + ' extends Iterable<' + a + '>'}.collect() + ', ' + String.join(', ', itr_gpt) + '>' } ``` iteratorsHaveNext = ``` diff --git a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.vm b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.vm index 8a2a9cec1..0835222ef 100644 --- a/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.vm +++ b/scijava-ops-engine/templates/main/java/org/scijava/ops/engine/adapt/lift/FunctionToIterables.vm @@ -20,7 +20,11 @@ import org.scijava.ops.spi.OpCollection; * that operate on {@link Iterable}s of types. N.B. it is the user's * responsibility to pass {@link Iterable}s of the same length (otherwise the Op * will stop when one of the {@link Iterable}s runs out of {@link Object}s). - * + *

+ * Note the use of generic types for each of the {@link Iterable}s in the output + * Ops. This is particularly useful for matching the Ops themselves, outside of + * adaptation. + *

* @author Gabriel Selzer */ public class FunctionToIterables$classGenerics.call($maxArity) implements OpCollection { diff --git a/scijava-ops-image/src/main/java/org/scijava/ops/image/create/Creators.java b/scijava-ops-image/src/main/java/org/scijava/ops/image/create/Creators.java index 79f11525d..f41444b66 100644 --- a/scijava-ops-image/src/main/java/org/scijava/ops/image/create/Creators.java +++ b/scijava-ops-image/src/main/java/org/scijava/ops/image/create/Creators.java @@ -54,6 +54,7 @@ import net.imglib2.type.logic.BitType; import net.imglib2.type.numeric.ComplexType; import net.imglib2.type.numeric.IntegerType; +import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.complex.ComplexDoubleType; import net.imglib2.type.numeric.complex.ComplexFloatType; import net.imglib2.type.numeric.integer.ByteType; @@ -72,6 +73,7 @@ import org.joml.Vector3f; import org.scijava.function.Functions; import org.scijava.function.Producer; +import org.scijava.ops.spi.OpDependency; public class Creators, L, I extends IntegerType, T extends Type, C extends ComplexType, W extends ComplexType & NativeType, B extends BooleanType, A extends ArrayDataAccess> { @@ -196,16 +198,19 @@ public class Creators, L, I extends IntegerType, T ex .factory(), img, img.firstElement()); /** - * @input interval - * @output img - * @implNote op names='create.img, engine.create', priority='-100.' + * @param typeCreator a {@link Producer} that knows how to create the resulting image type. + * @param interval the interval of the resulting {@link Img} + * @return an {@link Img} + * @implNote op names='create.img, engine.create', priority='-1000.' */ - public final Function> imgFromInterval = ( - interval) -> { - var type = new DoubleType(); + public static > Img imgFromInterval( // + @OpDependency(name="engine.create") Producer typeCreator, // + Interval interval // + ) { + var type = typeCreator.create(); return Imgs.create(Util.getSuitableImgFactory(interval, type), interval, - type); - }; + type); + } /** * @input arrayImg diff --git a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/AbstractApplyThresholdImg.java b/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/AbstractApplyThresholdImg.java index 5610b67d6..446b73017 100644 --- a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/AbstractApplyThresholdImg.java +++ b/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/AbstractApplyThresholdImg.java @@ -31,31 +31,58 @@ import java.util.function.Function; +import net.imglib2.RandomAccessibleInterval; import net.imglib2.histogram.Histogram1d; +import net.imglib2.type.logic.BitType; import net.imglib2.type.numeric.RealType; +import net.imglib2.util.Util; import org.scijava.function.Computers; import org.scijava.ops.spi.OpDependency; /** + * An abstract base class for Ops using a {@link Histogram1d} to compute a + * threshold across an {@link Iterable}. + *

+ * Note the use of type parameters {@code I} and {@code J}, allowing + * dependencies to be matched on the concrete input types instead of just on + * {@link Iterable} + *

+ * * @author Curtis Rueden * @author Christian Dietz (University of Konstanz) + * @author Gabriel Selzer + * @param the {@link RealType} implementation of input elements + * @param the {@link Iterable} subclass of the input + * @param the {@link Iterable} subclass of the output */ -public abstract class AbstractApplyThresholdImg> extends - AbstractApplyThresholdIterable -{ +public abstract class AbstractApplyThresholdImg< // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > implements Computers.Arity1 { @OpDependency(name = "image.histogram") - private Function, Histogram1d> createHistogramOp; + private Function> createHistogramOp; + @OpDependency(name = "threshold.apply") + private Computers.Arity2 applyThresholdOp; + + /** + * Thresholds {@code input}, storing the result in {@code output}. + * + * @param input the input dataset + * @param output the output dataset + */ @Override - protected T computeThreshold(final Iterable input) { + public void compute(final I input, final J output) { + // Compute the histogram final var inputHistogram = createHistogramOp.apply(input); + // Compute the threshold value from the histogram final var threshold = input.iterator().next().createVariable(); - final var computeThresholdOp = - getComputeThresholdOp(); - computeThresholdOp.compute(inputHistogram, threshold); - return threshold; + getComputeThresholdOp().compute(inputHistogram, threshold); + // Threshold the image against the computed value + applyThresholdOp.compute(input, threshold, output); } protected abstract Computers.Arity1, T> diff --git a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/AbstractApplyThresholdIterable.java b/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/AbstractApplyThresholdIterable.java deleted file mode 100644 index 7b079d4fa..000000000 --- a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/AbstractApplyThresholdIterable.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * #%L - * Image processing operations for SciJava Ops. - * %% - * Copyright (C) 2014 - 2024 SciJava developers. - * %% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * #L% - */ - -package org.scijava.ops.image.threshold; - -import net.imglib2.type.logic.BitType; - -import org.scijava.function.Computers; -import org.scijava.ops.spi.OpDependency; - -/** - * @author Curtis Rueden - * @author Christian Dietz (University of Konstanz) - */ -public abstract class AbstractApplyThresholdIterable implements - Computers.Arity1, Iterable> -{ - - @OpDependency(name = "threshold.apply") - private Computers.Arity2, T, Iterable> applyThresholdOp; - - /** - * TODO - * - * @param input - * @param output - */ - @Override - public void compute(final Iterable input, final Iterable output) { - applyThresholdOp.compute(input, computeThreshold(input), output); - } - - protected abstract T computeThreshold(Iterable input); -} diff --git a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/ApplyThresholdMethod.java b/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/ApplyThresholdMethod.java index 68031f8f3..9e6bdba2c 100644 --- a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/ApplyThresholdMethod.java +++ b/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/ApplyThresholdMethod.java @@ -30,6 +30,7 @@ package org.scijava.ops.image.threshold; import net.imglib2.histogram.Histogram1d; +import net.imglib2.type.logic.BitType; import net.imglib2.type.numeric.RealType; import org.scijava.function.Computers; @@ -51,9 +52,11 @@ private ApplyThresholdMethod() { /** * @implNote op names='threshold.huang' */ - public static class Huang> extends - AbstractApplyThresholdImg - { + public static class Huang < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.huang") private Computers.Arity1, T> computeThresholdOp; @@ -67,9 +70,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.ij1' */ - public static class IJ1> extends - AbstractApplyThresholdImg - { + public static class IJ1 < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.ij1") private Computers.Arity1, T> computeThresholdOp; @@ -83,9 +88,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.intermodes' */ - public static class Intermodes> extends - AbstractApplyThresholdImg - { + public static class Intermodes < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.intermodes") private Computers.Arity1, T> computeThresholdOp; @@ -99,9 +106,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.isoData' */ - public static class IsoData> extends - AbstractApplyThresholdImg - { + public static class IsoData < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.isoData") private Computers.Arity1, T> computeThresholdOp; @@ -115,9 +124,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.li' */ - public static class Li> extends - AbstractApplyThresholdImg - { + public static class Li < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.li") private Computers.Arity1, T> computeThresholdOp; @@ -131,9 +142,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.maxEntropy' */ - public static class MaxEntropy> extends - AbstractApplyThresholdImg - { + public static class MaxEntropy < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.maxEntropy") private Computers.Arity1, T> computeThresholdOp; @@ -147,9 +160,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.maxLikelihood' */ - public static class MaxLikelihood> extends - AbstractApplyThresholdImg - { + public static class MaxLikelihood < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.maxLikelihood") private Computers.Arity1, T> computeThresholdOp; @@ -163,9 +178,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.mean' */ - public static class Mean> extends - AbstractApplyThresholdImg - { + public static class Mean < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.mean") private Computers.Arity1, T> computeThresholdOp; @@ -179,9 +196,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.minError' */ - public static class MinError> extends - AbstractApplyThresholdImg - { + public static class MinError < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.minError") private Computers.Arity1, T> computeThresholdOp; @@ -195,9 +214,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.minimum' */ - public static class Minimum> extends - AbstractApplyThresholdImg - { + public static class Minimum < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.minimum") private Computers.Arity1, T> computeThresholdOp; @@ -211,9 +232,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.moments' */ - public static class Moments> extends - AbstractApplyThresholdImg - { + public static class Moments < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.moments") private Computers.Arity1, T> computeThresholdOp; @@ -227,9 +250,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.otsu' */ - public static class Otsu> extends - AbstractApplyThresholdImg - { + public static class Otsu < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.otsu") private Computers.Arity1, T> computeThresholdOp; @@ -243,9 +268,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.percentile' */ - public static class Percentile> extends - AbstractApplyThresholdImg - { + public static class Percentile < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.percentile") private Computers.Arity1, T> computeThresholdOp; @@ -259,9 +286,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.renyiEntropy' */ - public static class RenyiEntropy> extends - AbstractApplyThresholdImg - { + public static class RenyiEntropy < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.renyiEntropy") private Computers.Arity1, T> computeThresholdOp; @@ -275,9 +304,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.rosin' */ - public static class Rosin> extends - AbstractApplyThresholdImg - { + public static class Rosin < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.rosin") private Computers.Arity1, T> computeThresholdOp; @@ -291,9 +322,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.shanbhag' */ - public static class Shanbhag> extends - AbstractApplyThresholdImg - { + public static class Shanbhag < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.shanbhag") private Computers.Arity1, T> computeThresholdOp; @@ -307,9 +340,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.triangle' */ - public static class Triangle> extends - AbstractApplyThresholdImg - { + public static class Triangle < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.triangle") private Computers.Arity1, T> computeThresholdOp; @@ -323,9 +358,11 @@ protected Computers.Arity1, T> getComputeThresholdOp() { /** * @implNote op names='threshold.yen' */ - public static class Yen> extends - AbstractApplyThresholdImg - { + public static class Yen < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > extends AbstractApplyThresholdImg { // @OpDependency(name = "threshold.yen") private Computers.Arity1, T> computeThresholdOp; diff --git a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/apply/ApplyConstantThreshold.java b/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/apply/ApplyConstantThreshold.java index c45f1bc7c..f52d576ee 100644 --- a/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/apply/ApplyConstantThreshold.java +++ b/scijava-ops-image/src/main/java/org/scijava/ops/image/threshold/apply/ApplyConstantThreshold.java @@ -33,6 +33,7 @@ import java.util.function.Function; import org.scijava.function.Computers; +import org.scijava.ops.spi.Nullable; import org.scijava.ops.spi.OpDependency; import net.imglib2.type.logic.BitType; @@ -46,69 +47,46 @@ * @author Christian Dietz (University of Konstanz) * @implNote op names='threshold.apply' */ -public class ApplyConstantThreshold> implements - Computers.Arity3, T, Comparator, Iterable> +public class ApplyConstantThreshold < // + T extends RealType, // + I extends Iterable, // + J extends Iterable // + > implements Computers.Arity3, J> { @OpDependency(name = "threshold.apply") Computers.Arity3, BitType> applyThreshold; + // NB we lift manually in this Op because it's much more likely to find optimized + // lifters for Computers.Arity1 than it is to find optimized lifters + // that can handle the threshold and value as parameters. @OpDependency(name = "engine.adapt") - Function, Computers.Arity1, Iterable>> lifter; + Function, Computers.Arity1> lifter; - // TODO can/should the Comparator be of instead of just ? - /** - * TODO - * - * @param input - * @param threshold - * @param comparator - * @param output - */ - @Override - public void compute(final Iterable input, final T threshold, - final Comparator comparator, final Iterable output) - { - Computers.Arity1 thresholdComputer = (in, out) -> applyThreshold - .compute(in, threshold, comparator, out); - var liftedThreshold = lifter - .apply(thresholdComputer); - liftedThreshold.accept(input, output); - } + private final Comparator DEFAULT = Comparable::compareTo; -} - -// -- CONVENIENCE OPS -- // - -// If people don't want to / don't know how to make a comparator, they can just -// use this Op. The default comparator just returns true if the input is greater -// than the threshold. -/** - * TODO: Remove in favor of a nullable parameter on the Op above - * - * @implNote op names='threshold.apply' - */ -class ApplyConstantThresholdSimple> implements - Computers.Arity2, T, Iterable> -{ - - @OpDependency(name = "threshold.apply") - Computers.Arity3, T, Comparator, Iterable> applyThreshold; - - // TODO can/should the Comparator be of instead of just ? /** - * TODO + * Thresholds each input value against the threshold, optionally using a + * custom comparator. * - * @param input - * @param threshold - * @param output + * @param input the input data + * @param threshold the threshold value + * @param comparator defines whether the input is above or below the + * threshold. If not provided, {@link Comparable#compareTo} + * will be used. + * @param output a preallocated output buffer */ @Override - public void compute(final Iterable input, final T threshold, - final Iterable output) - { - - applyThreshold.compute(input, threshold, Comparable::compareTo, output); + public void compute( // + final I input, // + final T threshold, // + final @Nullable Comparator comparator, // + final J output // + ) { + final Comparator comp = comparator != null ? comparator : DEFAULT; + Computers.Arity1 thresholdComputer = // + (in, out) -> applyThreshold.compute(in, threshold, comp, out); + lifter.apply(thresholdComputer).compute(input, output); } } diff --git a/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/ComputeThresholdTest.java b/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/ComputeThresholdTest.java index 5382a399e..5c7e32f1e 100644 --- a/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/ComputeThresholdTest.java +++ b/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/ComputeThresholdTest.java @@ -199,9 +199,7 @@ private void testComputeThresholdOp(final int expectedOutput, private Computers.Arity1, UnsignedShortType> getComputeThresholdOp(final String name) { - return OpBuilder.matchComputer(ops, name, - new Nil>() - {}, new Nil() {}); + return OpBuilder.matchComputer(ops, name, new Nil<>() {}, new Nil<>() {}); } } diff --git a/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/apply/ApplyManualThresholdTest.java b/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/apply/ApplyConstantThresholdTest.java similarity index 59% rename from scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/apply/ApplyManualThresholdTest.java rename to scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/apply/ApplyConstantThresholdTest.java index 1556786e5..4fc45d47d 100644 --- a/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/apply/ApplyManualThresholdTest.java +++ b/scijava-ops-image/src/test/java/org/scijava/ops/image/threshold/apply/ApplyConstantThresholdTest.java @@ -29,41 +29,63 @@ package org.scijava.ops.image.threshold.apply; +import java.util.ArrayList; import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import net.imglib2.RandomAccessibleInterval; +import org.junit.jupiter.api.Assertions; +import org.scijava.ops.api.OpMatchingException; import org.scijava.ops.image.threshold.AbstractThresholdTest; import net.imglib2.exception.IncompatibleTypeException; -import net.imglib2.img.Img; import net.imglib2.type.logic.BitType; import net.imglib2.type.numeric.integer.UnsignedShortType; import org.junit.jupiter.api.Test; -import org.scijava.function.Computers; -import org.scijava.ops.api.OpBuilder; import org.scijava.types.Nil; /** - * Tests {@link ApplyManualThreshold}. + * Tests {@link ApplyConstantThreshold} and its wrappers. * * @author Curtis Rueden + * @author Gabriel Selzer */ -public class ApplyManualThresholdTest extends AbstractThresholdTest { +public class ApplyConstantThresholdTest extends AbstractThresholdTest { @Test public void testApplyThreshold() throws IncompatibleTypeException { - Computers.Arity3, UnsignedShortType, Comparator, Iterable> createFunc = - OpBuilder.matchComputer(ops, "threshold.apply", - new Nil>() - {}, new Nil() {}, - new Nil>() - {}, new Nil>() {}); - - final Img out = bitmap(); - final UnsignedShortType threshold = new UnsignedShortType(30000); - Comparator comparator = (c1, c2) -> (int) Math.ceil(c1 - .getRealDouble() - c2.getRealDouble()); - createFunc.compute(in, threshold, comparator, out); + final var out = bitmap(); + final var threshold = new UnsignedShortType(30000); + final Comparator comparator = // + (c1, c2) -> (int) Math.ceil(c1 .getRealDouble() - c2.getRealDouble()); + ops.op("threshold.apply").input(in, threshold, comparator).output(out).compute(); assertCount(out, 54); } + @Test + public void testApplyThresholdRAIs() { + // Test as Computer + final var buffer = bitmap(); + Assertions.assertDoesNotThrow(() -> ops.op("threshold.mean") // + .input(in) // + .output(buffer) // + .compute()); + // Test as Function + Assertions.assertDoesNotThrow(() -> ops.op("threshold.mean") // + .input(in) // + .apply()); + } + + @Test + public void testApplyThresholdIterables() { + List itr = in.stream().collect(Collectors.toList()); + List output = new ArrayList<>(itr.size()); + + ops.op("threshold.mean") // + .input(in) // + .output(output) // + .compute(); + } + }