Skip to content

Commit 9a3f3f6

Browse files
authored
Merge pull request #70 from imglib/img-math
ImgMath: new package net.imglib2.algorithm.math
2 parents c0eec87 + 3fbf315 commit 9a3f3f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2752
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package net.imglib2.algorithm.math;
2+
3+
import java.util.Map;
4+
5+
import net.imglib2.algorithm.math.abstractions.ABinaryFunction;
6+
import net.imglib2.algorithm.math.abstractions.OFunction;
7+
import net.imglib2.algorithm.math.execution.Addition;
8+
import net.imglib2.algorithm.math.execution.Variable;
9+
import net.imglib2.converter.Converter;
10+
import net.imglib2.type.numeric.RealType;
11+
12+
public final class Add extends ABinaryFunction
13+
{
14+
public Add( final Object o1, final Object o2 )
15+
{
16+
super( o1, o2 );
17+
}
18+
19+
public Add( final Object... obs )
20+
{
21+
super( obs );
22+
}
23+
24+
@Override
25+
public < O extends RealType< O > > Addition< O > reInit(
26+
final O tmp,
27+
final Map< String, O > bindings,
28+
final Converter< RealType< ? >, O > converter,
29+
Map< Variable< O >, OFunction< O > > imgSources )
30+
{
31+
return new Addition< O >( tmp.copy(), this.a.reInit( tmp, bindings, converter, imgSources ), this.b.reInit( tmp, bindings, converter, imgSources ) );
32+
}
33+
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package net.imglib2.algorithm.math;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.HashSet;
6+
import java.util.LinkedList;
7+
8+
import net.imglib2.Cursor;
9+
import net.imglib2.RandomAccessibleInterval;
10+
import net.imglib2.algorithm.math.abstractions.IBinaryFunction;
11+
import net.imglib2.algorithm.math.abstractions.IFunction;
12+
import net.imglib2.algorithm.math.abstractions.ITrinaryFunction;
13+
import net.imglib2.algorithm.math.abstractions.IUnaryFunction;
14+
import net.imglib2.algorithm.math.abstractions.OFunction;
15+
import net.imglib2.algorithm.math.abstractions.Util;
16+
import net.imglib2.converter.Converter;
17+
import net.imglib2.type.numeric.RealType;
18+
import net.imglib2.view.Views;
19+
20+
public class Compute
21+
{
22+
private final IFunction operation;
23+
private final boolean compatible_iteration_order;
24+
25+
/**
26+
* Validate the {code operation}.
27+
*
28+
* @param operation
29+
*/
30+
public Compute( final IFunction operation )
31+
{
32+
this.operation = operation;
33+
34+
// Throw RuntimeException as needed to indicate incorrect construction
35+
this.compatible_iteration_order = this.validate( this.operation );
36+
}
37+
38+
/**
39+
* Execute the computation and store the result into the {@code target}.
40+
* The computation is done using {@code Type}-based math, with the {@code Type}
41+
* of the {@code target} defining the specific math implementation and numerical
42+
* precision that will be used.
43+
*
44+
* @param target The {@code RandomAccessibleInterval} into which to store the computation;
45+
* note its {@code Type} determines the precision of the computation and the specific
46+
* implementation of the mathematical operations.
47+
* @return The {@code target}.
48+
*/
49+
public < O extends RealType< O > > RandomAccessibleInterval< O > into( final RandomAccessibleInterval< O > target )
50+
{
51+
return this.into( target, null );
52+
}
53+
54+
/**
55+
* Execute the mathematical operations and store the result into the given {@code RandomAccessibleInterval}.
56+
*
57+
* @param target The {@code RandomAccessibleInterval} into which to store the computation;
58+
* note its {@code Type} determines the precision of the computation and the specific
59+
* implementation of the mathematical operations.
60+
*
61+
* @param converter The {@code Converter} that transfers all input {@code Type} to the {@code Type}
62+
* of the {@code target}; when null, will create one that uses double floating-point
63+
* precision; but note that if the {@code Type} of an input {@code RandomAccessibleInterval}
64+
* is the same as that of the {@code target}, the converter will not be used.
65+
*
66+
* @return The {@code target}.
67+
*/
68+
public < O extends RealType< O > > RandomAccessibleInterval< O > into(
69+
final RandomAccessibleInterval< O > target,
70+
Converter< RealType< ? >, O > converter
71+
)
72+
{
73+
if ( null == converter )
74+
converter = new Converter< RealType< ? >, O >()
75+
{
76+
@Override
77+
public final void convert( final RealType< ? > input, final O output)
78+
{
79+
output.setReal( input.getRealDouble() );
80+
}
81+
};
82+
83+
// Recursive copy: initializes interval iterators and sets temporary computation holder
84+
final OFunction< O > f = this.operation.reInit(
85+
target.randomAccess().get().createVariable(),
86+
new HashMap< String, O >(),
87+
converter, null );
88+
89+
// Check compatible iteration order and dimensions
90+
if ( compatible_iteration_order )
91+
{
92+
// Evaluate function for every pixel
93+
for ( final O output : Views.iterable( target ) )
94+
output.set( f.eval() );
95+
}
96+
else
97+
{
98+
// Incompatible iteration order
99+
final Cursor< O > cursor = Views.iterable( target ).cursor();
100+
101+
while ( cursor.hasNext() )
102+
{
103+
cursor.fwd();
104+
cursor.get().set( f.eval( cursor ) );
105+
}
106+
}
107+
108+
return target;
109+
}
110+
111+
private boolean validate( final IFunction f )
112+
{
113+
final LinkedList< IFunction > ops = new LinkedList<>();
114+
ops.add( f );
115+
116+
// child-parent map
117+
final HashMap< IFunction, IFunction > cp = new HashMap<>();
118+
119+
// Collect images to later check their iteration order
120+
final LinkedList< RandomAccessibleInterval< ? > > images = new LinkedList<>();
121+
122+
// Collect Var instances to check that each corresponds to an upstream Let
123+
final ArrayList< Var > vars = new ArrayList<>();
124+
125+
// Collect Let instances to check that their declared variables are used
126+
final HashSet< Let > lets = new HashSet<>();
127+
128+
IFunction parent = null;
129+
130+
// Iterate into the nested operations
131+
while ( ! ops.isEmpty() )
132+
{
133+
final IFunction op = ops.removeFirst();
134+
cp.put( op, parent );
135+
parent = op;
136+
137+
if ( op instanceof ImgSource )
138+
{
139+
images.addLast( ( ( ImgSource< ? > )op ).getRandomAccessibleInterval() );
140+
}
141+
else if ( op instanceof IUnaryFunction )
142+
{
143+
ops.addLast( ( ( IUnaryFunction )op ).getFirst() );
144+
145+
if ( op instanceof IBinaryFunction )
146+
{
147+
ops.addLast( ( ( IBinaryFunction )op ).getSecond() );
148+
149+
if ( op instanceof Let )
150+
{
151+
lets.add( ( Let )op );
152+
}
153+
154+
if ( op instanceof ITrinaryFunction )
155+
{
156+
ops.addLast( ( ( ITrinaryFunction )op ).getThird() );
157+
}
158+
}
159+
}
160+
else if ( op instanceof Var )
161+
{
162+
final Var var = ( Var )op;
163+
vars.add( var );
164+
}
165+
}
166+
167+
// Check Vars: are they all using names declared in upstream Lets
168+
final HashSet< Let > used = new HashSet<>();
169+
all: for ( final Var var : vars )
170+
{
171+
parent = var;
172+
while ( null != ( parent = cp.get( parent ) ) )
173+
{
174+
if ( parent instanceof Let )
175+
{
176+
Let let = ( Let )parent;
177+
if ( let.getVarName() != var.getName() )
178+
continue;
179+
// Else, found: Var is in use
180+
used.add( let );
181+
continue all;
182+
}
183+
}
184+
// No upstream Let found
185+
throw new RuntimeException( "The Var(\"" + var.getName() + "\") does not read from any upstream Let. " );
186+
}
187+
188+
// Check Lets: are their declared variables used in downstream Vars?
189+
if ( lets.size() != used.size() )
190+
{
191+
lets.removeAll( used );
192+
String msg = "The Let-declared variable" + ( 1 == lets.size() ? "" : "s" );
193+
for ( final Let let : lets )
194+
msg += " \"" + let.getVarName() + "\"";
195+
msg += " " + ( 1 == lets.size() ? "is" : "are") + " not used by any downstream Var.";
196+
throw new RuntimeException( msg );
197+
}
198+
199+
// Check ImgSource: if they are downstream of an If statement, they should be declared in a Let before that
200+
201+
return Util.compatibleIterationOrder( images );
202+
}
203+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package net.imglib2.algorithm.math;
2+
3+
import java.util.Map;
4+
5+
import net.imglib2.algorithm.math.abstractions.ABinaryFunction;
6+
import net.imglib2.algorithm.math.abstractions.OFunction;
7+
import net.imglib2.algorithm.math.execution.Division;
8+
import net.imglib2.algorithm.math.execution.Variable;
9+
import net.imglib2.converter.Converter;
10+
import net.imglib2.type.numeric.RealType;
11+
12+
public final class Div extends ABinaryFunction
13+
{
14+
15+
public Div( final Object o1, final Object o2 )
16+
{
17+
super( o1, o2 );
18+
}
19+
20+
public Div( final Object... obs )
21+
{
22+
super( obs );
23+
}
24+
25+
@Override
26+
public < O extends RealType< O > > Division< O > reInit(
27+
final O tmp,
28+
final Map< String, O > bindings,
29+
final Converter< RealType< ? >, O > converter,
30+
Map< Variable< O >, OFunction< O > > imgSources )
31+
{
32+
return new Division< O >( tmp.copy(), this.a.reInit( tmp, bindings, converter, imgSources ), this.b.reInit( tmp, bindings, converter, imgSources ) );
33+
}
34+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package net.imglib2.algorithm.math;
2+
3+
import net.imglib2.algorithm.math.abstractions.PassThrough;
4+
5+
/**
6+
* A class that exists merely for coding readability.
7+
*/
8+
public class Else extends PassThrough
9+
{
10+
public Else( final Object o )
11+
{
12+
super ( o );
13+
}
14+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package net.imglib2.algorithm.math;
2+
3+
import java.util.Map;
4+
5+
import net.imglib2.algorithm.math.abstractions.Compare;
6+
import net.imglib2.algorithm.math.abstractions.OFunction;
7+
import net.imglib2.algorithm.math.execution.Equality;
8+
import net.imglib2.algorithm.math.execution.Variable;
9+
import net.imglib2.converter.Converter;
10+
import net.imglib2.type.numeric.RealType;
11+
12+
public final class Equal extends Compare
13+
{
14+
public Equal( final Object o1, final Object o2 )
15+
{
16+
super( o1, o2 );
17+
}
18+
19+
@Override
20+
public < O extends RealType< O > > OFunction< O > reInit(
21+
final O tmp,
22+
final Map< String, O > bindings,
23+
final Converter< RealType< ? >, O > converter,
24+
final Map< Variable< O >, OFunction< O > > imgSources )
25+
{
26+
return new Equality< O >( tmp.copy(), this.a.reInit( tmp, bindings, converter, imgSources ), this.b.reInit( tmp, bindings, converter, imgSources ) );
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package net.imglib2.algorithm.math;
2+
3+
import java.util.Map;
4+
5+
import net.imglib2.algorithm.math.abstractions.Compare;
6+
import net.imglib2.algorithm.math.abstractions.OFunction;
7+
import net.imglib2.algorithm.math.execution.IsGreaterThan;
8+
import net.imglib2.algorithm.math.execution.Variable;
9+
import net.imglib2.converter.Converter;
10+
import net.imglib2.type.numeric.RealType;
11+
12+
public final class GreaterThan extends Compare
13+
{
14+
public GreaterThan( final Object o1, final Object o2 )
15+
{
16+
super( o1, o2 );
17+
}
18+
19+
@Override
20+
public < O extends RealType< O > > IsGreaterThan< O > reInit(
21+
final O tmp,
22+
final Map< String, O > bindings,
23+
final Converter< RealType< ? >, O > converter,
24+
Map< Variable< O >, OFunction< O > > imgSources )
25+
{
26+
return new IsGreaterThan< O >( tmp.copy(), this.a.reInit( tmp, bindings, converter, imgSources ), this.b.reInit( tmp, bindings, converter, imgSources ) );
27+
}
28+
}

0 commit comments

Comments
 (0)