-
Notifications
You must be signed in to change notification settings - Fork 90
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
Add RandomAccessibleInterval.getType #312
Conversation
49ef92d
to
f27e986
Compare
Thanks for this @hanslovsky! Been bitten by this many times when using lazy cell loading: entire large blocks are loaded (e.g., when a Cell is the whole 2D section, representing a whole 1 GB file). Would have been nice to have a way to return the known type without having to load 1 GB files that won't be used otherwise. |
Is there a reason not to move this method into
If you moved this method to RA, then you'd get it in all of these places.
I like |
Ah, you'd want a default implementation in |
Aha, |
Adding more implementations for RAI<T> raiWithEfficientGetType = ...
raiWithEfficientGetType.getType(); // this is fast
RAI<U> notEfficient = Converters.convert(raiWithEfficientGetType, ...);
notEfficient.getType(); // this is slow Several options:
|
In dc0b039, I added an example of how an implementation for (most) of RA/RAI could look like. This just for demonstration purposes and can be easily reverted. I did not override
|
What do you mean here, @hanslovsky? How does it break? |
@gselzer Let me provide a different example: A use case that probably is not that uncommon is to take an smaller interval from a larger RAI<T> cachedImg = ... the cached cell img happens to override cachedImg.getType() is a very fast operation. The user now goes ahead and takes a smaller interval out of this cached cell img, i.e.
The user also knows that interval.getType() is very slow, and the user has no way of making it fast, again. This is, of course a hypothetical example, but might easily happen if we provide a default implementation for |
Huh, in the case of |
But I guess all of this means having to touch quite some code in imglib2, I think something that @axtimwalde was afraid of when discussing this in gitter?! Personally, as my "cloud hosted image" use-cases (and I guess more people will have such use-cases in the future) are suffering quite a bit from this issue I would still be in favor of trying to find a solution. @hanslovsky for the For example:
And then
Does that help? EDIT: Sorry, I think my comments are in fact obsolete as they are already covered here: dc0b039 |
Yes, that is exactly my point. They will have to delegate to make it any useful. That's why I don't like the |
Well, what do you mean by 'make it any useful'? I think that your |
It will not provide any benefit over what is already there unless we implement it for all classes. |
Well, it might if a given implementation has implemented it, no? If you have a Anyways, I'll delegate to your judgement here, the PR is a fantastic addition either way 😁 |
Generally, I agree, as long as a simple operation like
Thank you, I appreciate it. I will leave it to the maintainers (@tpietzsch @axtimwalde @StephanPreibisch) to decide what part of the PR should go into the repo. My recommendation is to add implementations wherever possible for classes that implement |
I added implementations for
|
dc0b039
to
dc07263
Compare
I recently ran into this again, where a more efficient way to retrieve the type would have been very helpful. I rebased over current master/main and marked as ready for review. |
I created this little kscript to demonstrate the behavior + fix: @file:Repository("https://maven.scijava.org/content/groups/public")
// @file:Repository("https://jitpack.io") // uncomment for getType fix
// @file:DependsOn("com.github.imglib:imglib2:feature-rai-getType-SNAPSHOT") // uncomment for getType fix
@file:DependsOn("net.imglib2:imglib2:6.2.0") // uncomment for current behavior
@file:DependsOn("net.imglib2:imglib2-cache:1.0.0-beta-17")
import net.imglib2.cache.img.CachedCellImg
import net.imglib2.cache.img.CellLoader
import net.imglib2.cache.ref.SoftRefLoaderCache
import net.imglib2.img.basictypeaccess.volatiles.array.VolatileIntArray
import net.imglib2.img.cell.Cell
import net.imglib2.img.cell.CellGrid
import net.imglib2.type.numeric.integer.IntType
import net.imglib2.util.Util
val dims = longArrayOf(10L)
val chunks = intArrayOf(1)
val grid = CellGrid(dims, chunks)
val cache = SoftRefLoaderCache<Long, Cell<VolatileIntArray>>().withLoader {
println("Loading cell $it")
Cell(chunks, longArrayOf(it), VolatileIntArray(1, true))
}
val img = CachedCellImg(grid, IntType(), cache, VolatileIntArray(1, true))
cache.invalidateAll(5000)
println("getTypeFromInterval")
Util.getTypeFromInterval(img)
cache.invalidateAll(5000)
println("getLinkedType")
img.createLinkedType()
println("getTypeFromInterval")
Util.getTypeFromInterval(img) Output with imglib2-6.2.0:
Output with this PR:
|
return converterSupplier.get().convert( ( Sampler< ? extends A > ) new ConstantSampler( getSource().getType() ) ); | ||
} | ||
|
||
private static class ConstantSampler< T > implements Sampler< T > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is duplicated, could be extracted and shared between WriteConvertedRandomAccessibleInterval
and WriteConvertedRandomAccessible
.
@Override | ||
public T getType() { | ||
try { | ||
return linkedType.createVariable(); | ||
} catch ( final NullPointerException e ) { | ||
return super.getType(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could move into the NativeImage
interface as
@Override
public default T getType() {
return createLinkedType().createVariable();
}
Is there a performance penalty to creating a linked type vs just createVariable()
? Is this null
safe or should we add a null
check ?
// TODO can we remove generic parameter F and use | ||
// RandomAccessible<T> rai instead? | ||
// This would be a breaking change, though. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we just leave the generic parameter as is.
// setup | ||
final RandomAccessibleInterval< ? > rai = ArrayImgs.bytes( 1 ); | ||
// process & test | ||
assertEquals( ByteType.class, rai.getType().getClass() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is not very useful. Should we remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it! A simple sanity check.
@ctrueden I looked at all the errors and made draft PRs for every failing project (always branch |
Open questions: - We cannot deprecate Utils.getTypeFromInterval because it does not use RAI as argument. We could change the argument to RAI but this would be a breaking change (see comment in JavaDoc for that function) - What about getType in other places like RA, RRA, RRARI? - Name preference getType vs type?
In many cases, it may be more efficient to delegate getType to a wrapped source
IterableRealInterval and RandomAccessible cannot both have default getType() implementations, otherwise we run into a bug with generic bounds: https://bugs.openjdk.org/browse/JDK-7120669 Therefore we implement getType for all IterableRealInterval implementations. For the same reason, the getType() method must be inherited from a common super-type. Possibly it is possible to avoid this by not having a default implementation at all. Something to try. On the other hand, a Typed<T> interface is probably a good idea.
Instead, implement getType() in all RandomAccessible[Interval] implementations
Implement getType() in all Sampler implementations
Instead implement it in all Real...Accessible implementation
359f407
to
d10e744
Compare
…if no dataAccess is set
This pull request has been mentioned on Image.sc Forum. There might be relevant details there: https://forum.image.sc/t/recent-and-upcoming-imglib2-improvements/96083/2 |
Adding
getType
to theRandomAccessibleInterval
interface would allow individual implementations to provide more efficient implementations. For example, loading the voxel at the min of the RAI may be expensive for some implementations ofNativeImg
. Instead, those implementations can use theirlinkedType
to create a copy of the associated type, if available.Discussion on gitter for reference
Open questions: