Skip to content

Commit d0b8baf

Browse files
committed
WIP: multi-stage transformations
1 parent 882b346 commit d0b8baf

File tree

1 file changed

+83
-66
lines changed

1 file changed

+83
-66
lines changed

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

Lines changed: 83 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.lang.reflect.TypeVariable;
3636
import java.util.ArrayList;
3737
import java.util.Arrays;
38+
import java.util.Collections;
3839
import java.util.Comparator;
3940
import java.util.EnumSet;
4041
import java.util.HashMap;
@@ -43,8 +44,6 @@
4344
import java.util.List;
4445
import java.util.Map;
4546
import java.util.Map.Entry;
46-
import java.util.PriorityQueue;
47-
import java.util.Queue;
4847
import java.util.function.Function;
4948
import java.util.stream.Collectors;
5049

@@ -61,10 +60,10 @@
6160
import org.scijava.ops.matcher.OpMatcher;
6261
import org.scijava.ops.matcher.OpMatchingException;
6362
import org.scijava.ops.matcher.OpRef;
64-
import org.scijava.ops.transform.AdaptedOp;
6563
import org.scijava.ops.transform.OpRunner;
6664
import org.scijava.ops.transform.OpTransformationMatcher;
6765
import org.scijava.ops.transform.OpTransformer;
66+
import org.scijava.ops.types.Any;
6867
import org.scijava.ops.types.Nil;
6968
import org.scijava.ops.types.TypeService;
7069
import org.scijava.ops.util.OpWrapper;
@@ -269,7 +268,7 @@ public <T> T findOpInstance(final String opName, final Nil<T> specialType, final
269268
public Object findOpInstance(final String opName, final OpRef ref, boolean adaptable) {
270269
Object op = null;
271270
OpCandidate match = null;
272-
AdaptedOp adaptation = null;
271+
OpAdaptor adaptation = null;
273272
try {
274273
// Find single match which matches the specified types
275274
match = getOpMatcher().findSingleMatch(this, ref);
@@ -282,8 +281,8 @@ public Object findOpInstance(final String opName, final OpRef ref, boolean adapt
282281
}
283282
log.debug("Attempting Op adaptation...");
284283
try {
285-
adaptation = adaptOp(opName, ref);
286-
op = adaptation.op();
284+
adaptation = adaptOp(ref);
285+
op = adaptation.getAdaptedOp();
287286
} catch (OpMatchingException e1) {
288287
log.debug("No suitable Op adaptation found");
289288
throw new IllegalArgumentException(e1);
@@ -305,82 +304,73 @@ public Object findOpInstance(final String opName, final OpRef ref, boolean adapt
305304
return wrappedOp;
306305
}
307306

308-
public AdaptedOp adaptOp(String opName, OpRef ref) throws OpMatchingException {
309-
307+
public OpAdaptor adaptOp(OpRef ref) throws OpMatchingException {
308+
310309
// TODO: support all types of ref
311310
// TODO: multi-stage adaptations (do we need this if we are not doing OpRunners
312311
// anymore?)
313312
// TODO: prevent searching for Op types that have already been searched for
314313
// TODO: export code to helper method.
315-
Type opType = ref.getTypes()[0];
316-
List<OpInfo> adaptors = opCache.get("adapt");
317-
318-
// create a priority queue to store suitable transformations.
319-
Comparator<OpAdaptor> comp = (OpAdaptor i1,
320-
OpAdaptor i2) -> i1.adaptorInfo().priority() < i2.adaptorInfo().priority() ? -1
321-
: i1.adaptorInfo().priority() == i2.adaptorInfo().priority() ? 0 : 1;
322-
Queue<OpAdaptor> suitableAdaptors = new PriorityQueue<>(comp);
323-
314+
324315
// create an OpCandidate list of suitable adaptors
325-
for (OpInfo adaptor : adaptors) {
326-
Type adaptTo = adaptor.output().getType();
327-
Map<TypeVariable<?>, Type> map = new HashMap<>();
328-
// make sure that the adaptor outputs the correct type
329-
if(opType instanceof ParameterizedType) {
330-
try {
331-
if(!MatchingUtils.checkGenericAssignability(adaptTo, (ParameterizedType) opType, map, true))
332-
continue;
333-
} catch(IllegalArgumentException e) {continue; }
334-
}
335-
else if (!Types.isAssignable(opType, adaptTo, map)) {
336-
continue;
337-
}
338-
// make sure that the adaptor is a Function (so we can cast it later)
339-
if (Types.isInstance(adaptor.opType(), Function.class)) {
340-
log.debug(adaptor + " is an illegal adaptor Op: must be a Function");
341-
continue;
342-
}
343-
// make an OpCandidate
344-
suitableAdaptors.add(new OpAdaptor(ref, adaptor, map, this, log));
345-
}
316+
Type blahadaptTo = ref.getTypes()[0];
317+
Type adaptFrom = new Any();
318+
Type refType = Types.parameterize(Function.class, new Type[] {adaptFrom, blahadaptTo});
319+
OpRef adaptorRef = new OpRef("adapt", new Type[] {refType}, blahadaptTo, new Type[] {adaptFrom});
320+
List<OpCandidate> adaptorCandidates = getOpMatcher().findCandidates(this, adaptorRef);
321+
Comparator<OpCandidate> comp = (OpCandidate i1,
322+
OpCandidate i2) -> i1.opInfo().priority() < i2.opInfo().priority() ? -1
323+
: i1.opInfo().priority() == i2.opInfo().priority() ? 0 : 1;
324+
Collections.sort(adaptorCandidates, comp);
325+
// Queue<OpAdaptor> suitableAdaptors = new PriorityQueue<>(comp);
326+
327+
// // create an OpCandidate list of suitable adaptors
328+
// for (OpInfo adaptor : adaptors) {
329+
// Type adaptTo = adaptor.output().getType();
330+
// Map<TypeVariable<?>, Type> map = new HashMap<>();
331+
// // make sure that the adaptor outputs the correct type
332+
// if(opType instanceof ParameterizedType) {
333+
// try {
334+
// if(!MatchingUtils.checkGenericAssignability(adaptTo, (ParameterizedType) opType, map, true))
335+
// continue;
336+
// } catch(IllegalArgumentException e) {continue; }
337+
// }
338+
// else if (!Types.isAssignable(opType, adaptTo, map)) {
339+
// continue;
340+
// }
341+
// // make sure that the adaptor is a Function (so we can cast it later)
342+
// if (Types.isInstance(adaptor.opType(), Function.class)) {
343+
// log.debug(adaptor + " is an illegal adaptor Op: must be a Function");
344+
// continue;
345+
// }
346+
// // make an OpCandidate
347+
// suitableAdaptors.add(new OpAdaptor(ref, adaptor, map, this, log));
348+
// }
346349

347-
while (suitableAdaptors.size() > 0) {
348-
OpAdaptor adaptor = suitableAdaptors.remove();
349-
Object adaptorOp;
350+
while (adaptorCandidates.size() > 0) {
351+
352+
OpAdaptor adaptor = new OpAdaptor(ref, suitableAdaptors.remove().opInfo(), ;
350353
// attempt to construct the adaptor
351354
// (N.B. we fail here if, for example, the adaptor cannot resolve its OpDependencies).
352355
try {
353-
adaptorOp = adaptor.constructAdaptor();
356+
adaptor.constructAdaptor();
354357
} catch (OpMatchingException e) {
355358
continue;
356359
}
357360
try {
358-
359-
// grab the first type parameter (from the OpCandidate?) and search for an Op
360-
// that will then be adapted (this will be the first (only) type in the args of
361-
// the adaptor)
362-
Type adaptFrom = adaptor.adaptorCandidate().paddedArgs()[0];
363-
final OpRef inferredRef = inferOpRef(adaptFrom, opName, adaptor.adaptorCandidate().typeVarAssigns());
364-
// TODO: export this to another function (also done in findOpInstance).
365-
// We need this here because we need to grab the OpInfo.
366-
// TODO: is there a better way to do this?
367-
final OpCandidate srcCandidate = getOpMatcher().findSingleMatch(this, inferredRef);
368-
final List<Object> srcDependencies = resolveOpDependencies(srcCandidate);
369-
final Object fromOp = srcCandidate.opInfo().createOpInstance(srcDependencies).object();
370-
371361
// get adapted Op by applying adaptor on unadapted Op, then return
372-
// TODO: can we make this safer?
373-
@SuppressWarnings("unchecked")
374-
Object toOp = ((Function<Object, Object>) adaptorOp).apply(fromOp);
375-
return new AdaptedOp(toOp, srcCandidate.opInfo(), adaptor.adaptorCandidate().opInfo());
362+
final Object fromOp = adaptor.constructSrcOp(ref.getName(), this);
363+
adaptor.executeAdaptation(fromOp);
364+
return adaptor;
376365
} catch (OpMatchingException e1) {
377-
// TODO: chain adaptations
378-
continue;
366+
//TODO: this should probably be safer.
367+
OpRef srcOpRef = adaptor.srcOpRef;
368+
379369
}
380370

381371
}
382372
// no adaptors available.
383-
throw new OpMatchingException("Op adaptation failed: no adaptable Ops of type " + opName);
373+
throw new OpMatchingException("Op adaptation failed: no adaptable Ops of type " + ref.getName());
384374
}
385375

386376
/**
@@ -813,10 +803,13 @@ private class OpAdaptor {
813803

814804
//TODO: do we actually need all of these things?
815805
private Object adaptor;
806+
private Object srcOp;
807+
private Object adaptedOp;
816808
private OpInfo adaptorInfo;
809+
private OpInfo srcOpInfo;
817810
private OpCandidate adaptorCandidate;
818811
private OpRef adaptorRef;
819-
private OpRef srcRef;
812+
private OpRef srcOpRef;
820813
private OpRef targetRef;
821814
private OpRef child;
822815
private Map<TypeVariable<?>, Type> typeVarAssigns;
@@ -847,15 +840,39 @@ public Object constructAdaptor() throws OpMatchingException {
847840
return adaptor;
848841
}
849842

843+
public Object constructSrcOp(String opName, OpService ops) throws OpMatchingException {
844+
// grab the first type parameter (from the OpCandidate?) and search for an Op
845+
// that will then be adapted (this will be the first (only) type in the args of
846+
// the adaptor)
847+
Type adaptFrom = adaptorCandidate.paddedArgs()[0];
848+
srcOpRef = inferOpRef(adaptFrom, opName, typeVarAssigns);
849+
// TODO: export this to another function (also done in findOpInstance).
850+
// We need this here because we need to grab the OpInfo.
851+
// TODO: is there a better way to do this?
852+
final OpCandidate srcCandidate = getOpMatcher().findSingleMatch(ops, srcOpRef);
853+
final List<Object> srcDependencies = resolveOpDependencies(srcCandidate);
854+
srcOp = srcCandidate.opInfo().createOpInstance(srcDependencies).object();
855+
srcOpInfo = srcCandidate.opInfo();
856+
return srcOp;
857+
}
858+
850859
public OpInfo adaptorInfo() {return adaptorInfo; }
860+
861+
public OpInfo srcInfo() {return srcOpInfo; }
862+
863+
public OpRef srcRef() {return srcOpRef; }
851864

852865
public OpCandidate adaptorCandidate() {return adaptorCandidate; }
853866

854-
public Object executeAdaptation(Object fromOp) {
855-
Object toOp = ((Function<Object, Object>) adaptor).apply(fromOp);
867+
public void executeAdaptation(Object fromOp) {
868+
//TODO: can we make this safer?
869+
@SuppressWarnings("unchecked")
870+
Object op = ((Function<Object, Object>) adaptor).apply(fromOp);
871+
adaptedOp = op;
856872
// TODO: child adaptor support.
857-
return toOp;
858873
}
874+
875+
public Object getAdaptedOp() {return adaptedOp; }
859876

860877
}
861878
}

0 commit comments

Comments
 (0)