-
Notifications
You must be signed in to change notification settings - Fork 48
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
Implement broadcasting for biosequences #135
Comments
My instinct with this, is to simply look at what can be done, indexing with Vectors, and basically have |
julia> a = [1,2,3,4,5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> a[4:5] = [-1, -2]
2-element Array{Int64,1}:
-1
-2
julia> a
5-element Array{Int64,1}:
1
2
3
-1
-2
julia> a[4:5] = -6
ERROR: ArgumentError: indexed assignment with a single value to many locations is not supported; perhaps use broadcasting `.=` instead?
Stacktrace:
[1] setindex_shape_check(::Int64, ::Int64) at ./indices.jl:258
[2] macro expansion at ./multidimensional.jl:795 [inlined]
[3] _unsafe_setindex!(::IndexLinear, ::Array{Int64,1}, ::Int64, ::UnitRange{Int64}) at ./multidimensional.jl:789
[4] _setindex! at ./multidimensional.jl:785 [inlined]
[5] setindex!(::Array{Int64,1}, ::Int64, ::UnitRange{Int64}) at ./abstractarray.jl:1153
[6] top-level scope at REPL[9]:1 Ah well, there we go! I would say let's go that route! |
julia> my_seq[2:4] = DNA_M
ERROR: MethodError: no method matching length(::DNA)
Closest candidates are:
length(::CompositeException) at task.jl:41
length(::Base.MethodList) at reflection.jl:869
length(::ExponentialBackOff) at error.jl:259
...
Stacktrace:
[1] setindex!(::LongSequence{DNAAlphabet{4}}, ::DNA, ::UnitRange{Int64}) at /Users/bward/repos/github/BioJulia/BioSequences/src/biosequence/indexing.jl:78
[2] top-level scope at REPL[32]:1 @jakobnissen Ok, so it looks like this is already not possible anymore, probably due to the interface rework. It likely got removed then. |
Exactly, I removed it for v3. I'd be very happy if you could give a go at implementing broadcasting, I got pretty much nowhere when I tried! (the Julia docs are not exactly easy to understand on that point, see JuliaLang/julia#32066). I'd want to be a little careful to make sure that biosequences have a broadcast style guarantees that the result is a biosequence instead of a vector - but maybe we just need to implement something and see how it feels. |
So as far as I can tell, we need a style, and then we need rules, that dictate when the output should be a sequence or not. So |
So, since broadcasting is a bit... complex, I'm going to be documenting my progress here so I can ask questions and the wider julia community can poke holes in what I'm doing: https://discourse.julialang.org/t/attempting-to-customise-broadcasting-for-biosequences/64892 |
Before this issue is resolved, we should remember to fix the method ambiguity that currently exists between these two methods: Base.Broadcast.BroadcastStyle(s1::BioSequences.PFMBroadcastStyle, s2::Base.Broadcast.BroadcastStyle) in B
ioSequences at /Users/jakobnissen/code/BioSequences.jl/src/search/pwm.jl:74
Base.Broadcast.BroadcastStyle(::S, ::Base.Broadcast.Unknown) where S<:Base.Broadcast.BroadcastStyle in Ba
se.Broadcast at broadcast.jl:133 |
TL;DR
For v3, we should add broadcasting to BioSequence, and make
my_seq[1:4] = DNA_A
error.Rationale
I was working on #133 , but can't get it to work properly. When calling
getindex
andsetindex!
with BioSequences, there always seems to be an edge case where dispatch goes the wrong way, or something is not implemented, or you get a method ambiguity error. I remember thinking the same when doing #120 .I hate method ambiguity errors. They're a critical error in the sense that they completely break your workflow. They can't be found statically, and they're extremely hard to test for. The
LongSequence
test suite is compresensive, but I can guarantee you, I can find method ambiguity in something as simple assetindex!
there.Why is this so hard? Why is it so hard for BioSequences in particular?
I've come to think one of the reasons is that
my_seq[inds] = x
has two distinct semtantic meaning in BioSequences right now, namely these two:Having two distinct semantic meanings covered by the same function is a bad idea. Here's what happens if you do it.
setindex!(::BioSequence, ::Any, ::Vector{Bool})
andsetindex!(::BioSequence, ::BioSequence, ::Vector{Bool})
separately. This works ONLY because one signature is more specific than the other, NOT because the signatures are incompatible. Note that we already loses some flexibility, because we now can't domy_seq[1:2] = [DNA_A, DNA_C]
, since that would call the wrong method.LongSequence
orLongSubSeq
. We need to specialize one of the setindex! methods, so we addsetindex!(::LongSequence, ::Any, ::Vector{Bool})
.setindex!(::LongSequence, ::LongSequence, ::Vector{Bool})
. We lose even more flexibility, and the original method error may still be exposed if you try to domy_seq[1:2] = mer"TA"
. Also, we have to duplicate efforts by having this new method, whose content is identical to the original one.We've gone down a wrong path. I can see two solutions:
setindex!(::BioSequence, ::Any, ::Vector{Bool})
, and instead have a method where we restrict the middle argument to be e.g.Union{BioSymbol, Char}
or something, and the other method to haveUnion{BioSequence, AbstractVector}
. The disadvantage here is that we lose some ducktyping.setindex!(::BioSequence, ::Any, ::Vector{Bool})
(and a few other functions like it), and replace them with new functions. I think we can do this by overloading broadcasting. The disadvantage here is that I don't know how complex implementing broadcasting is.The text was updated successfully, but these errors were encountered: