Skip to content

Commit 1bd7b19

Browse files
gselzerctrueden
authored andcommitted
Op transformation: breadth-first searching
This is better than depth-first because it provides the shortest possible transformation
1 parent 9dc6f1b commit 1bd7b19

4 files changed

Lines changed: 58 additions & 34 deletions

File tree

src/main/java/org/scijava/ops/OpService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ public Object findOpInstance(final String opName, final OpRef ref) {
319319

320320
// If we can't find an op matching the original request, we try to find a
321321
// transformation
322-
transformation = transformer.findTransfromation(this, ref);
322+
transformation = transformer.findTransformation(this, ref);
323323
if (transformation == null) {
324324
log.debug("No matching Op transformation found");
325325
throw new IllegalArgumentException(e);

src/main/java/org/scijava/ops/transform/DefaultOpTransformerService.java

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434

3535
import java.util.ArrayList;
3636
import java.util.Collection;
37+
import java.util.LinkedList;
3738
import java.util.List;
39+
import java.util.stream.Collectors;
3840

3941
import org.scijava.ops.OpEnvironment;
4042
import org.scijava.ops.matcher.OpCandidate;
@@ -59,16 +61,18 @@ public final class DefaultOpTransformerService extends AbstractSingletonService<
5961
@Parameter
6062
private OpTypeMatchingService matcher;
6163

64+
private final int maxTransformations = 2;
65+
6266
@Override
63-
public List<OpTransformation> getTansformationsTo(OpRef toRef) {
67+
public List<OpTransformation> getTransformationsTo(OpRef toRef, int currentChainLength) {
6468
List<OpTransformation> transforms = new ArrayList<>();
6569

6670
for (OpTransformer ot: getInstances()) {
6771
final Collection<OpRef> fromRefs = ot.getRefsTransformingTo(toRef);
6872
if (fromRefs != null) {
6973
for (OpRef fromRef : fromRefs) {
7074
if (fromRef != null) {
71-
transforms.add(new OpTransformation(fromRef, toRef, ot));
75+
transforms.add(new OpTransformation(fromRef, toRef, ot, currentChainLength + 1));
7276
}
7377
}
7478
}
@@ -77,35 +81,27 @@ public List<OpTransformation> getTansformationsTo(OpRef toRef) {
7781
}
7882

7983
@Override
80-
public OpTransformationCandidate findTransfromation(OpEnvironment opEnv, OpRef ref) {
81-
List<OpTransformation> ts = getTansformationsTo(ref);
82-
for (OpTransformation t : ts) {
83-
OpTransformationCandidate match = findTransfromation(opEnv, t, 0);
84-
if (match != null) {
85-
return match;
86-
}
87-
}
88-
return null;
89-
}
90-
91-
private OpTransformationCandidate findTransfromation(OpEnvironment opEnv, OpTransformation candidate, int depth) {
92-
if (candidate == null || depth > 1) {
93-
return null;
94-
} else {
95-
OpRef fromRef = candidate.getSource();
84+
public OpTransformationCandidate findTransformation(OpEnvironment opEnv, OpRef ref) {
85+
LinkedList<OpTransformation> tsQueue = new LinkedList<>();
86+
tsQueue.addAll(getTransformationsTo(ref, 0));
87+
while (!tsQueue.isEmpty()) {
88+
OpTransformation t = tsQueue.pop();
89+
OpRef fromRef = t.getSource();
9690
try {
9791
OpCandidate match = matcher.findSingleMatch(opEnv, fromRef);
98-
return new OpTransformationCandidate(match, candidate);
92+
return new OpTransformationCandidate(match, t);
9993
} catch (OpMatchingException e) {
100-
List<OpTransformation> ts = getTansformationsTo(fromRef);
101-
for (OpTransformation t : ts) {
102-
OpTransformationCandidate cand = findTransfromation(opEnv, t.chain(candidate), depth + 1);
103-
if (cand != null) {
104-
return cand;
105-
}
106-
}
94+
// if we have done fewer than the maximum allowed number of transformations from
95+
// ref, find more transformations from t
96+
if (t.getChainLength() < maxTransformations)
97+
// we need to make sure chain all of these transformations to t, thus we map the
98+
// results of getTransformationsTo
99+
tsQueue.addAll(getTransformationsTo(fromRef, t.getChainLength())//
100+
.stream().map(next -> next.chain(t))//
101+
.collect(Collectors.toList()));
107102
}
108103
}
109104
return null;
110105
}
106+
111107
}

src/main/java/org/scijava/ops/transform/OpTransformation.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,25 @@ public class OpTransformation {
1717
private OpTransformer transformation;
1818

1919
private OpTransformation child;
20+
private int chainLength;
2021

21-
public OpTransformation(OpRef from, OpRef to, OpTransformer transformer) {
22+
/**
23+
* Constructor
24+
*
25+
* @param from
26+
* the OpRef we are transforming from
27+
* @param to
28+
* the OpRef we are transforming to
29+
* @param transformer
30+
* the OpTransformer that will take an Op with the fromRef signature
31+
* and transform it to the toRef signature
32+
* @param chainLength the length of the chain from what was originally requested to toRef
33+
*/
34+
public OpTransformation(OpRef from, OpRef to, OpTransformer transformer, int chainLength) {
2235
this.srcRef = from;
2336
this.targetRef = to;
2437
this.transformation = transformer;
38+
this.chainLength = chainLength;
2539
}
2640

2741
/**
@@ -59,6 +73,15 @@ public OpTransformer getTransformer() {
5973
public OpTransformation getChild() {
6074
return this.child;
6175
}
76+
77+
/**
78+
* Get the length of the transformation chain
79+
*
80+
* @return
81+
*/
82+
public int getChainLength() {
83+
return this.chainLength;
84+
}
6285

6386
/**
6487
* Executes this transformation on the specified object.

src/main/java/org/scijava/ops/transform/OpTransformerService.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,19 @@ default Class<OpTransformer> getPluginType() {
2121

2222
/**
2323
* Retrieve a list of {@link OpTransformation}s that describe a transformation
24-
* that is able to transform an Op matching an {@link OpRef} into another Op matching
25-
* the specified {@link OpRef}. This can be used to find Ops that are transformable
26-
* into the specified {@link OpRef}.
24+
* that is able to transform an Op matching an {@link OpRef} into another Op
25+
* matching the specified {@link OpRef}. This can be used to find Ops that are
26+
* transformable into the specified {@link OpRef}.
2727
*
28-
* @param opRef the ref which should be the target of the transformations to look for
28+
* @param opRef
29+
* the ref which should be the target of the transformations to look
30+
* for
31+
* @param currentChainLength
32+
* the number of transformations between the requested OpRef and the
33+
* passed argument
2934
* @return
3035
*/
31-
List<OpTransformation> getTansformationsTo (OpRef opRef);
36+
List<OpTransformation> getTransformationsTo (OpRef opRef, int currentChainLength);
3237

3338
/**
3439
* Attempts to find an {@link OpTransformationCandidate}, transforming an existing Op into another
@@ -44,5 +49,5 @@ default Class<OpTransformer> getPluginType() {
4449
* @param ref the ref which should be the target of the transformation to look for
4550
* @return
4651
*/
47-
OpTransformationCandidate findTransfromation(OpEnvironment opEnv, OpRef ref);
52+
OpTransformationCandidate findTransformation(OpEnvironment opEnv, OpRef ref);
4853
}

0 commit comments

Comments
 (0)