Skip to content

Commit f68064a

Browse files
Treiblesschorlegselzer
authored andcommitted
Add auto op transformation.
Needs to be tested more thoroughly though.
1 parent b5f023a commit f68064a

11 files changed

Lines changed: 564 additions & 1 deletion

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@
5151
import org.scijava.ops.matcher.OpMatchingException;
5252
import org.scijava.ops.matcher.OpRef;
5353
import org.scijava.ops.matcher.OpTypeMatchingService;
54-
import org.scijava.ops.util.Inject;
54+
import org.scijava.ops.transform.OpTransformation;
55+
import org.scijava.ops.transform.OpTransformationInfo;
56+
import org.scijava.ops.transform.OpTransformerService;
5557
import org.scijava.plugin.Parameter;
5658
import org.scijava.plugin.Plugin;
5759
import org.scijava.plugin.PluginInfo;
@@ -79,6 +81,9 @@ public class OpService extends AbstractService implements SciJavaService, OpEnvi
7981

8082
@Parameter
8183
private LogService log;
84+
85+
@Parameter
86+
private OpTransformerService transformer;
8287

8388
/**
8489
* Prefix tree to cache and quickly find {@link OpInfo}s.
@@ -163,9 +168,45 @@ public <T> T findOpInstance(final String opName, final Nil<T> specialType, final
163168
OpCandidate match = findTypeMatch(ref);
164169
return (T) match.createOp(secondaryArgs);
165170
} catch (OpMatchingException e) {
171+
// If we can't find an op matching the original request, we try to find a transformation
172+
OpTransformation transfrom = findTransfromation(ref);
173+
// If we found one, try to do transformation and return transformed op
174+
if (transfrom != null) {
175+
return (T) transfrom.exceute(this, secondaryArgs);
176+
}
166177
throw new RuntimeException(e);
167178
}
168179
}
180+
181+
private OpTransformation findTransfromation(OpRef ref) {
182+
List<OpTransformationInfo> ts = transformer.getTansformationsTo(ref);
183+
for (OpTransformationInfo t : ts) {
184+
OpTransformation match = findTransfromation(t, 0);
185+
if (match != null) {
186+
return match;
187+
}
188+
}
189+
return null;
190+
}
191+
192+
private OpTransformation findTransfromation(OpTransformationInfo candidate, int depth) {
193+
if (candidate == null || depth > 1) {
194+
return null;
195+
} else {
196+
OpRef fromRef = candidate.getFrom();
197+
try {
198+
OpCandidate match = findTypeMatch(fromRef);
199+
return new OpTransformation(match, candidate);
200+
} catch (OpMatchingException e) {
201+
List<OpTransformationInfo> ts = transformer.getTansformationsTo(fromRef);
202+
for (OpTransformationInfo t : ts) {
203+
return findTransfromation(candidate.chain(t), depth + 1);
204+
}
205+
}
206+
}
207+
return null;
208+
}
209+
169210
public <T> T findOp(final Nil<T> specialType, final Nil<?>[] inTypes, final Nil<?>[] outTypes,
170211
final Object... secondaryArgs) {
171212
return findOpInstance(null, specialType, inTypes, outTypes, secondaryArgs);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
7+
* Institute of Molecular Cell Biology and Genetics, University of
8+
* Konstanz, and KNIME GmbH.
9+
* %%
10+
* Redistribution and use in source and binary forms, with or without
11+
* modification, are permitted provided that the following conditions are met:
12+
*
13+
* 1. Redistributions of source code must retain the above copyright notice,
14+
* this list of conditions and the following disclaimer.
15+
* 2. Redistributions in binary form must reproduce the above copyright notice,
16+
* this list of conditions and the following disclaimer in the documentation
17+
* and/or other materials provided with the distribution.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
* #L%
31+
*/
32+
33+
package org.scijava.ops.transform;
34+
35+
import java.util.ArrayList;
36+
import java.util.List;
37+
38+
import org.scijava.ops.matcher.OpRef;
39+
import org.scijava.plugin.AbstractSingletonService;
40+
import org.scijava.plugin.Plugin;
41+
import org.scijava.service.Service;
42+
43+
@Plugin(type = Service.class)
44+
public final class DefaultOpTransformerService extends AbstractSingletonService<OpTransformer>
45+
implements OpTransformerService {
46+
47+
@Override
48+
public List<OpTransformationInfo> getTansformationsTo(OpRef toRef) {
49+
List<OpTransformationInfo> transforms = new ArrayList<>();
50+
51+
for (OpTransformer ot: getInstances()) {
52+
OpRef fromRef = ot.getFromTransformTo(toRef);
53+
if (fromRef != null) {
54+
transforms.add(new OpTransformationInfo(fromRef, toRef, ot));
55+
}
56+
}
57+
return transforms;
58+
}
59+
60+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.scijava.ops.transform;
2+
3+
import org.scijava.ops.OpService;
4+
import org.scijava.ops.matcher.OpCandidate;
5+
import org.scijava.ops.matcher.OpMatchingException;
6+
7+
public class OpTransformation {
8+
9+
OpTransformationInfo transformation;
10+
OpCandidate srcOp;
11+
12+
public OpTransformation(OpCandidate scrOp, OpTransformationInfo transformation) {
13+
this.srcOp = scrOp;
14+
this.transformation = transformation;
15+
}
16+
17+
public Object exceute(OpService opService, Object... secondaryArgs) {
18+
try {
19+
Object op = srcOp.createOp(secondaryArgs);
20+
return transformation.execute(op, opService);
21+
} catch (OpMatchingException e) {
22+
return null;
23+
}
24+
}
25+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.scijava.ops.transform;
2+
3+
import java.util.Arrays;
4+
import java.util.Iterator;
5+
import java.util.LinkedList;
6+
7+
import org.scijava.ops.OpService;
8+
import org.scijava.ops.matcher.OpRef;
9+
10+
public class OpTransformationInfo {
11+
12+
private LinkedList<OpRef> fromRefs = new LinkedList<>();
13+
private LinkedList<OpRef> toRefs = new LinkedList<>();
14+
private LinkedList<OpTransformer> transformationQueue = new LinkedList<>();
15+
16+
public OpTransformationInfo(OpRef from, OpRef to, OpTransformer transformer) {
17+
fromRefs.addFirst(from);
18+
toRefs.addFirst(to);
19+
transformationQueue.addFirst(transformer);
20+
}
21+
22+
public OpRef getFrom() {
23+
return fromRefs.getFirst();
24+
}
25+
26+
public OpRef getTo() {
27+
return toRefs.getFirst();
28+
}
29+
30+
public OpTransformer getTransformer() {
31+
return transformationQueue.getFirst();
32+
}
33+
34+
public Object execute(Object obj, OpService opService) {
35+
Object candidate = obj;
36+
int i = 0;
37+
for (OpTransformer t : transformationQueue) {
38+
candidate = t.transform(opService, toRefs.get(i), candidate);
39+
i++;
40+
}
41+
return candidate;
42+
}
43+
44+
public OpTransformationInfo chain(OpTransformationInfo transformation) {
45+
fromRefs.addFirst(transformation.getFrom());
46+
toRefs.addFirst(transformation.getTo());
47+
transformationQueue.addFirst(transformation.getTransformer());
48+
return this;
49+
}
50+
51+
@Override
52+
public String toString() {
53+
StringBuilder s = new StringBuilder();
54+
Iterator<OpRef> fromIter = fromRefs.descendingIterator();
55+
Iterator<OpRef> toIter = toRefs.descendingIterator();
56+
Iterator<OpTransformer> transformIter = transformationQueue.descendingIterator();
57+
58+
int i = 0;
59+
while(fromIter.hasNext()) {
60+
s.append(i + ")\n");
61+
s.append("\tFrom:\t");
62+
s.append(Arrays.deepToString(fromIter.next().getTypes()));
63+
s.append("\n\tTo:\t\t");
64+
s.append(Arrays.deepToString(toIter.next().getTypes()));
65+
s.append("\n\tWith:\t");
66+
s.append(transformIter.next().getClass().getName());
67+
s.append("\n\n");
68+
}
69+
return s.toString();
70+
}
71+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
7+
* Institute of Molecular Cell Biology and Genetics, University of
8+
* Konstanz, and KNIME GmbH.
9+
* %%
10+
* Redistribution and use in source and binary forms, with or without
11+
* modification, are permitted provided that the following conditions are met:
12+
*
13+
* 1. Redistributions of source code must retain the above copyright notice,
14+
* this list of conditions and the following disclaimer.
15+
* 2. Redistributions in binary form must reproduce the above copyright notice,
16+
* this list of conditions and the following disclaimer in the documentation
17+
* and/or other materials provided with the distribution.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
* #L%
31+
*/
32+
33+
package org.scijava.ops.transform;
34+
35+
import java.lang.reflect.Type;
36+
37+
import org.scijava.ops.OpService;
38+
import org.scijava.ops.matcher.OpRef;
39+
import org.scijava.plugin.SingletonPlugin;
40+
41+
public interface OpTransformer extends SingletonPlugin {
42+
43+
Object transform(OpService opService, OpRef ref, Object src);
44+
45+
OpRef getFromTransformTo(OpRef srcRef);
46+
47+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.scijava.ops.transform;
2+
3+
import java.util.List;
4+
5+
import org.scijava.ops.matcher.OpRef;
6+
import org.scijava.plugin.SingletonService;
7+
import org.scijava.service.SciJavaService;
8+
9+
public interface OpTransformerService extends SciJavaService, SingletonService<OpTransformer> {
10+
11+
@Override
12+
default Class<OpTransformer> getPluginType() {
13+
return OpTransformer.class;
14+
}
15+
16+
List<OpTransformationInfo> getTansformationsTo (OpRef opRef);
17+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.scijava.ops.transform.impl;
2+
3+
import java.lang.reflect.Type;
4+
import java.util.function.Function;
5+
6+
import org.scijava.ops.OpService;
7+
import org.scijava.ops.core.Computer;
8+
import org.scijava.ops.matcher.OpRef;
9+
import org.scijava.ops.transform.OpTransformer;
10+
import org.scijava.ops.transform.TypeModUtils;
11+
import org.scijava.ops.util.Adapt;
12+
import org.scijava.ops.util.Computers;
13+
import org.scijava.plugin.Plugin;
14+
import org.scijava.types.Nil;
15+
16+
@Plugin(type = OpTransformer.class)
17+
public class FunctionToComputerTransformer implements OpTransformer {
18+
19+
@Override
20+
public Object transform(OpService opService, OpRef ref, Object src) {
21+
if (src instanceof Function) {
22+
// TODO what happens if we actually have several?
23+
Type[] outTypes = ref.getOutTypes();
24+
try {
25+
Computer copy = Computers.unary(opService, "copy", Nil.of(outTypes[0]), Nil.of(outTypes[0]));
26+
return Adapt.Functions.asComputer((Function) src, copy);
27+
} catch (Exception e) {
28+
//TODO
29+
}
30+
}
31+
return null;
32+
}
33+
34+
@Override
35+
public OpRef getFromTransformTo(OpRef toRef) {
36+
Type[] refTypes = toRef.getTypes();
37+
boolean hit = TypeModUtils.replaceRawTypes(refTypes, Computer.class, Function.class);
38+
if (hit) {
39+
return OpRef.fromTypes(toRef.getName(), refTypes, toRef.getOutTypes(), toRef.getArgs());
40+
}
41+
return null;
42+
}
43+
44+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.scijava.ops.transform.impl;
2+
3+
import java.lang.reflect.Type;
4+
import java.util.function.Function;
5+
6+
import org.scijava.ops.OpService;
7+
import org.scijava.ops.matcher.OpRef;
8+
import org.scijava.ops.transform.OpTransformer;
9+
import org.scijava.ops.transform.TypeModUtils;
10+
import org.scijava.ops.util.Maps;
11+
import org.scijava.plugin.Plugin;
12+
13+
@Plugin(type = OpTransformer.class)
14+
public class LiftFunctionToIterableTransformer implements OpTransformer {
15+
16+
@Override
17+
public Object transform(OpService opService, OpRef fromRef, Object src) {
18+
if (src instanceof Function) {
19+
try {
20+
return Maps.Lift.Functions.iterable((Function) src);
21+
} catch (Exception e) {
22+
// TODO
23+
}
24+
}
25+
return null;
26+
}
27+
28+
@Override
29+
public OpRef getFromTransformTo(OpRef toRef) {
30+
Type[] refTypes = toRef.getTypes();
31+
boolean typesChanged = TypeModUtils.unliftParameterizedTypes(refTypes, Function.class, Iterable.class);
32+
// TODO We assume here that the functional input is the first Type in
33+
// this list and all others are secondary args if there are any (we do
34+
// not want to touch them as they are not part of op transformations).
35+
// Should always be the case as during structification of the ops,
36+
// the functional args are always checked first. Hence, they always
37+
// need to be requested first and are thus at the beginning of the list.
38+
// From the functional type we know how many there must be.
39+
Type[] args = toRef.getArgs();
40+
boolean argsChanged = TypeModUtils.unliftTypes(args, Iterable.class, 0);
41+
Type[] outs = toRef.getOutTypes();
42+
boolean outsChanged = TypeModUtils.unliftTypes(outs, Iterable.class, 0);
43+
44+
if (typesChanged && argsChanged && outsChanged) {
45+
return OpRef.fromTypes(toRef.getName(), refTypes, outs, args);
46+
}
47+
return null;
48+
}
49+
50+
}

0 commit comments

Comments
 (0)