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

Adv+ac/phylogenetic trees #3255

Merged
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
e2cd3e4
Some helpful functions for MPI meeting
antonydellavecchia Nov 6, 2023
44b6e0f
phylogenetic trees
antonydellavecchia Nov 10, 2023
4a5495c
some clean up
antonydellavecchia Nov 13, 2023
0ddfd41
get properties with julia types
Jan 25, 2024
f75154a
Tropical median consensus added
Jan 25, 2024
e832159
export consensus
andreicomaneci Feb 1, 2024
43d9858
docs for phylo functions
andreicomaneci Feb 1, 2024
9c8cbdd
doc tropical median consensus
andreicomaneci Feb 1, 2024
da8cc8a
tropical_median_consensus to md file
andreicomaneci Feb 1, 2024
fa72603
add intro doc phylogenetics
andreicomaneci Feb 1, 2024
a0e91dd
Merge remote-tracking branch 'origin/master' into adv+ac/phylogenetic…
antonydellavecchia Feb 1, 2024
d3bf458
fix conflict
andreicomaneci Feb 1, 2024
3b9d2b1
added some test skeleton and some docs
antonydellavecchia Feb 1, 2024
5c009a2
Merge branch 'phylo-tests' into adv+ac/phylogenetic-trees
antonydellavecchia Feb 1, 2024
f9afdad
remove doc for now
antonydellavecchia Feb 1, 2024
7bceabd
added more stuff to tests
antonydellavecchia Feb 1, 2024
b01a22e
Merge branch 'phylo-tests' into adv+ac/phylogenetic-trees
antonydellavecchia Feb 1, 2024
7456d24
Merge branch 'master' into adv+ac/phylogenetic-trees
andreicomaneci Feb 1, 2024
32ff0d0
add fix for QQField matrix type
antonydellavecchia Feb 1, 2024
cee3495
Merge remote-tracking branch 'andrei/adv+ac/phylogenetic-trees' into …
antonydellavecchia Feb 1, 2024
048ab83
fix printing
antonydellavecchia Feb 1, 2024
e63cde2
fix tests
andreicomaneci Feb 1, 2024
dab3e8e
eliminate duplicate in exports.jl
andreicomaneci Feb 1, 2024
44e602a
remove the unused param T
andreicomaneci Feb 1, 2024
4500fbf
change where T in Varargs{phylo}
andreicomaneci Feb 1, 2024
2f0be23
removed spaces around where
andreicomaneci Feb 1, 2024
020b569
change deprecated where
andreicomaneci Feb 1, 2024
8ac80ab
this might fix the export issues
antonydellavecchia Feb 2, 2024
75be07e
removed undefined method from exports
andreicomaneci Feb 1, 2024
a1315a8
trying to fix arg types
antonydellavecchia Feb 2, 2024
4301b2f
fixing vararg
antonydellavecchia Feb 2, 2024
524fcaf
Merge remote-tracking branch 'andrei/adv+ac/phylogenetic-trees' into …
antonydellavecchia Feb 2, 2024
9ccf315
removed swp file
andreicomaneci Feb 3, 2024
144df00
add undirected adjacency
andreicomaneci Feb 3, 2024
10913b3
Merge branch 'adv+ac/phylogenetic-trees' of github.com:andreicomaneci…
andreicomaneci Feb 3, 2024
3be4b7f
i think this might work
antonydellavecchia Feb 3, 2024
6292a40
remove vararg function
andreicomaneci Feb 3, 2024
d3d91f0
trying again with signature
antonydellavecchia Feb 3, 2024
3c2635e
use splat
antonydellavecchia Feb 3, 2024
f511afa
adjacency_tree returns a directed graph now
andreicomaneci Feb 6, 2024
20666a5
update tests
andreicomaneci Feb 6, 2024
0bd1c63
Merge remote-tracking branch 'origin/master' into adv+ac/phylogenetic…
antonydellavecchia Feb 6, 2024
09ac0f8
makes some type and signature fixes and adjustments to tests
antonydellavecchia Feb 6, 2024
38f47b2
Merge remote-tracking branch 'andrei/adv+ac/phylogenetic-trees' into …
antonydellavecchia Feb 6, 2024
7dad693
Revert "Merge remote-tracking branch 'andrei/adv+ac/phylogenetic-tree…
antonydellavecchia Feb 6, 2024
d9a0653
moves graph from edges up out of phylo trees section
antonydellavecchia Feb 6, 2024
0a9d603
some restructuring
antonydellavecchia Feb 7, 2024
c13fc9f
Revert "some restructuring"
antonydellavecchia Feb 7, 2024
c784565
new phylogenetic trees file
antonydellavecchia Feb 7, 2024
334b61b
returning graph from edges to the bottom of file + add include
antonydellavecchia Feb 7, 2024
f07e5ca
Update src/Combinatorics/Graphs/functions.jl
antonydellavecchia Feb 7, 2024
367d102
removed swp file
antonydellavecchia Feb 7, 2024
2aeda8a
Merge branch 'master' into adv+ac/phylogenetic-trees
antonydellavecchia Feb 9, 2024
651dedd
Update src/Combinatorics/Graphs/functions.jl
benlorenz Feb 9, 2024
35bd835
updates from review comments
antonydellavecchia Feb 9, 2024
3089c39
make Phylogenetic tree immutable
antonydellavecchia Feb 9, 2024
52f14ee
Apply suggestions from code review
antonydellavecchia Feb 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions docs/doc.main
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,15 @@
],

"Combinatorics" => [
"Combinatorics/graphs.md",
"Combinatorics/matroids.md",
"Combinatorics/simplicialcomplexes.md",
"Enumerative combinatorics" => [
"Combinatorics/EnumerativeCombinatorics/partitions.md",
"Combinatorics/EnumerativeCombinatorics/tableaux.md",
"Combinatorics/EnumerativeCombinatorics/schur_polynomials.md",
],
"Combinatorics/graphs.md",
"Combinatorics/matroids.md",
"Combinatorics/simplicialcomplexes.md",
"Combinatorics/phylogenetic_trees.md",
"Enumerative combinatorics" => [
"Combinatorics/EnumerativeCombinatorics/partitions.md",
"Combinatorics/EnumerativeCombinatorics/tableaux.md",
"Combinatorics/EnumerativeCombinatorics/schur_polynomials.md",
],
],

"Straight Line Programs" => [
Expand Down
27 changes: 27 additions & 0 deletions docs/src/Combinatorics/phylogenetic_trees.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
```@meta
CurrentModule = Oscar
```

# Phylogenetic Trees

## Introduction

Phylogenetic trees represent the evolutionary history of some species of consideration.
Here we consider phylogenetic trees with branch lengths as defined in C. Semple, M. Steel: Phylogenetics.
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved

## Construction

```@docs
phylogenetic_tree
```

## Some Helpful Functions

```@docs
adjacency_tree
equidistant
cophenetic_matrix
taxa
newick
tropical_median_consensus
```
Binary file added src/Combinatorics/Graphs/.functions.jl.swp
lgoettgens marked this conversation as resolved.
Show resolved Hide resolved
Binary file not shown.
4 changes: 2 additions & 2 deletions src/Combinatorics/Graphs/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function graph_from_adjacency_matrix(::Type{T}, G::Union{MatElem, Matrix}) where
end



antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
_has_node(G::Graph, node::Int64) = 0 < node <= nvertices(G)

@doc raw"""
Expand Down Expand Up @@ -1088,7 +1089,7 @@ function graph_from_edges(::Type{T},

n_needed = maximum(reduce(append!,[[src(e),dst(e)] for e in edges]))
@req (n_vertices >= n_needed || n_vertices < 0) "n_vertices must be at least the maximum vertex in the edges"

g = Graph{T}(max(n_needed, n_vertices))
for e in edges
add_edge!(g, src(e), dst(e))
Expand Down Expand Up @@ -1130,4 +1131,3 @@ n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(
graph_from_edges(
edges::Vector{Vector{Int}},
n_vertices::Int=-1) = graph_from_edges(Undirected, [Edge(e[1], e[2]) for e in edges], n_vertices)

2 changes: 1 addition & 1 deletion src/Combinatorics/Graphs/structs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import Oscar: Polymake
import Oscar.Polymake: Directed, Undirected

struct Graph{T <: Union{Directed, Undirected}}
pm_graph::Polymake.Graph{T}
pm_graph::Polymake.Graph{T}
end

289 changes: 289 additions & 0 deletions src/Combinatorics/PhylogeneticTrees.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}}
pm_ptree::Polymake.LibPolymake.BigObjectAllocated
end

function pm_object(PT::PhylogeneticTree)
return PT.pm_ptree
end

@doc raw"""
phylogenetic_tree(T::Type{<:Union{Float64, QQFieldElem}}, newick::String)

Constructs a phylogenetic tree with Newick representation `newick`. `T` indicates
the numerical type of the edge lengths.

# Examples
Make a phylogenetic tree with 4 leaves from its Newick representation and print
its taxa and cophenetic matrix.
```jldoctest
julia> phylo_t = phylogenetic_tree(Float64, "((H:3,(C:1,B:1):2):1,G:4);");

julia> taxa(phylo_t)
4-element Vector{String}:
"B"
"C"
"G"
"H"

julia> cophenetic_matrix(phylo_t)
4×4 Matrix{Float64}:
0.0 2.0 8.0 6.0
2.0 0.0 8.0 6.0
8.0 8.0 0.0 8.0
6.0 6.0 8.0 0.0
```
"""
function phylogenetic_tree(T::Type{<:Union{Float64, QQFieldElem}}, newick::String)
pm_ptree = Polymake.graph.PhylogeneticTree{Polymake.convert_to_pm_type(T)}(NEWICK = newick)

# load graph properties
pm_ptree.ADJACENCY

return PhylogeneticTree{T}(pm_ptree)
end

@doc raw"""
phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: Union{Float64, QQFieldElem}

Constructs a phylogenetic tree with cophenetic matrix `M` and taxa `taxa`. The matrix `M` must be
ultrametric, otherwise an error will be thrown.

# Examples
Make a phylogenetic tree on 4 taxa with given cophenetic matrix and print one Newick representation.

```jldoctest
julia> mat = [0. 2 8 6; 2 0 8 6; 8 8 0 8; 6 6 8 0]
4×4 Matrix{Float64}:
0.0 2.0 8.0 6.0
2.0 0.0 8.0 6.0
8.0 8.0 0.0 8.0
6.0 6.0 8.0 0.0

julia> tax = ["Bonobo", "Chimpanzee", "Gorilla", "Human"]
4-element Vector{String}:
"Bonobo"
"Chimpanzee"
"Gorilla"
"Human"

julia> tree_mat = phylogenetic_tree(mat, tax);

julia> newick(tree_mat)
"Gorilla:4,(Human:3,(Bonobo:1,Chimpanzee:1):2):1;"
```
"""
function phylogenetic_tree(M::Matrix{Float64}, taxa::Vector{String})
n_taxa = length(taxa)
@req (n_taxa, n_taxa) == size(M) "Number of taxa should match the rows and columns of the given matrix"
pm_ptree = Polymake.graph.PhylogeneticTree{Float64}(COPHENETIC_MATRIX = M, TAXA = taxa)
return PhylogeneticTree{Float64}(pm_ptree)
end

function phylogenetic_tree(M::QQMatrix, taxa::Vector{String})
n_taxa = length(taxa)
@req (n_taxa, n_taxa) == size(M) "Number of taxa should match the rows and columns of the given matrix"
pm_T = Polymake.convert_to_pm_type(QQFieldElem)
cp_M = convert(Matrix{pm_T}, Matrix{QQFieldElem}(M))
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved

pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}(
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
COPHENETIC_MATRIX = M, TAXA = taxa
)
return PhylogeneticTree{QQFieldElem}(pm_ptree)
end

@doc raw"""
adjacency_tree(ptree::PhylogeneticTree)

Returns the underlying graph of the phylogenetic tree `ptree`.

# Examples
Make a phylogenetic tree with given Newick format and print its underlying graph.

```jldoctest
julia> ptree = phylogenetic_tree(Float64, "((H:3,(C:1,B:1):2):1,G:4);");

julia> adjacency_tree(ptree)
Undirected graph with 7 nodes and the following edges:
(2, 1)(3, 2)(4, 2)(5, 4)(6, 4)(7, 1)
```
"""
function adjacency_tree(ptree::PhylogeneticTree)
return Graph{Undirected}(ptree.pm_ptree.ADJACENCY)
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
end

function Base.show(io::IO, ptree::PhylogeneticTree{T}) where T
print(io, "Phylogenetic tree with $T type coefficients")
end

@doc raw"""
equidistant(ptree::PhylogeneticTree)

Checks if the phylogenetic tree `ptree` is equidistant.

# Examples
Make a phylogenetic tree with given Newick format and check if it is equidistant.

```jldoctest
julia> ptree = phylogenetic_tree(Float64, "((H:3,(C:1,B:1):2):1,G:4);");

julia> equidistant(ptree)
true
```
"""
function equidistant(ptree::PhylogeneticTree)
return ptree.pm_ptree.EQUIDISTANT
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
end


@doc raw"""
cophenetic_matrix(ptree::PhylogeneticTree)

Returns the cophenetic matrix of the phylogenetic tree `ptree`.

# Examples
Make a phylogenetic tree with given Newick format and print its cophenetic matrix.

```jldoctest
julia> ptree = phylogenetic_tree(Float64, "((H:3,(C:1,B:1):2):1,G:4);");

julia> cophenetic_matrix(ptree)
4×4 Matrix{Float64}:
0.0 2.0 8.0 6.0
2.0 0.0 8.0 6.0
8.0 8.0 0.0 8.0
6.0 6.0 8.0 0.0
```
"""
function cophenetic_matrix(ptree::PhylogeneticTree{Float64})
return convert(Matrix, ptree.pm_ptree.COPHENETIC_MATRIX)
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
end

function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem})
return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX))
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
end

@doc raw"""
taxa(ptree::PhylogeneticTree)

Returns the taxa of the phylogenetic tree `ptree`.

# Examples
Make a phylogenetic tree with given Newick format and print its taxa.

```jldoctest
julia> ptree = phylogenetic_tree(Float64, "((H:3,(C:1,B:1):2):1,G:4);");

julia> taxa(ptree)
4-element Vector{String}:
"B"
"C"
"G"
"H"
```
"""
function taxa(ptree::PhylogeneticTree)
return convert(Array{String}, ptree.pm_ptree.TAXA)
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
end

@doc raw"""
newick(ptree::PhylogeneticTree)

Returns a Newick representation of the phylogenetic tree `ptree`.

# Examples
Make a phylogenetic tree from a matrix and print a Newick representation of it.

```jldoctest
julia> mat = [0. 2 8 6; 2 0 8 6; 8 8 0 8; 6 6 8 0]
4×4 Matrix{Float64}:
0.0 2.0 8.0 6.0
2.0 0.0 8.0 6.0
8.0 8.0 0.0 8.0
6.0 6.0 8.0 0.0

julia> tax = ["Bonobo", "Chimpanzee", "Gorilla", "Human"]
4-element Vector{String}:
"Bonobo"
"Chimpanzee"
"Gorilla"
"Human"

julia> tree_mat = phylogenetic_tree(mat, tax);

julia> newick(tree_mat)
"Gorilla:4,(Human:3,(Bonobo:1,Chimpanzee:1):2):1;"
```
"""
function newick(ptree::PhylogeneticTree)
return convert(String, ptree.pm_ptree.NEWICK)
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
end


@doc raw"""
tropical_median_consensus(arr::Vector{PhylogeneticTree{T}})

Computes the tropical median consensus tree of the phylogenetic trees from
the vector `arr`.

# Examples
Compute the tropical median consensus of three trees and print one of its
Newick representations.

```jldoctest
julia> t1 = phylogenetic_tree(Float64, "((H:30,(C:10,B:10):20):10,G:40);");

julia> t2 = phylogenetic_tree(Float64, "(((H:10,C:10):20,B:30):10,G:40);");

julia> t3 = phylogenetic_tree(Float64, "((H:25,C:25):15,(B:15,G:15):25);");

julia> arr = [t1, t2, t3];

julia> tc = tropical_median_consensus(arr);

julia> newick(tc)
"G:40,(B:35,(C:30,H:30):5):5;"
```
"""
function tropical_median_consensus(arr::Vector{PhylogeneticTree{T}}) where {T <: Union{Float64, QQFieldElem}}

n = length(arr)
@req n > 0 "The vector must not be empty"

phylo_type = Polymake.bigobject_type(arr[1].pm_ptree)
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved
pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n)

for i in 1:n
pm_arr[i] = arr[i].pm_ptree
end
antonydellavecchia marked this conversation as resolved.
Show resolved Hide resolved

pm_cons_tree = Polymake.tropical.tropical_median_consensus(pm_arr)
return PhylogeneticTree{T}(pm_cons_tree)
end


@doc raw"""
tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N}

Computes the tropical median consensus tree of any number of phylogenetic trees
given as parameters.

# Examples
Compute the tropical median consensus of three trees and print one of its
Newick representations.

```jldoctest
julia> t1 = phylogenetic_tree(Float64, "((H:30,(C:10,B:10):20):10,G:40);");

julia> t2 = phylogenetic_tree(Float64, "(((H:10,C:10):20,B:30):10,G:40);");

julia> t3 = phylogenetic_tree(Float64, "((H:25,C:25):15,(B:15,G:15):25);");

julia> tc = tropical_median_consensus(t1, t2, t3);

julia> newick(tc)
"G:40,(B:35,(C:30,H:30):5):5;"
```
"""
function tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N}
return tropical_median_consensus(collect(trees))
end
1 change: 1 addition & 0 deletions src/Oscar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ include("Combinatorics/OrderedMultiIndex.jl")
include("Combinatorics/Matroids/JMatroids.jl")
include("Combinatorics/Compositions.jl")
include("Combinatorics/EnumerativeCombinatorics/EnumerativeCombinatorics.jl")
include("Combinatorics/PhylogeneticTrees.jl")

include("StraightLinePrograms/StraightLinePrograms.jl")
include("Rings/lazypolys.jl") # uses StraightLinePrograms
Expand Down
14 changes: 14 additions & 0 deletions src/Serialization/Combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,17 @@ function load_object(s::DeserializerState, K::Type{SimplicialComplex})
bigobject = Polymake.call_function(:common, :deserialize_json_string, json(s.obj))
return K(bigobject)
end

###############################################################################
## Phylogenetic Trees
###############################################################################
@register_serialization_type PhylogeneticTree

function save_object(s::SerializerState, PT::PhylogeneticTree)
save_object(s, pm_object(PT))
end

function load_object(s::DeserializerState, T::Type{PhylogeneticTree}, dict::Dict)
bigobject = Polymake.call_function(:common, :deserialize_json_string, json(dict))
return T(bigobject)
end
Loading
Loading