Skip to content
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

Simplifying the chain type definition with named tuples #8

Closed
bicycle1885 opened this issue Sep 25, 2024 · 0 comments · Fixed by #9
Closed

Simplifying the chain type definition with named tuples #8

bicycle1885 opened this issue Sep 25, 2024 · 0 comments · Fixed by #9

Comments

@bicycle1885
Copy link
Collaborator

I want to suggest a simpler way to define the chain types. Instead of using defining separated types for annotated and not annotated chains, we can use a named tuple to define an extensible chain type. This way, we can avoid the complexity of handling two different types and thus simplify the interface and implementation.

The main points are:

  • Define a chain type having a named tuple of properties as a field so that we can add new properties without changing the type definition.
  • Make the chain type immutable to avoid unnecessary memory allocations.
  • Define types for chain and residue properties to allow for different types of properties.

First, we define the property tyepss for the chain type:

abstract type AbstractProperty end

# Chain-level properties
struct ChainProperty{T} <: AbstractProperty
    value::T
end

Base.getindex(prop::ChainProperty) = prop.value

# Residue-level properties (the last dimension of the array corresponds to residues)
struct ResidueProperty{T, A <: AbstractArray{T}} <: AbstractProperty
    values::A
end

Base.getindex(prop::ResidueProperty) = prop.values
Base.getindex(prop::ResidueProperty, i::AbstractVector) = selectdim(prop.values, ndims(prop.values), i)

Then, we define the chain type as a named tuple:

const NamedProperties{names} = NamedTuple{names, <: Tuple{Vararg{AbstractProperty}}}

struct Chain{T, Ps <: NamedProperties}
    id::String
    sequence::String
    backbone::Array{T, 3}
    numbering::Vector{Int64}
    atoms::Vector{Vector{Atom{T}}}
    properties::Ps
end

Base.getproperty(chain::Chain, name::Symbol) =
    name == :id ? getfield(chain, :id) :
    name == :sequence ? getfield(chain, :sequence) :
    name == :backbone ? getfield(chain, :backbone) :
    name == :numbering ? getfield(chain, :numbering) :
    name == :atoms ? getfield(chain, :atoms) :
    name == :properties ? getfield(chain, :properties) :
    getfield(getfield(chain, :properties), name)

function Base.getindex(chain::Chain, i::AbstractVector)
    properties = map(p -> p isa ChainProperty ? ChainProperty(getindex(p)) : ResidueProperty(getindex(p, i)), chain.properties)
    Chain(chain.id, chain.sequence[i], chain.backbone[:,:,i], chain.numbering[i], chain.atoms[i], properties)
end

annotate(chain::Chain; annotations...) =
    Chain(chain.id, chain.sequence, chain.backbone, chain.numbering, chain.atoms, merge(chain.properties, annotations))

This works as follows:

# Create a chain with random data
chain = Chain(
    "myid",
    "ABCDEFGHIJ",
    randn(3, 3, 10),
    [1:10;],
    [Atom{Float64}[] for _ in 1:10],
    (score = ChainProperty(0.1), others = ResidueProperty(randn(10))),
)

# Select the first 5 residues
x = chain[1:5]

# Access some properties
x.id, x.sequence, x.score, x.others

# Annotate the chain with a new property
annotate(chain, label = ChainProperty("foo bar"))

If type stability is not a concern, we can remove the type parameter of the properties in the Chain type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant