-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RealMaskRealInterval OR and AND hang when combining too many masks #60
Comments
What is the code doing while the hang is happening? https://imagej.net/learn/troubleshooting#if-imagej-freezes-or-hangs In an IDE you can simply hit the pause button and inspect the stack trace. Or use the IDE or VisualVM to profile the code to find out where it's spending its time. |
Hmm, it's a lot of recursion, yeah. But I'm still surprised; it's not exponential growth, but rather a linear increase. I cannot spend time digging on this right now. Main thought off the top of my head is: can we introduce some memoization to avoid repeated recursion on unchanging intervals? The diff --git a/src/main/java/net/imglib2/roi/Bounds.java b/src/main/java/net/imglib2/roi/Bounds.java
index 3f9e1ab..7c5145b 100644
--- a/src/main/java/net/imglib2/roi/Bounds.java
+++ b/src/main/java/net/imglib2/roi/Bounds.java
@@ -535,40 +535,60 @@ public abstract class Bounds< I extends RealInterval, B extends Bounds< I, B > >
private final RealInterval i2;
+ private final double[] min;
+
+ private final double[] max;
+
public UnionRealInterval( final RealInterval i1, final RealInterval i2 )
{
super( i1.numDimensions() );
this.i1 = i1;
this.i2 = i2;
assert ( i1.numDimensions() == i2.numDimensions() );
+ min = new double[ i1.numDimensions() ];
+ max = new double[ i1.numDimensions() ];
+ Arrays.fill( min, Double.NaN );
+ Arrays.fill( max, Double.NaN );
}
@Override
public double realMin( final int d )
{
- if ( Intervals.isEmpty( i1 ) )
+ if ( Double.isNaN( min[ d ] ) )
{
- if ( Intervals.isEmpty( i2 ) )
- return Double.POSITIVE_INFINITY;
- return i2.realMin( d );
+ if ( Intervals.isEmpty( i1 ) )
+ {
+ if ( Intervals.isEmpty( i2 ) )
+ min[ d ] = Double.POSITIVE_INFINITY;
+ else
+ min[ d ] = i2.realMin( d );
+ }
+ else if ( Intervals.isEmpty( i2 ) )
+ min[ d] = i1.realMin( d );
+ else
+ min[ d ] = Math.min( i1.realMin( d ), i2.realMin( d ) );
}
- if ( Intervals.isEmpty( i2 ) )
- return i1.realMin( d );
- return Math.min( i1.realMin( d ), i2.realMin( d ) );
+ return min[ d ];
}
@Override
public double realMax( final int d )
{
- if ( Intervals.isEmpty( i1 ) )
+ if ( Double.isNaN( max[d] )
{
- if ( Intervals.isEmpty( i2 ) )
- return Double.NEGATIVE_INFINITY;
- return i2.realMax( d );
+ if ( Intervals.isEmpty( i1 ) )
+ {
+ if ( Intervals.isEmpty( i2 ) )
+ max[ d ] = Double.NEGATIVE_INFINITY;
+ else
+ max[ d ] = i2.realMax( d );
+ }
+ else if ( Intervals.isEmpty( i2 ) )
+ max[ d ] = i1.realMax( d );
+ else
+ max[ d ] = Math.max( i1.realMax( d ), i2.realMax( d ) );
}
- if ( Intervals.isEmpty( i2 ) )
- return i1.realMax( d );
- return Math.max( i1.realMax( d ), i2.realMax( d ) );
+ return max[ d ];
}
} |
Thanks! I will try to find time to test it! |
Here's a link for how to apply the patch, @tischi: https://stackoverflow.com/questions/2249852/how-to-apply-a-patch-generated-with-git-format-patch |
Some new finding: it also hangs when combining the masks with If you have any pointers for me where the look for the culprit, let me know. |
I may have found something (sorry for potential spamming, using this to keep notes in case I cannot fully fix it). This works fine (when commenting out the
|
This is fast as well, indicating that the recursion is in
|
I still don't get why there are sooo many recursions, but this is not very efficient:
Because |
Another place for optimization is that |
Adding the mentioned explicit code seems to help a bit but only gives a factor of 2 or so in speed up. Right now, it feels to me that some (if only short-term, if that is possible) caching of at least whether the contained Intervals |
This is of course the case because there are
Maybe this is the reason for the explosion? Maybe that this leads to a 2 * 2 * 2 ... type of behavior? In other words just to get one, e.g., Would it be possible to change the code (e.g., for Or implement a special |
I think I may have found a solution 🥳 All test run and it is fast ( only 8 ms even for a 1000 combined AND intervals ) .
What do you think? If you approve, I will continue to work on a PR tomorrow (getting late here). |
This is most likely wrong. |
@tpietzsch In fact, I agree, I had the same thought, but in the original code it looked like this:
The point is to replace the Do you think that a) already the original code is wrong, or |
My feeling would be that it is wrong in the original code. Maybe we should replace:
with
? |
I am confused. In
To me this indicates that we apparently do not want I don't know what would be correct here, to continue I would need some help/explanation about what should happen here and why. |
The behavior with just standard imglib2 is in fact such that it does return some finite value for the interval bounds even if it is empty:
Then I would suggest to proceed with my refactoring approach, but reconsider the name of the new |
No, confused again... ;-) I don't get why we do these
In fact, If I just comment it out all test pass... 😕
So, maybe it should just be removed? @ctrueden any opinions? |
Could If yes, then I think they should both behave similar and the currently existing The same argumentation applies to |
I think: Yes to both...
No.
|
A fix for |
I merged imglib/imglib2#301. See imglib/imglib2#315 for follow-up discussion. |
Yes, that's the problem exactly.
I think this is the right idea. What needs to be done:
If somebody wants to work making this into a PR that would be great! |
Just double checking: should we still do all of this even if we would have a If so, I could try to give this a shot next week. |
@tpietzsch |
Yes, I think |
Can this be closed, now that #63 is merged? |
@ctrueden @tpietzsch
This code starts to hang for me around iteration 10:
Am I doing something wrong or is it an issue with the code?
(I know that this specific example does not make sense as I am always combining the same mask, but it also hangs for me when doing it with a similar amount of different masks).
The text was updated successfully, but these errors were encountered: