From e2cd3e43faa1c26ac2adaf92b54503a195f08065 Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Mon, 6 Nov 2023 14:09:32 +0100 Subject: [PATCH 01/46] Some helpful functions for MPI meeting --- src/Combinatorics/Graphs/functions.jl | 25 +++++++++++++++++++++++++ src/Combinatorics/Graphs/structs.jl | 4 ++++ src/Serialization/Combinatorics.jl | 14 ++++++++++++++ src/exports.jl | 1 + 4 files changed, 44 insertions(+) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index aa0403bc5610..3aa30ea84bd8 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -5,6 +5,9 @@ function pm_object(G::Graph{T}) where {T <: Union{Directed, Undirected}} return G.pm_graph end +function pm_object(PT::PhylogeneticTree) + return PT.pm_ptree +end ################################################################################ ################################################################################ @@ -1079,3 +1082,25 @@ function Base.show(io::IO, G::Graph{T}) where {T <: Union{Polymake.Directed, Po print(io, "$(_to_string(T)) graph with $(nvertices(G)) nodes and $(nedges(G)) edges") end end + +################################################################################ +################################################################################ +## Phylogenetic Trees +################################################################################ +################################################################################ + +function phylogenetic_tree(T::scalar_type_or_field, newick::String) + pm_ptree = Polymake.graph.PhylogeneticTree{T}(NEWICK = newick) + + return PhylogeneticTree(pm_ptree) +end + +function phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: Number + 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{T}(COPHENETIC_MATRIX = M, TAXA = taxa) + return PhylogeneticTree(pm_ptree) +end + + diff --git a/src/Combinatorics/Graphs/structs.jl b/src/Combinatorics/Graphs/structs.jl index d7964b862ced..75bbcc6d6ba1 100644 --- a/src/Combinatorics/Graphs/structs.jl +++ b/src/Combinatorics/Graphs/structs.jl @@ -5,3 +5,7 @@ struct Graph{T <: Union{Directed, Undirected}} pm_graph::Polymake.Graph{T} end +mutable struct PhylogeneticTree + pm_ptree::Polymake.LibPolymake.BigObjectAllocated +end + diff --git a/src/Serialization/Combinatorics.jl b/src/Serialization/Combinatorics.jl index 6ecd7f452e73..b47ac051ffd4 100644 --- a/src/Serialization/Combinatorics.jl +++ b/src/Serialization/Combinatorics.jl @@ -49,3 +49,17 @@ function load_object(s::DeserializerState, K::Type{SimplicialComplex}, dict::Dic bigobject = Polymake.call_function(:common, :deserialize_json_string, json(dict)) 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 diff --git a/src/exports.jl b/src/exports.jl index 3cbc8930e045..d5bd00a3588e 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -1141,6 +1141,7 @@ export permutation_group export permutation_matrix export permutation_of_terms export permuted +export phylogenetic_tree export picard_class export picard_group export picard_index From 44b6e0fca90e39561ece24671c818aec467f4bd2 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Fri, 10 Nov 2023 11:12:22 +0100 Subject: [PATCH 02/46] phylogenetic trees --- src/Serialization/polymake.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Serialization/polymake.jl b/src/Serialization/polymake.jl index 436b0f179192..34ce1d89a11d 100644 --- a/src/Serialization/polymake.jl +++ b/src/Serialization/polymake.jl @@ -22,6 +22,7 @@ const polymake2OscarTypes = Dict{String, Type}([ "topaz::SimplicialComplex" => SimplicialComplex, "common::GraphAdjacency" => Graph{Undirected}, "common::GraphAdjacency" => Graph{Directed}, + "graph::PhylogeneticTree" => PhylogenticTree{QQFieldElem} ]) @register_serialization_type Polymake.BigObjectAllocated "Polymake.BigObject" uses_id From 4a5495cce66630a298b194b2cc9c5abcc39930a6 Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Mon, 13 Nov 2023 11:25:04 +0100 Subject: [PATCH 03/46] some clean up --- src/Combinatorics/Graphs/functions.jl | 12 ++++++++---- src/Combinatorics/Graphs/structs.jl | 2 +- src/Serialization/polymake.jl | 8 +++++++- test/Combinatorics/PhylogeneticTrees.jl | 6 ++++++ 4 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 test/Combinatorics/PhylogeneticTrees.jl diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 3aa30ea84bd8..907da73e3470 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1089,18 +1089,22 @@ end ################################################################################ ################################################################################ -function phylogenetic_tree(T::scalar_type_or_field, newick::String) +function phylogenetic_tree(T::Type{<:Union{Float64, Int, QQFieldElem}}, newick::String) pm_ptree = Polymake.graph.PhylogeneticTree{T}(NEWICK = newick) - return PhylogeneticTree(pm_ptree) + # load graph properties + pm_ptree.ADJACENCY + + return PhylogeneticTree{T}(pm_ptree) end -function phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: Number +function phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: scalar_type_or_field 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{T}(COPHENETIC_MATRIX = M, TAXA = taxa) - return PhylogeneticTree(pm_ptree) + return PhylogeneticTree{T}(pm_ptree) end + diff --git a/src/Combinatorics/Graphs/structs.jl b/src/Combinatorics/Graphs/structs.jl index 75bbcc6d6ba1..b972e04328db 100644 --- a/src/Combinatorics/Graphs/structs.jl +++ b/src/Combinatorics/Graphs/structs.jl @@ -5,7 +5,7 @@ struct Graph{T <: Union{Directed, Undirected}} pm_graph::Polymake.Graph{T} end -mutable struct PhylogeneticTree +mutable struct PhylogeneticTree{T <: Union{Float64, Int, QQFieldElem}} pm_ptree::Polymake.LibPolymake.BigObjectAllocated end diff --git a/src/Serialization/polymake.jl b/src/Serialization/polymake.jl index 34ce1d89a11d..a29e5b2b92b5 100644 --- a/src/Serialization/polymake.jl +++ b/src/Serialization/polymake.jl @@ -12,6 +12,10 @@ function load_from_polymake(::Type{Graph{T}}, jsondict::Dict{Symbol, Any}) where return Graph{T}(polymake_object) end +function load_from_polymake(::Type{PhylogeneticTree{T}}, jsondict::Dict{Symbol, Any}) where {T <: Union{Float64, Int, QQFieldElem}} + polymake_object = Polymake.call_function(:common, :deserialize_json_string, json(jsondict)) + return PhylogeneticTree{T}(polymake_object) +end const polymake2OscarTypes = Dict{String, Type}([ "polytope::Cone" => Cone{QQFieldElem}, @@ -22,7 +26,9 @@ const polymake2OscarTypes = Dict{String, Type}([ "topaz::SimplicialComplex" => SimplicialComplex, "common::GraphAdjacency" => Graph{Undirected}, "common::GraphAdjacency" => Graph{Directed}, - "graph::PhylogeneticTree" => PhylogenticTree{QQFieldElem} + "graph::PhylogeneticTree" => PhylogeneticTree{QQFieldElem}, + "graph::PhylogeneticTree" => PhylogeneticTree{Float64}, + "graph::PhylogeneticTree" => PhylogeneticTree{Int} ]) @register_serialization_type Polymake.BigObjectAllocated "Polymake.BigObject" uses_id diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl new file mode 100644 index 000000000000..3cd7a3f34299 --- /dev/null +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -0,0 +1,6 @@ +@testset "Phylogenetic Trees" begin + @testset "constructors" begin + ptree1 = phylogenetic_tree(Float64, "((A:4,B:4):5,C:9);") + ptree2 = phylogenetic_tree([0 4 9; 4 0 9; 9.0 9 0], ["a", "b", "c"]) + end +end From 0ddfd41d63a7eaaf6ec7189bdd8922a4c4d8baf0 Mon Sep 17 00:00:00 2001 From: Andrei Comaneci Date: Thu, 25 Jan 2024 10:44:08 +0100 Subject: [PATCH 04/46] get properties with julia types --- src/Combinatorics/Graphs/functions.jl | 23 +++++++++++++++++++++-- src/Combinatorics/Graphs/structs.jl | 4 ++-- src/Serialization/polymake.jl | 3 +-- src/exports.jl | 5 +++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 907da73e3470..ac8394f69d8a 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1089,8 +1089,8 @@ end ################################################################################ ################################################################################ -function phylogenetic_tree(T::Type{<:Union{Float64, Int, QQFieldElem}}, newick::String) - pm_ptree = Polymake.graph.PhylogeneticTree{T}(NEWICK = newick) +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 @@ -1106,5 +1106,24 @@ function phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: scalar return PhylogeneticTree{T}(pm_ptree) end +function adjacency_tree(ptree::PhylogeneticTree) + return ptree.pm_ptree.ADJACENCY +end + +function equidistant(ptree::PhylogeneticTree) + return ptree.pm_ptree.EQUIDISTANT +end + +function cophenetic_matrix(ptree::PhylogeneticTree) + return convert(Matrix, ptree.pm_ptree.COPHENETIC_MATRIX) +end + +function taxa(ptree::PhylogeneticTree) + return convert(Array{String}, ptree.pm_ptree.TAXA) +end + +function newick(ptree::PhylogeneticTree) + return ptree.pm_ptree.NEWICK +end diff --git a/src/Combinatorics/Graphs/structs.jl b/src/Combinatorics/Graphs/structs.jl index b972e04328db..a0aef202796f 100644 --- a/src/Combinatorics/Graphs/structs.jl +++ b/src/Combinatorics/Graphs/structs.jl @@ -2,10 +2,10 @@ 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 -mutable struct PhylogeneticTree{T <: Union{Float64, Int, QQFieldElem}} +mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} pm_ptree::Polymake.LibPolymake.BigObjectAllocated end diff --git a/src/Serialization/polymake.jl b/src/Serialization/polymake.jl index a29e5b2b92b5..fec4107c49c7 100644 --- a/src/Serialization/polymake.jl +++ b/src/Serialization/polymake.jl @@ -27,8 +27,7 @@ const polymake2OscarTypes = Dict{String, Type}([ "common::GraphAdjacency" => Graph{Undirected}, "common::GraphAdjacency" => Graph{Directed}, "graph::PhylogeneticTree" => PhylogeneticTree{QQFieldElem}, - "graph::PhylogeneticTree" => PhylogeneticTree{Float64}, - "graph::PhylogeneticTree" => PhylogeneticTree{Int} + "graph::PhylogeneticTree" => PhylogeneticTree{Float64} ]) @register_serialization_type Polymake.BigObjectAllocated "Polymake.BigObject" uses_id diff --git a/src/exports.jl b/src/exports.jl index d5bd00a3588e..255b21472a2d 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -198,6 +198,7 @@ export add_edge! export add_glueing! export add_vertex! export add_vertices! +export adjacency_tree export adjacent_chamber export affine_algebra export affine_charts @@ -400,6 +401,7 @@ export coordinate_names_of_torus export coordinate_ring export coordinate_ring_of_torus export coordinates +export cophenetic_matrix export corank export core export corresponding_bilinear_form @@ -503,6 +505,7 @@ export equidimensional_decomposition_radical export equidimensional_decomposition_weak export equidimensional_hull export equidimensional_hull_radical +export equidistant export euler_characteristic export euler_phi export expand @@ -1051,6 +1054,7 @@ export negwdeglex export negwdegrevlex export neighbor_patches export neighbors +export newick export newton_polytope export nfacets export ngens @@ -1393,6 +1397,7 @@ export syz export syzygy_generators export tail export tangent_space +export taxa export tensor_product export terms export tetrahedron From f75154ae605c73c93c3afdbe9e3969f523b16dcf Mon Sep 17 00:00:00 2001 From: Andrei Comaneci Date: Thu, 25 Jan 2024 12:40:33 +0100 Subject: [PATCH 05/46] Tropical median consensus added --- src/Combinatorics/Graphs/functions.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index ac8394f69d8a..9516ad69dd02 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1126,4 +1126,27 @@ function newick(ptree::PhylogeneticTree) return ptree.pm_ptree.NEWICK end +function tropical_median_consensus(arr::Array{PhylogeneticTree{T}}) where + T <: Union{Float64, QQFieldElem} + + n = length(arr) + @req n > 0 "The array must not be empty" + + phylo_type = Polymake.bigobject_type(arr[1].pm_ptree) + pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) + + for i in 1:n + pm_arr[i] = arr[i].pm_ptree + end + + pm_cons_tree = Polymake.tropical.tropical_median_consensus(pm_arr) + return PhylogeneticTree{T}(pm_cons_tree) +end + +function tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N} + return tropical_median_consensus(collect(trees)) +end + + + From e83215961841a571f7190863579aea4553a4950f Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Thu, 1 Feb 2024 11:23:16 +0100 Subject: [PATCH 06/46] export consensus --- src/Combinatorics/Graphs/.functions.jl.swp | Bin 0 -> 1024 bytes src/Combinatorics/Graphs/functions.jl | 6 +++--- src/exports.jl | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 src/Combinatorics/Graphs/.functions.jl.swp diff --git a/src/Combinatorics/Graphs/.functions.jl.swp b/src/Combinatorics/Graphs/.functions.jl.swp new file mode 100644 index 0000000000000000000000000000000000000000..fec793c42bc4b09dbd3a7e6de5ee7e2f4351c309 GIT binary patch literal 1024 zcmYc?$V<%2S1{8vVn6|#q!}0zlk;;?1aWX2^HPdZGjT{F38$6jC6{F8=N0Q^ Date: Thu, 1 Feb 2024 13:24:22 +0100 Subject: [PATCH 07/46] docs for phylo functions --- src/Combinatorics/Graphs/functions.jl | 160 +++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 2 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index e31f82b8717d..04d33ee8f026 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1092,7 +1092,33 @@ end ## Phylogenetic Trees ################################################################################ ################################################################################ +@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) @@ -1102,6 +1128,36 @@ function phylogenetic_tree(T::Type{<:Union{Float64, QQFieldElem}}, newick::Strin 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{T}, taxa::Vector{String}) where T <: Union{Float64, QQFieldElem} n_taxa = length(taxa) @req (n_taxa, n_taxa) == size(M) "Number of taxa should match the rows and columns of the given matrix" @@ -1110,31 +1166,131 @@ function phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: Union{ return PhylogeneticTree{T}(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) 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 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) return convert(Matrix, ptree.pm_ptree.COPHENETIC_MATRIX) 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) 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) end -function tropical_median_consensus(arr::Array{PhylogeneticTree{T}}) where +function tropical_median_consensus(arr::Vector{PhylogeneticTree{T}}) where T <: Union{Float64, QQFieldElem} n = length(arr) - @req n > 0 "The array must not be empty" + @req n > 0 "The vector must not be empty" phylo_type = Polymake.bigobject_type(arr[1].pm_ptree) pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) From 9c8cbdded4d1cd295153509c0181df7287e0a4fb Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Thu, 1 Feb 2024 13:59:57 +0100 Subject: [PATCH 08/46] doc tropical median consensus --- src/Combinatorics/Graphs/functions.jl | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index c2d3188d7d1e..9a5f7d333fd8 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1285,6 +1285,32 @@ function newick(ptree::PhylogeneticTree) return convert(String, ptree.pm_ptree.NEWICK) 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} @@ -1302,6 +1328,30 @@ function tropical_median_consensus(arr::Vector{PhylogeneticTree{T}}) where 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 From da8cc8a80dd706a19df706b7311f0a7d99088b83 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Thu, 1 Feb 2024 14:01:46 +0100 Subject: [PATCH 09/46] tropical_median_consensus to md file --- docs/src/Combinatorics/phylogenetic_trees.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/Combinatorics/phylogenetic_trees.md b/docs/src/Combinatorics/phylogenetic_trees.md index e7063662f77e..e09e0fc64c78 100644 --- a/docs/src/Combinatorics/phylogenetic_trees.md +++ b/docs/src/Combinatorics/phylogenetic_trees.md @@ -22,4 +22,5 @@ equidistant cophenetic_matrix taxa newick +tropical_median_consensus ``` From fa72603581d7fe7c2ecc26cd85604c0453568414 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Thu, 1 Feb 2024 14:13:53 +0100 Subject: [PATCH 10/46] add intro doc phylogenetics --- docs/src/Combinatorics/phylogenetic_trees.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/Combinatorics/phylogenetic_trees.md b/docs/src/Combinatorics/phylogenetic_trees.md index e09e0fc64c78..457e5b64b141 100644 --- a/docs/src/Combinatorics/phylogenetic_trees.md +++ b/docs/src/Combinatorics/phylogenetic_trees.md @@ -6,7 +6,8 @@ CurrentModule = Oscar ## Introduction -add intro here +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. ## Construction From 3b9d2b189d1b857f4309d7ac8d1a5aa6b6e448d2 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Thu, 1 Feb 2024 16:34:38 +0100 Subject: [PATCH 11/46] added some test skeleton and some docs --- docs/doc.main | 1 + docs/src/Combinatorics/phylogenetic_trees.md | 26 ++++++++++++++++++++ src/Combinatorics/Graphs/functions.jl | 5 ++-- test/Combinatorics/PhylogeneticTrees.jl | 22 ++++++++++++++--- 4 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 docs/src/Combinatorics/phylogenetic_trees.md diff --git a/docs/doc.main b/docs/doc.main index cacbdecb6bbe..76aa682244ec 100644 --- a/docs/doc.main +++ b/docs/doc.main @@ -231,6 +231,7 @@ "Combinatorics/partitions.md", "Combinatorics/tableaux.md", "Combinatorics/schur_polynomials.md", + "Combinatorics/phylogenetic_trees.md" ], "Straight Line Programs" => [ diff --git a/docs/src/Combinatorics/phylogenetic_trees.md b/docs/src/Combinatorics/phylogenetic_trees.md new file mode 100644 index 000000000000..e09e0fc64c78 --- /dev/null +++ b/docs/src/Combinatorics/phylogenetic_trees.md @@ -0,0 +1,26 @@ +```@meta +CurrentModule = Oscar +``` + +# Phylogenetic Trees + +## Introduction + +add intro here + +## Construction + +```@docs +phylogenetic_tree +``` + +## Some Helpful Functions + +```@docs +adjacency_tree +equidistant +cophenetic_matrix +taxa +newick +tropical_median_consensus +``` diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index e31f82b8717d..c4e06ce77e59 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1105,7 +1105,6 @@ end function phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: Union{Float64, QQFieldElem} 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{T}(COPHENETIC_MATRIX = M, TAXA = taxa) return PhylogeneticTree{T}(pm_ptree) end @@ -1130,11 +1129,11 @@ function newick(ptree::PhylogeneticTree) return convert(String, ptree.pm_ptree.NEWICK) end -function tropical_median_consensus(arr::Array{PhylogeneticTree{T}}) where +function tropical_median_consensus(arr::Vector{PhylogeneticTree{T}}) where T <: Union{Float64, QQFieldElem} n = length(arr) - @req n > 0 "The array must not be empty" + @req n > 0 "The vector must not be empty" phylo_type = Polymake.bigobject_type(arr[1].pm_ptree) pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl index 3cd7a3f34299..228986e75606 100644 --- a/test/Combinatorics/PhylogeneticTrees.jl +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -1,6 +1,20 @@ @testset "Phylogenetic Trees" begin - @testset "constructors" begin - ptree1 = phylogenetic_tree(Float64, "((A:4,B:4):5,C:9);") - ptree2 = phylogenetic_tree([0 4 9; 4 0 9; 9.0 9 0], ["a", "b", "c"]) - end + ptree1 = phylogenetic_tree(Float64, "((A:4,B:4):5,C:9);") + + # waiting for dante and marcel for a graph constructor + adjacency_tree(ptree1) + + @test equidistant(ptree1) == true + + + # this will need a conversion + M = matrix(QQ, [0 4 9; 4 0 9; 9 9//2 0]) + ptree2 = phylogenetic_tree(M, ["A", "B", "C"]) + + cophenetic_matrix(ptree2) + @test newick(ptree2) == "c:4.5,(a:2,b:2):2.5;" + @test taxa(ptree2) == ["a", "b", "c"] + ptree2_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["A", "B", "C"]) + + tropical_median_consensus(ptree2_test, ptree2) end From f9afdad3e6f61c1d066fd57cda2967a27207396a Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Thu, 1 Feb 2024 16:43:51 +0100 Subject: [PATCH 12/46] remove doc for now --- docs/src/Combinatorics/phylogenetic_trees.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/Combinatorics/phylogenetic_trees.md b/docs/src/Combinatorics/phylogenetic_trees.md index e09e0fc64c78..e7063662f77e 100644 --- a/docs/src/Combinatorics/phylogenetic_trees.md +++ b/docs/src/Combinatorics/phylogenetic_trees.md @@ -22,5 +22,4 @@ equidistant cophenetic_matrix taxa newick -tropical_median_consensus ``` From 7bceabd383cd0a9241f831f6e191988b5ee21704 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Thu, 1 Feb 2024 17:10:54 +0100 Subject: [PATCH 13/46] added more stuff to tests --- test/Combinatorics/PhylogeneticTrees.jl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl index 228986e75606..56b1cde20cd4 100644 --- a/test/Combinatorics/PhylogeneticTrees.jl +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -1,20 +1,22 @@ @testset "Phylogenetic Trees" begin ptree1 = phylogenetic_tree(Float64, "((A:4,B:4):5,C:9);") - + # waiting for dante and marcel for a graph constructor adjacency_tree(ptree1) @test equidistant(ptree1) == true - # this will need a conversion M = matrix(QQ, [0 4 9; 4 0 9; 9 9//2 0]) - ptree2 = phylogenetic_tree(M, ["A", "B", "C"]) + ptree2 = phylogenetic_tree(M, ["a", "b", "c"]) cophenetic_matrix(ptree2) @test newick(ptree2) == "c:4.5,(a:2,b:2):2.5;" @test taxa(ptree2) == ["a", "b", "c"] - ptree2_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["A", "B", "C"]) - - tropical_median_consensus(ptree2_test, ptree2) + + ptree2_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["a", "b", "c"]) + tmc = tropical_median_consensus(ptree2_test, ptree2) + tmc_v = tropical_median_consensus([ptree2_test, ptree2]) + @test newick(tmc) == "c:4.5,(a:2,b:2):2.5;" + @test newick(tmc_v) == "c:4.5,(a:2,b:2):2.5;" end From 32ff0d05aadc7b3393f8ce164caa63bae67b8382 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Thu, 1 Feb 2024 17:41:33 +0100 Subject: [PATCH 14/46] add fix for QQField matrix type --- src/Combinatorics/Graphs/functions.jl | 14 +++++++++++++- test/Combinatorics/PhylogeneticTrees.jl | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 9a5f7d333fd8..3697b68655d5 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1158,13 +1158,25 @@ julia> newick(tree_mat) "Gorilla:4,(Human:3,(Bonobo:1,Chimpanzee:1):2):1;" ``` """ -function phylogenetic_tree(M::Matrix{T}, taxa::Vector{String}) where T <: Union{Float64, QQFieldElem} +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{T}(COPHENETIC_MATRIX = M, TAXA = taxa) return PhylogeneticTree{T}(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)) + + pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( + COPHENETIC_MATRIX = M, TAXA = taxa + ) + return PhylogeneticTree{QQFieldElem}(pm_ptree) +end + @doc raw""" adjacency_tree(ptree::PhylogeneticTree) diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl index 56b1cde20cd4..ce65785decdb 100644 --- a/test/Combinatorics/PhylogeneticTrees.jl +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -7,7 +7,7 @@ @test equidistant(ptree1) == true # this will need a conversion - M = matrix(QQ, [0 4 9; 4 0 9; 9 9//2 0]) + M = matrix(QQ, [0 4 9; 4 0 9; 9 9 0]) ptree2 = phylogenetic_tree(M, ["a", "b", "c"]) cophenetic_matrix(ptree2) From 048ab8339a0261c1296b8c73e5c25cf0ac7f6133 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Thu, 1 Feb 2024 18:05:21 +0100 Subject: [PATCH 15/46] fix printing --- src/Combinatorics/Graphs/functions.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index fe610d4dc1b8..8577d524a483 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1159,8 +1159,8 @@ julia> newick(tree_mat) 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{T}(COPHENETIC_MATRIX = M, TAXA = taxa) - return PhylogeneticTree{T}(pm_ptree) + 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}) @@ -1195,6 +1195,9 @@ function adjacency_tree(ptree::PhylogeneticTree) return Graph{Undirected}(ptree.pm_ptree.ADJACENCY) 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) From 8ac80ab6a11b3fc4a829de4390ed3582191b72b6 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Fri, 2 Feb 2024 15:01:00 +0100 Subject: [PATCH 16/46] this might fix the export issues --- src/exports.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/exports.jl b/src/exports.jl index f4a924634708..b66dd477408d 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -1390,7 +1390,6 @@ export symplectic_group export syz export syzygy_generators export tail -export tangent_space export tangent_lines export tangent_space export taxa From 75be07e025c02f814f1edca0e6fdaa74721b6228 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Thu, 1 Feb 2024 23:05:22 +0100 Subject: [PATCH 17/46] removed undefined method from exports --- src/exports.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/exports.jl b/src/exports.jl index b66dd477408d..bf593366873f 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -1427,7 +1427,6 @@ export trivial_morphism export trivial_subgroup, has_trivial_subgroup, set_trivial_subgroup export tropical_matrix export tropical_median_consensus -export tropical_points export tropical_polynomial export tropical_pluecker_vector export tropical_polynomial From e63cde2dff5ee284ae5a341e1543b2df57e4a633 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Thu, 1 Feb 2024 23:55:01 +0100 Subject: [PATCH 18/46] fix tests --- src/Combinatorics/Graphs/functions.jl | 2 +- test/Combinatorics/PhylogeneticTrees.jl | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 8577d524a483..b03c343e653a 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1365,7 +1365,7 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N} +function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}, N}) where {T,N} return tropical_median_consensus(collect(trees)) end diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl index ce65785decdb..09364d4c4f5e 100644 --- a/test/Combinatorics/PhylogeneticTrees.jl +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -6,17 +6,16 @@ @test equidistant(ptree1) == true - # this will need a conversion M = matrix(QQ, [0 4 9; 4 0 9; 9 9 0]) ptree2 = phylogenetic_tree(M, ["a", "b", "c"]) cophenetic_matrix(ptree2) - @test newick(ptree2) == "c:4.5,(a:2,b:2):2.5;" + @test newick(ptree2) == "c:9/2,(a:2,b:2):5/2;" @test taxa(ptree2) == ["a", "b", "c"] - ptree2_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["a", "b", "c"]) - tmc = tropical_median_consensus(ptree2_test, ptree2) - tmc_v = tropical_median_consensus([ptree2_test, ptree2]) - @test newick(tmc) == "c:4.5,(a:2,b:2):2.5;" - @test newick(tmc_v) == "c:4.5,(a:2,b:2):2.5;" + ptree1_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["A", "B", "C"]) + tmc = tropical_median_consensus(ptree1_test, ptree1) + tmc_v = tropical_median_consensus([ptree1_test, ptree1]) + @test newick(tmc) == "C:9,(A:6.5,B:6.5):2.5;" + @test newick(tmc_v) == "C:9,(A:6.5,B:6.5):2.5;" end From dab3e8e1d8be8d6d65bd71e17ff73a0dfb0c58ac Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Fri, 2 Feb 2024 00:04:51 +0100 Subject: [PATCH 19/46] eliminate duplicate in exports.jl --- src/exports.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/exports.jl b/src/exports.jl index bf593366873f..6e7f9aba0c27 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -1427,7 +1427,6 @@ export trivial_morphism export trivial_subgroup, has_trivial_subgroup, set_trivial_subgroup export tropical_matrix export tropical_median_consensus -export tropical_polynomial export tropical_pluecker_vector export tropical_polynomial export tropical_variety From 44e602ac217d012ae992bc127319664379bb1977 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Fri, 2 Feb 2024 00:21:57 +0100 Subject: [PATCH 20/46] remove the unused param T --- src/Combinatorics/Graphs/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index b03c343e653a..3401ba5a6f20 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1365,7 +1365,7 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}, N}) where {T,N} +function tropical_median_consensus(trees::Vararg{<:PhylogeneticTree, N}) where {N} return tropical_median_consensus(collect(trees)) end From 4500fbf9dfde2780b4e7562250d2529d16b9eafd Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Fri, 2 Feb 2024 00:30:03 +0100 Subject: [PATCH 21/46] change where T in Varargs{phylo} --- src/Combinatorics/Graphs/functions.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 3401ba5a6f20..b0626eb9280f 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1365,7 +1365,8 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{<:PhylogeneticTree, N}) where {N} +function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}, N}) + where {N, T <: Union{Float64, QQFieldElem}} return tropical_median_consensus(collect(trees)) end From 2f0be235f6b999a51667a52148823767c1e7e672 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Fri, 2 Feb 2024 00:37:28 +0100 Subject: [PATCH 22/46] removed spaces around where --- src/Combinatorics/Graphs/functions.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index b0626eb9280f..f2a984938c28 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1324,8 +1324,7 @@ 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} +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" @@ -1365,8 +1364,7 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}, N}) - where {N, T <: Union{Float64, QQFieldElem}} +function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}, N}) where {N, T <: Union{Float64, QQFieldElem}} return tropical_median_consensus(collect(trees)) end From 020b569cfe86ce7731b08d73d4018fd6e3ebc57b Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Fri, 2 Feb 2024 00:56:43 +0100 Subject: [PATCH 23/46] change deprecated where --- src/Combinatorics/Graphs/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 57114d0b8f1c..5039335a88b0 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1364,7 +1364,7 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{<: PhylogeneticTree}) +function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}}) where T <: Union{Float64, QQFieldElem} return tropical_median_consensus(collect(trees)) end From a1315a8d0551c7c85f6d87a7161b87d3c7823925 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Fri, 2 Feb 2024 18:21:57 +0100 Subject: [PATCH 24/46] trying to fix arg types --- src/Combinatorics/Graphs/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index f2a984938c28..57114d0b8f1c 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1364,7 +1364,7 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}, N}) where {N, T <: Union{Float64, QQFieldElem}} +function tropical_median_consensus(trees::Vararg{<: PhylogeneticTree}) return tropical_median_consensus(collect(trees)) end From 4301b2f0a038911e28154a68a17da8b2993583de Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Fri, 2 Feb 2024 18:28:42 +0100 Subject: [PATCH 25/46] fixing vararg --- src/Combinatorics/Graphs/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 57114d0b8f1c..55979bfa65f5 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1364,7 +1364,7 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{<: PhylogeneticTree}) +function tropical_median_consensus(trees::Vararg{T}) where T <: PhylogeneticTree return tropical_median_consensus(collect(trees)) end From 9ccf31580220f06a7a5db3757b11b0430e52ac9d Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Sat, 3 Feb 2024 09:53:04 +0100 Subject: [PATCH 26/46] removed swp file --- src/Combinatorics/Graphs/.functions.jl.swp | Bin 1024 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/Combinatorics/Graphs/.functions.jl.swp diff --git a/src/Combinatorics/Graphs/.functions.jl.swp b/src/Combinatorics/Graphs/.functions.jl.swp deleted file mode 100644 index fec793c42bc4b09dbd3a7e6de5ee7e2f4351c309..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1024 zcmYc?$V<%2S1{8vVn6|#q!}0zlk;;?1aWX2^HPdZGjT{F38$6jC6{F8=N0Q^ Date: Sat, 3 Feb 2024 10:08:28 +0100 Subject: [PATCH 27/46] add undirected adjacency --- src/Combinatorics/Graphs/functions.jl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 6c4b0a9f7a3e..237fc62bad7e 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1368,5 +1368,27 @@ function tropical_median_consensus(trees::Tuple{T, Vararg{T}}) where T <: Phylog return tropical_median_consensus(collect(trees)) end +function directed_adjacency(ptree::PhylogeneticTree{T}) where T <: Union{Float64, QQFieldElem} + udir_tree = adjacency_tree(ptree) + n = nv(udir_tree) + # list_edges = collect(edges(udir_tree)) + dir_tree = Graph{Directed}(n) + + queue = [1] + visited = fill(false, n) + visited[1] = true + while length(queue) > 0 + x = popfirst!(queue) + for y in neighbors(udir_tree, x) + if visited[y] == false + add_edge!(dir_tree, x, y) + push!(queue, y) + visited[y] = true + end + end + end + + return dir_tree +end From 3be4b7f4abeb08e5ce08179bacf6c8d5d7c32bb0 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Sat, 3 Feb 2024 10:15:52 +0100 Subject: [PATCH 28/46] i think this might work --- src/Combinatorics/Graphs/functions.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 55979bfa65f5..6c4b0a9f7a3e 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1364,10 +1364,9 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{T}) where T <: PhylogeneticTree +function tropical_median_consensus(trees::Tuple{T, Vararg{T}}) where T <: PhylogeneticTree return tropical_median_consensus(collect(trees)) end - From 6292a40c144200c8d2c51a895d6364093c1d1da4 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Sat, 3 Feb 2024 10:24:16 +0100 Subject: [PATCH 29/46] remove vararg function --- src/Combinatorics/Graphs/functions.jl | 29 +++------------------------ 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 4a71ae20acdd..337517c06481 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1341,32 +1341,9 @@ function tropical_median_consensus(arr::Vector{PhylogeneticTree{T}}) where {T <: 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...) - return tropical_median_consensus(trees) -end +#function tropical_median_consensus(trees...) +# return tropical_median_consensus(trees) +#end function directed_adjacency(ptree::PhylogeneticTree{T}) where T <: Union{Float64, QQFieldElem} udir_tree = adjacency_tree(ptree) From d3d91f048eb53a4269190828a8142e69d90028a7 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Sat, 3 Feb 2024 10:42:45 +0100 Subject: [PATCH 30/46] trying again with signature --- src/Combinatorics/Graphs/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 6c4b0a9f7a3e..addcffce13cf 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1364,7 +1364,7 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Tuple{T, Vararg{T}}) where T <: PhylogeneticTree +function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}}) where T <: Union{QQFieldElem, Float64} return tropical_median_consensus(collect(trees)) end From 3c2635e6b07c6fb7f4d23479553286033fcca0cf Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Sat, 3 Feb 2024 10:59:07 +0100 Subject: [PATCH 31/46] use splat --- src/Combinatorics/Graphs/functions.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index addcffce13cf..c9dfc148c1a3 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1364,8 +1364,8 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees::Vararg{PhylogeneticTree{T}}) where T <: Union{QQFieldElem, Float64} - return tropical_median_consensus(collect(trees)) +function tropical_median_consensus(trees...) + return tropical_median_consensus(trees) end From f511afaf65ec4e727472651267dc5fcdf3d595a1 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Tue, 6 Feb 2024 15:05:53 +0100 Subject: [PATCH 32/46] adjacency_tree returns a directed graph now --- src/Combinatorics/Graphs/functions.jl | 49 +++++++++++++-------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 337517c06481..31b727776c20 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1178,7 +1178,7 @@ end @doc raw""" adjacency_tree(ptree::PhylogeneticTree) -Returns the underlying graph of the phylogenetic tree `ptree`. +Returns the underlying graph of the phylogenetic tree `ptree`. It will be an directed tree with edges directed away from the root (labeled with 1). # Examples Make a phylogenetic tree with given Newick format and print its underlying graph. @@ -1187,12 +1187,31 @@ Make a phylogenetic tree with given Newick format and print its underlying graph 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) +Directed graph with 7 nodes and the following edges: +(1, 2)(1, 7)(2, 3)(2, 4)(4, 5)(4, 6) ``` """ function adjacency_tree(ptree::PhylogeneticTree) - return Graph{Undirected}(ptree.pm_ptree.ADJACENCY) + udir_tree = Graph{Undirected}(ptree.pm_ptree.ADJACENCY) + n = nv(udir_tree) + # list_edges = collect(edges(udir_tree)) + dir_tree = Graph{Directed}(n) + + queue = [1] + visited = fill(false, n) + visited[1] = true + while length(queue) > 0 + x = popfirst!(queue) + for y in neighbors(udir_tree, x) + if visited[y] == false + add_edge!(dir_tree, x, y) + push!(queue, y) + visited[y] = true + end + end + end + + return dir_tree end function Base.show(io::IO, ptree::PhylogeneticTree{T}) where T @@ -1345,27 +1364,5 @@ end # return tropical_median_consensus(trees) #end -function directed_adjacency(ptree::PhylogeneticTree{T}) where T <: Union{Float64, QQFieldElem} - udir_tree = adjacency_tree(ptree) - n = nv(udir_tree) - # list_edges = collect(edges(udir_tree)) - dir_tree = Graph{Directed}(n) - - queue = [1] - visited = fill(false, n) - visited[1] = true - while length(queue) > 0 - x = popfirst!(queue) - for y in neighbors(udir_tree, x) - if visited[y] == false - add_edge!(dir_tree, x, y) - push!(queue, y) - visited[y] = true - end - end - end - - return dir_tree -end From 20666a5f9702c185579536c4f49b76629ba028a5 Mon Sep 17 00:00:00 2001 From: andreicomaneci Date: Tue, 6 Feb 2024 15:08:44 +0100 Subject: [PATCH 33/46] update tests --- test/Combinatorics/PhylogeneticTrees.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl index 09364d4c4f5e..c5c21de74d6d 100644 --- a/test/Combinatorics/PhylogeneticTrees.jl +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -14,8 +14,8 @@ @test taxa(ptree2) == ["a", "b", "c"] ptree1_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["A", "B", "C"]) - tmc = tropical_median_consensus(ptree1_test, ptree1) + # tmc = tropical_median_consensus(ptree1_test, ptree1) -- Varargs method removed tmc_v = tropical_median_consensus([ptree1_test, ptree1]) - @test newick(tmc) == "C:9,(A:6.5,B:6.5):2.5;" + # @test newick(tmc) == "C:9,(A:6.5,B:6.5):2.5;" @test newick(tmc_v) == "C:9,(A:6.5,B:6.5):2.5;" end From 09ac0f8adb6ef2d8a2e5b7c13e1a472707043255 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Tue, 6 Feb 2024 16:34:55 +0100 Subject: [PATCH 34/46] makes some type and signature fixes and adjustments to tests --- src/Combinatorics/Graphs/functions.jl | 10 +++++++--- test/Combinatorics/PhylogeneticTrees.jl | 20 +++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index fc349bb0017a..a3e9ec7cb5e7 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1238,10 +1238,14 @@ julia> cophenetic_matrix(ptree) 6.0 6.0 8.0 0.0 ``` """ -function cophenetic_matrix(ptree::PhylogeneticTree) +function cophenetic_matrix(ptree::PhylogeneticTree{Float64}) return convert(Matrix, ptree.pm_ptree.COPHENETIC_MATRIX) end +function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) + return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) +end + @doc raw""" taxa(ptree::PhylogeneticTree) @@ -1364,8 +1368,8 @@ julia> newick(tc) "G:40,(B:35,(C:30,H:30):5):5;" ``` """ -function tropical_median_consensus(trees...) - return tropical_median_consensus(trees) +function tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N} + return tropical_median_consensus(collect(trees)) end function graph_from_edges(::Type{T}, diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl index 09364d4c4f5e..e0221dc814ea 100644 --- a/test/Combinatorics/PhylogeneticTrees.jl +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -1,21 +1,19 @@ @testset "Phylogenetic Trees" begin ptree1 = phylogenetic_tree(Float64, "((A:4,B:4):5,C:9);") - - # waiting for dante and marcel for a graph constructor - adjacency_tree(ptree1) - + test_tree = graph_from_edges([[2, 1], [3, 2], [4, 2], [5, 1]]) + @test is_isomorphic(adjacency_tree(ptree1), test_tree) @test equidistant(ptree1) == true - M = matrix(QQ, [0 4 9; 4 0 9; 9 9 0]) - ptree2 = phylogenetic_tree(M, ["a", "b", "c"]) - - cophenetic_matrix(ptree2) - @test newick(ptree2) == "c:9/2,(a:2,b:2):5/2;" - @test taxa(ptree2) == ["a", "b", "c"] - ptree1_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["A", "B", "C"]) tmc = tropical_median_consensus(ptree1_test, ptree1) tmc_v = tropical_median_consensus([ptree1_test, ptree1]) @test newick(tmc) == "C:9,(A:6.5,B:6.5):2.5;" @test newick(tmc_v) == "C:9,(A:6.5,B:6.5):2.5;" + + M = matrix(QQ, [0 4 9; 4 0 9; 9 9 0]) + ptree2 = phylogenetic_tree(M, ["a", "b", "c"]) + + @test cophenetic_matrix(ptree2) == matrix(QQ, [0 4 9; 4 0 9; 9 9 0]) + @test newick(ptree2) == "c:9/2,(a:2,b:2):5/2;" + @test taxa(ptree2) == ["a", "b", "c"] end From 7dad693e2f0638f2bce147a4357a76af95822aa2 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Tue, 6 Feb 2024 16:39:33 +0100 Subject: [PATCH 35/46] Revert "Merge remote-tracking branch 'andrei/adv+ac/phylogenetic-trees' into adv+ac/phylogenetic-trees" This reverts commit 38f47b24ac6f3943f6b4060ea4cf64302d74e34e, reversing changes made to 09ac0f8adb6ef2d8a2e5b7c13e1a472707043255. --- src/Combinatorics/Graphs/.functions.jl.swp | Bin 0 -> 1024 bytes src/Combinatorics/Graphs/functions.jl | 126 +++++++++------------ test/Combinatorics/PhylogeneticTrees.jl | 4 +- 3 files changed, 58 insertions(+), 72 deletions(-) create mode 100644 src/Combinatorics/Graphs/.functions.jl.swp diff --git a/src/Combinatorics/Graphs/.functions.jl.swp b/src/Combinatorics/Graphs/.functions.jl.swp new file mode 100644 index 0000000000000000000000000000000000000000..fec793c42bc4b09dbd3a7e6de5ee7e2f4351c309 GIT binary patch literal 1024 zcmYc?$V<%2S1{8vVn6|#q!}0zlk;;?1aWX2^HPdZGjT{F38$6jC6{F8=N0Q^= 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)) - end - - return g -end - -graph_from_edges(::Type{T}, -edges::EdgeIterator, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) - -@doc raw""" - graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} - -Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. - -# Examples 1 -```jldoctest -julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) -Undirected graph with 5 nodes and the following edges: -(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) - -``` - -``` -# Examples 2 -```jldoctest -julia> G = graph_from_edges(Undirected,[[1,3]]) -Undirected graph with 3 nodes and the following edges: -(3, 1)) - -``` -""" -graph_from_edges(::Type{T}, -edges::Vector{Vector{Int}}, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) -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) @doc raw""" visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} @@ -1068,6 +1021,8 @@ function visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Un Polymake.visual(BigGraph) end + + # Some standard polytopes from graphs @doc raw""" fractional_cut_polytope(G::Graph{Undirected}) @@ -1223,7 +1178,7 @@ end @doc raw""" adjacency_tree(ptree::PhylogeneticTree) -Returns the underlying graph of the phylogenetic tree `ptree`. It will be an directed tree with edges directed away from the root (labeled with 1). +Returns the underlying graph of the phylogenetic tree `ptree`. # Examples Make a phylogenetic tree with given Newick format and print its underlying graph. @@ -1232,31 +1187,12 @@ Make a phylogenetic tree with given Newick format and print its underlying graph julia> ptree = phylogenetic_tree(Float64, "((H:3,(C:1,B:1):2):1,G:4);"); julia> adjacency_tree(ptree) -Directed graph with 7 nodes and the following edges: -(1, 2)(1, 7)(2, 3)(2, 4)(4, 5)(4, 6) +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) - udir_tree = Graph{Undirected}(ptree.pm_ptree.ADJACENCY) - n = nv(udir_tree) - # list_edges = collect(edges(udir_tree)) - dir_tree = Graph{Directed}(n) - - queue = [1] - visited = fill(false, n) - visited[1] = true - while length(queue) > 0 - x = popfirst!(queue) - for y in neighbors(udir_tree, x) - if visited[y] == false - add_edge!(dir_tree, x, y) - push!(queue, y) - visited[y] = true - end - end - end - - return dir_tree + return Graph{Undirected}(ptree.pm_ptree.ADJACENCY) end function Base.show(io::IO, ptree::PhylogeneticTree{T}) where T @@ -1408,6 +1344,7 @@ function tropical_median_consensus(arr::Vector{PhylogeneticTree{T}}) where {T <: return PhylogeneticTree{T}(pm_cons_tree) end + @doc raw""" tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N} @@ -1434,3 +1371,52 @@ julia> newick(tc) function tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N} return tropical_median_consensus(collect(trees)) end + +function graph_from_edges(::Type{T}, + edges::Vector{Edge}, + n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} + + 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)) + end + + return g +end + +graph_from_edges(::Type{T}, +edges::EdgeIterator, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) + +@doc raw""" + graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} + +Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. + +# Examples 1 +```jldoctest +julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) +Undirected graph with 5 nodes and the following edges: +(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) + +``` + +``` +# Examples 2 +```jldoctest +julia> G = graph_from_edges(Undirected,[[1,3]]) +Undirected graph with 3 nodes and the following edges: +(3, 1)) + +``` +""" +graph_from_edges(::Type{T}, +edges::Vector{Vector{Int}}, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) + +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) diff --git a/test/Combinatorics/PhylogeneticTrees.jl b/test/Combinatorics/PhylogeneticTrees.jl index fcb86b1d7666..e0221dc814ea 100644 --- a/test/Combinatorics/PhylogeneticTrees.jl +++ b/test/Combinatorics/PhylogeneticTrees.jl @@ -5,9 +5,9 @@ @test equidistant(ptree1) == true ptree1_test = phylogenetic_tree([0 4 9; 4 0 9.0; 9 9 0], ["A", "B", "C"]) - # tmc = tropical_median_consensus(ptree1_test, ptree1) -- Varargs method removed + tmc = tropical_median_consensus(ptree1_test, ptree1) tmc_v = tropical_median_consensus([ptree1_test, ptree1]) - # @test newick(tmc) == "C:9,(A:6.5,B:6.5):2.5;" + @test newick(tmc) == "C:9,(A:6.5,B:6.5):2.5;" @test newick(tmc_v) == "C:9,(A:6.5,B:6.5):2.5;" M = matrix(QQ, [0 4 9; 4 0 9; 9 9 0]) From d9a06530bbabc17c36d90eaa5f8be42de6b363c1 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Tue, 6 Feb 2024 16:43:27 +0100 Subject: [PATCH 36/46] moves graph from edges up out of phylo trees section --- src/Combinatorics/Graphs/functions.jl | 98 +++++++++++++-------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index a3e9ec7cb5e7..35a598ab94cd 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -83,6 +83,55 @@ function graph_from_adjacency_matrix(::Type{T}, G::Union{MatElem, Matrix}) where end +function graph_from_edges(::Type{T}, + edges::Vector{Edge}, + n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} + + 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)) + end + + return g +end + +graph_from_edges(::Type{T}, +edges::EdgeIterator, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) + +@doc raw""" + graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} + +Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. + +# Examples 1 +```jldoctest +julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) +Undirected graph with 5 nodes and the following edges: +(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) + +``` + +``` +# Examples 2 +```jldoctest +julia> G = graph_from_edges(Undirected,[[1,3]]) +Undirected graph with 3 nodes and the following edges: +(3, 1)) + +``` +""" +graph_from_edges(::Type{T}, +edges::Vector{Vector{Int}}, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) + +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) + _has_node(G::Graph, node::Int64) = 0 < node <= nvertices(G) @doc raw""" @@ -1371,52 +1420,3 @@ julia> newick(tc) function tropical_median_consensus(trees::Vararg{PhylogeneticTree, N}) where {N} return tropical_median_consensus(collect(trees)) end - -function graph_from_edges(::Type{T}, - edges::Vector{Edge}, - n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} - - 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)) - end - - return g -end - -graph_from_edges(::Type{T}, -edges::EdgeIterator, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) - -@doc raw""" - graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} - -Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. - -# Examples 1 -```jldoctest -julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) -Undirected graph with 5 nodes and the following edges: -(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) - -``` - -``` -# Examples 2 -```jldoctest -julia> G = graph_from_edges(Undirected,[[1,3]]) -Undirected graph with 3 nodes and the following edges: -(3, 1)) - -``` -""" -graph_from_edges(::Type{T}, -edges::Vector{Vector{Int}}, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) - -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) From 0a9d603fe78105159e7eb883e6e088e7496fd854 Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Wed, 7 Feb 2024 09:54:21 +0100 Subject: [PATCH 37/46] some restructuring --- src/Combinatorics/Graphs/functions.jl | 412 ++++--------------------- src/Combinatorics/Graphs/structs.jl | 4 - src/Combinatorics/PhylogeneticTrees.jl | 290 +++++++++++++++++ 3 files changed, 347 insertions(+), 359 deletions(-) create mode 100644 src/Combinatorics/PhylogeneticTrees.jl diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 35a598ab94cd..9e5837512e1c 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -5,10 +5,6 @@ function pm_object(G::Graph{T}) where {T <: Union{Directed, Undirected}} return G.pm_graph end -function pm_object(PT::PhylogeneticTree) - return PT.pm_ptree -end - ################################################################################ ################################################################################ ## Constructing and modifying @@ -83,55 +79,6 @@ function graph_from_adjacency_matrix(::Type{T}, G::Union{MatElem, Matrix}) where end -function graph_from_edges(::Type{T}, - edges::Vector{Edge}, - n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} - - 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)) - end - - return g -end - -graph_from_edges(::Type{T}, -edges::EdgeIterator, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) - -@doc raw""" - graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} - -Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. - -# Examples 1 -```jldoctest -julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) -Undirected graph with 5 nodes and the following edges: -(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) - -``` - -``` -# Examples 2 -```jldoctest -julia> G = graph_from_edges(Undirected,[[1,3]]) -Undirected graph with 3 nodes and the following edges: -(3, 1)) - -``` -""" -graph_from_edges(::Type{T}, -edges::Vector{Vector{Int}}, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) - -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) - _has_node(G::Graph, node::Int64) = 0 < node <= nvertices(G) @doc raw""" @@ -282,11 +229,10 @@ end ################################################################################ ################################################################################ struct Edge - source::Int64 - target::Int64 + source::Int64 + target::Int64 end - @doc raw""" src(e::Edge) @@ -1012,8 +958,6 @@ function dualgraph(p::Polyhedron) return Graph{Undirected}(pmg) end - - @doc raw""" complete_graph(n::Int64) @@ -1035,7 +979,6 @@ function complete_graph(n::Int64) return Graph{Undirected}(bigobj.ADJACENCY) end - @doc raw""" complete_bipartite_graph(n::Int64, m::Int64) @@ -1059,18 +1002,54 @@ function complete_bipartite_graph(n::Int64, m::Int64) end +function graph_from_edges(::Type{T}, + edges::Vector{Edge}, + n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} -@doc raw""" - visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} + 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" -Visualize a graph. -""" -function visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} - BigGraph = Polymake.graph.Graph(ADJACENCY=pm_object(G)) - Polymake.visual(BigGraph) + g = Graph{T}(max(n_needed, n_vertices)) + for e in edges + add_edge!(g, src(e), dst(e)) + end + + return g end +graph_from_edges(::Type{T}, +edges::EdgeIterator, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) + +@doc raw""" + graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} +Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. + +# Examples 1 +```jldoctest +julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) +Undirected graph with 5 nodes and the following edges: +(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) + +``` + +``` +# Examples 2 +```jldoctest +julia> G = graph_from_edges(Undirected,[[1,3]]) +Undirected graph with 3 nodes and the following edges: +(3, 1)) + +``` +""" +graph_from_edges(::Type{T}, +edges::Vector{Vector{Int}}, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) + +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) # Some standard polytopes from graphs @doc raw""" @@ -1106,12 +1085,22 @@ Polytope in ambient dimension 6 """ fractional_matching_polytope(G::Graph{Undirected}) = polyhedron(Polymake.polytope.fractional_matching_polytope(pm_object(G))) - ################################################################################ ################################################################################ -## Printing +## Printing and Visuals ################################################################################ ################################################################################ + +@doc raw""" + visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} + +Visualize a graph. +""" +function visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} + BigGraph = Polymake.graph.Graph(ADJACENCY=pm_object(G)) + Polymake.visual(BigGraph) +end + _to_string(::Type{Polymake.Directed}) = "Directed" _to_string(::Type{Polymake.Undirected}) = "Undirected" @@ -1133,290 +1122,3 @@ function Base.show(io::IO, G::Graph{T}) where {T <: Union{Polymake.Directed, Po print(io, "$(_to_string(T)) graph with $(nvertices(G)) nodes and $(nedges(G)) edges") end end - -################################################################################ -################################################################################ -## Phylogenetic Trees -################################################################################ -################################################################################ -@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)) - - pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( - 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) -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 -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) -end - -function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) - return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) -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) -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) -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) - pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) - - for i in 1:n - pm_arr[i] = arr[i].pm_ptree - end - - 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 diff --git a/src/Combinatorics/Graphs/structs.jl b/src/Combinatorics/Graphs/structs.jl index a0aef202796f..e5b44e77610b 100644 --- a/src/Combinatorics/Graphs/structs.jl +++ b/src/Combinatorics/Graphs/structs.jl @@ -5,7 +5,3 @@ struct Graph{T <: Union{Directed, Undirected}} pm_graph::Polymake.Graph{T} end -mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} - pm_ptree::Polymake.LibPolymake.BigObjectAllocated -end - diff --git a/src/Combinatorics/PhylogeneticTrees.jl b/src/Combinatorics/PhylogeneticTrees.jl new file mode 100644 index 000000000000..b32ab340b1fa --- /dev/null +++ b/src/Combinatorics/PhylogeneticTrees.jl @@ -0,0 +1,290 @@ +mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} + pm_ptree::Polymake.LibPolymake.BigObjectAllocated +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)) + + pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( + COPHENETIC_MATRIX = M, TAXA = taxa + ) + return PhylogeneticTree{QQFieldElem}(pm_ptree) +end + + +function pm_object(PT::PhylogeneticTree) + return PT.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) +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 +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) +end + +function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) + return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) +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) +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) +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) + pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) + + for i in 1:n + pm_arr[i] = arr[i].pm_ptree + end + + 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 From c13fc9f5a206256f9e1faaaebd2a75f20d7cdbec Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Wed, 7 Feb 2024 10:26:45 +0100 Subject: [PATCH 38/46] Revert "some restructuring" This reverts commit 0a9d603fe78105159e7eb883e6e088e7496fd854. --- src/Combinatorics/Graphs/functions.jl | 412 +++++++++++++++++++++---- src/Combinatorics/Graphs/structs.jl | 4 + src/Combinatorics/PhylogeneticTrees.jl | 290 ----------------- 3 files changed, 359 insertions(+), 347 deletions(-) delete mode 100644 src/Combinatorics/PhylogeneticTrees.jl diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 9e5837512e1c..35a598ab94cd 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -5,6 +5,10 @@ function pm_object(G::Graph{T}) where {T <: Union{Directed, Undirected}} return G.pm_graph end +function pm_object(PT::PhylogeneticTree) + return PT.pm_ptree +end + ################################################################################ ################################################################################ ## Constructing and modifying @@ -79,6 +83,55 @@ function graph_from_adjacency_matrix(::Type{T}, G::Union{MatElem, Matrix}) where end +function graph_from_edges(::Type{T}, + edges::Vector{Edge}, + n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} + + 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)) + end + + return g +end + +graph_from_edges(::Type{T}, +edges::EdgeIterator, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) + +@doc raw""" + graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} + +Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. + +# Examples 1 +```jldoctest +julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) +Undirected graph with 5 nodes and the following edges: +(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) + +``` + +``` +# Examples 2 +```jldoctest +julia> G = graph_from_edges(Undirected,[[1,3]]) +Undirected graph with 3 nodes and the following edges: +(3, 1)) + +``` +""" +graph_from_edges(::Type{T}, +edges::Vector{Vector{Int}}, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) + +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) + _has_node(G::Graph, node::Int64) = 0 < node <= nvertices(G) @doc raw""" @@ -229,10 +282,11 @@ end ################################################################################ ################################################################################ struct Edge - source::Int64 - target::Int64 + source::Int64 + target::Int64 end + @doc raw""" src(e::Edge) @@ -958,6 +1012,8 @@ function dualgraph(p::Polyhedron) return Graph{Undirected}(pmg) end + + @doc raw""" complete_graph(n::Int64) @@ -979,6 +1035,7 @@ function complete_graph(n::Int64) return Graph{Undirected}(bigobj.ADJACENCY) end + @doc raw""" complete_bipartite_graph(n::Int64, m::Int64) @@ -1002,54 +1059,18 @@ function complete_bipartite_graph(n::Int64, m::Int64) end -function graph_from_edges(::Type{T}, - edges::Vector{Edge}, - n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} - - 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)) - end - - return g -end - -graph_from_edges(::Type{T}, -edges::EdgeIterator, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) @doc raw""" - graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} - -Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. - -# Examples 1 -```jldoctest -julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) -Undirected graph with 5 nodes and the following edges: -(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) - -``` - -``` -# Examples 2 -```jldoctest -julia> G = graph_from_edges(Undirected,[[1,3]]) -Undirected graph with 3 nodes and the following edges: -(3, 1)) + visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} -``` +Visualize a graph. """ -graph_from_edges(::Type{T}, -edges::Vector{Vector{Int}}, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) +function visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} + BigGraph = Polymake.graph.Graph(ADJACENCY=pm_object(G)) + Polymake.visual(BigGraph) +end + -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) # Some standard polytopes from graphs @doc raw""" @@ -1085,22 +1106,12 @@ Polytope in ambient dimension 6 """ fractional_matching_polytope(G::Graph{Undirected}) = polyhedron(Polymake.polytope.fractional_matching_polytope(pm_object(G))) + ################################################################################ ################################################################################ -## Printing and Visuals +## Printing ################################################################################ ################################################################################ - -@doc raw""" - visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} - -Visualize a graph. -""" -function visualize(G::Graph{T}) where {T <: Union{Polymake.Directed, Polymake.Undirected}} - BigGraph = Polymake.graph.Graph(ADJACENCY=pm_object(G)) - Polymake.visual(BigGraph) -end - _to_string(::Type{Polymake.Directed}) = "Directed" _to_string(::Type{Polymake.Undirected}) = "Undirected" @@ -1122,3 +1133,290 @@ function Base.show(io::IO, G::Graph{T}) where {T <: Union{Polymake.Directed, Po print(io, "$(_to_string(T)) graph with $(nvertices(G)) nodes and $(nedges(G)) edges") end end + +################################################################################ +################################################################################ +## Phylogenetic Trees +################################################################################ +################################################################################ +@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)) + + pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( + 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) +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 +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) +end + +function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) + return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) +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) +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) +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) + pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) + + for i in 1:n + pm_arr[i] = arr[i].pm_ptree + end + + 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 diff --git a/src/Combinatorics/Graphs/structs.jl b/src/Combinatorics/Graphs/structs.jl index e5b44e77610b..a0aef202796f 100644 --- a/src/Combinatorics/Graphs/structs.jl +++ b/src/Combinatorics/Graphs/structs.jl @@ -5,3 +5,7 @@ struct Graph{T <: Union{Directed, Undirected}} pm_graph::Polymake.Graph{T} end +mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} + pm_ptree::Polymake.LibPolymake.BigObjectAllocated +end + diff --git a/src/Combinatorics/PhylogeneticTrees.jl b/src/Combinatorics/PhylogeneticTrees.jl deleted file mode 100644 index b32ab340b1fa..000000000000 --- a/src/Combinatorics/PhylogeneticTrees.jl +++ /dev/null @@ -1,290 +0,0 @@ -mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} - pm_ptree::Polymake.LibPolymake.BigObjectAllocated -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)) - - pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( - COPHENETIC_MATRIX = M, TAXA = taxa - ) - return PhylogeneticTree{QQFieldElem}(pm_ptree) -end - - -function pm_object(PT::PhylogeneticTree) - return PT.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) -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 -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) -end - -function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) - return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) -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) -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) -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) - pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) - - for i in 1:n - pm_arr[i] = arr[i].pm_ptree - end - - 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 From c784565a367bdaf96745d612d15ce71760e92b17 Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Wed, 7 Feb 2024 10:29:47 +0100 Subject: [PATCH 39/46] new phylogenetic trees file --- src/Combinatorics/PhylogeneticTrees.jl | 289 +++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 src/Combinatorics/PhylogeneticTrees.jl diff --git a/src/Combinatorics/PhylogeneticTrees.jl b/src/Combinatorics/PhylogeneticTrees.jl new file mode 100644 index 000000000000..d3702b28cd74 --- /dev/null +++ b/src/Combinatorics/PhylogeneticTrees.jl @@ -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)) + + pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( + 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) +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 +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) +end + +function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) + return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) +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) +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) +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) + pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) + + for i in 1:n + pm_arr[i] = arr[i].pm_ptree + end + + 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 From 334b61baf2cab0a8321e6175fc426969dc0cbec3 Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Wed, 7 Feb 2024 10:37:54 +0100 Subject: [PATCH 40/46] returning graph from edges to the bottom of file + add include --- src/Combinatorics/Graphs/functions.jl | 347 +++----------------------- src/Combinatorics/Graphs/structs.jl | 4 - src/Oscar.jl | 1 + 3 files changed, 30 insertions(+), 322 deletions(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 35a598ab94cd..5dc45d623110 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -5,9 +5,6 @@ function pm_object(G::Graph{T}) where {T <: Union{Directed, Undirected}} return G.pm_graph end -function pm_object(PT::PhylogeneticTree) - return PT.pm_ptree -end ################################################################################ ################################################################################ @@ -83,54 +80,6 @@ function graph_from_adjacency_matrix(::Type{T}, G::Union{MatElem, Matrix}) where end -function graph_from_edges(::Type{T}, - edges::Vector{Edge}, - n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} - - 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)) - end - - return g -end - -graph_from_edges(::Type{T}, -edges::EdgeIterator, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) - -@doc raw""" - graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} - -Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. - -# Examples 1 -```jldoctest -julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) -Undirected graph with 5 nodes and the following edges: -(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) - -``` - -``` -# Examples 2 -```jldoctest -julia> G = graph_from_edges(Undirected,[[1,3]]) -Undirected graph with 3 nodes and the following edges: -(3, 1)) - -``` -""" -graph_from_edges(::Type{T}, -edges::Vector{Vector{Int}}, -n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) - -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) _has_node(G::Graph, node::Int64) = 0 < node <= nvertices(G) @@ -1134,289 +1083,51 @@ function Base.show(io::IO, G::Graph{T}) where {T <: Union{Polymake.Directed, Po end end -################################################################################ -################################################################################ -## Phylogenetic Trees -################################################################################ -################################################################################ -@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)) - - pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( - 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) -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. +function graph_from_edges(::Type{T}, + edges::Vector{Edge}, + n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} -# Examples -Make a phylogenetic tree with given Newick format and check if it is equidistant. + 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" -```jldoctest -julia> ptree = phylogenetic_tree(Float64, "((H:3,(C:1,B:1):2):1,G:4);"); + g = Graph{T}(max(n_needed, n_vertices)) + for e in edges + add_edge!(g, src(e), dst(e)) + end -julia> equidistant(ptree) -true -``` -""" -function equidistant(ptree::PhylogeneticTree) - return ptree.pm_ptree.EQUIDISTANT + return g end +graph_from_edges(::Type{T}, +edges::EdgeIterator, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, collect(edges), n_vertices) @doc raw""" - cophenetic_matrix(ptree::PhylogeneticTree) - -Returns the cophenetic matrix of the phylogenetic tree `ptree`. + graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}) where {T <:Union{Directed, Undirected}} -# Examples -Make a phylogenetic tree with given Newick format and print its cophenetic matrix. +Creates a graph from a vector of edges. Optionally, you could input the number of vertices, but if this number is lower than the maximum vertex in the edges, this argument will be ignored. +# Examples 1 ```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) -end - -function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) - return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) -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. +julia> G = graph_from_edges(Undirected, [[1,3],[3,5],[4,5],[2,4],[2,3]]) +Undirected graph with 5 nodes and the following edges: +(3, 1)(3, 2)(4, 2)(5, 3)(5, 4) -```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) -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) -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. - +# Examples 2 ```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> G = graph_from_edges(Undirected,[[1,3]]) +Undirected graph with 3 nodes and the following edges: +(3, 1)) -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) - pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) - - for i in 1:n - pm_arr[i] = arr[i].pm_ptree - end - - 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); +graph_from_edges(::Type{T}, +edges::Vector{Vector{Int}}, +n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} = graph_from_edges(T, [Edge(e[1], e[2]) for e in edges], n_vertices) -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 +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) diff --git a/src/Combinatorics/Graphs/structs.jl b/src/Combinatorics/Graphs/structs.jl index a0aef202796f..e5b44e77610b 100644 --- a/src/Combinatorics/Graphs/structs.jl +++ b/src/Combinatorics/Graphs/structs.jl @@ -5,7 +5,3 @@ struct Graph{T <: Union{Directed, Undirected}} pm_graph::Polymake.Graph{T} end -mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} - pm_ptree::Polymake.LibPolymake.BigObjectAllocated -end - diff --git a/src/Oscar.jl b/src/Oscar.jl index 2c02dfa3a82d..f91d5e4deded 100644 --- a/src/Oscar.jl +++ b/src/Oscar.jl @@ -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 From f07e5ca74ea73526b2c1482804c982cf22336f77 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Wed, 7 Feb 2024 10:43:50 +0100 Subject: [PATCH 41/46] Update src/Combinatorics/Graphs/functions.jl --- src/Combinatorics/Graphs/functions.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 5dc45d623110..a137060c8d70 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -80,7 +80,6 @@ function graph_from_adjacency_matrix(::Type{T}, G::Union{MatElem, Matrix}) where end - _has_node(G::Graph, node::Int64) = 0 < node <= nvertices(G) @doc raw""" From 367d1024e80d9c25168cc354364a248ab344f066 Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Wed, 7 Feb 2024 10:47:41 +0100 Subject: [PATCH 42/46] removed swp file --- src/Combinatorics/Graphs/.functions.jl.swp | Bin 1024 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/Combinatorics/Graphs/.functions.jl.swp diff --git a/src/Combinatorics/Graphs/.functions.jl.swp b/src/Combinatorics/Graphs/.functions.jl.swp deleted file mode 100644 index fec793c42bc4b09dbd3a7e6de5ee7e2f4351c309..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1024 zcmYc?$V<%2S1{8vVn6|#q!}0zlk;;?1aWX2^HPdZGjT{F38$6jC6{F8=N0Q^ Date: Fri, 9 Feb 2024 15:45:36 +0100 Subject: [PATCH 43/46] Update src/Combinatorics/Graphs/functions.jl --- src/Combinatorics/Graphs/functions.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Combinatorics/Graphs/functions.jl b/src/Combinatorics/Graphs/functions.jl index 1fcb75bcbfaa..ce95638fb2f3 100644 --- a/src/Combinatorics/Graphs/functions.jl +++ b/src/Combinatorics/Graphs/functions.jl @@ -1121,7 +1121,6 @@ Directed graph with 4 nodes and the following edges: (1, 3) ``` """ - function graph_from_edges(::Type{T}, edges::Vector{Vector{Int}}, n_vertices::Int=-1) where {T <: Union{Directed, Undirected}} From 35bd835a982fffe0eb47e23d53915531cdaec075 Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Fri, 9 Feb 2024 16:41:32 +0100 Subject: [PATCH 44/46] updates from review comments --- docs/oscar_references.bib | 10 +++++++ docs/src/Combinatorics/phylogenetic_trees.md | 2 +- src/Combinatorics/PhylogeneticTrees.jl | 28 +++++++++----------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/docs/oscar_references.bib b/docs/oscar_references.bib index 29e7251a13fb..f14b6e563dd0 100644 --- a/docs/oscar_references.bib +++ b/docs/oscar_references.bib @@ -1721,6 +1721,16 @@ @Article{RSS03 year = {2003} } +@Book{SS03, + author = {Semple, Charles and Steel, Mike}, + title = {Phylogenetics}, + series = {Oxf. Lect. Ser. Math. Appl.}, + volume = {24}, + publisher = {Oxford University Press}, + year = {2003}, + fseries = {Oxford Lecture Series in Mathematics and its Applications} +} + @Article{SS12, author = {Savage, Carla D. and Schuster, Michael J.}, title = {Ehrhart series of lecture hall polytopes and Eulerian polynomials for inversion sequences}, diff --git a/docs/src/Combinatorics/phylogenetic_trees.md b/docs/src/Combinatorics/phylogenetic_trees.md index 457e5b64b141..8058ddca29cd 100644 --- a/docs/src/Combinatorics/phylogenetic_trees.md +++ b/docs/src/Combinatorics/phylogenetic_trees.md @@ -7,7 +7,7 @@ CurrentModule = Oscar ## 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. +Here we consider phylogenetic trees with branch lengths as defined in [SS03](@cite). ## Construction diff --git a/src/Combinatorics/PhylogeneticTrees.jl b/src/Combinatorics/PhylogeneticTrees.jl index d3702b28cd74..efe32eb9c7d0 100644 --- a/src/Combinatorics/PhylogeneticTrees.jl +++ b/src/Combinatorics/PhylogeneticTrees.jl @@ -82,10 +82,7 @@ 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)) - - pm_ptree = Polymake.graph.PhylogeneticTree{pm_T}( + pm_ptree = Polymake.graph.PhylogeneticTree{Rational}( COPHENETIC_MATRIX = M, TAXA = taxa ) return PhylogeneticTree{QQFieldElem}(pm_ptree) @@ -108,7 +105,7 @@ Undirected graph with 7 nodes and the following edges: ``` """ function adjacency_tree(ptree::PhylogeneticTree) - return Graph{Undirected}(ptree.pm_ptree.ADJACENCY) + return Graph{Undirected}(pm_object(ptree).ADJACENCY) end function Base.show(io::IO, ptree::PhylogeneticTree{T}) where T @@ -131,7 +128,7 @@ true ``` """ function equidistant(ptree::PhylogeneticTree) - return ptree.pm_ptree.EQUIDISTANT + return pm_object(ptree).EQUIDISTANT::Bool end @@ -155,11 +152,14 @@ julia> cophenetic_matrix(ptree) ``` """ function cophenetic_matrix(ptree::PhylogeneticTree{Float64}) - return convert(Matrix, ptree.pm_ptree.COPHENETIC_MATRIX) + return convert(Matrix, pm_object(ptree).COPHENETIC_MATRIX)::Matrix{Float64} end function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) - return matrix(QQ, convert(Matrix{QQFieldElem}, ptree.pm_ptree.COPHENETIC_MATRIX)) + return matrix( + QQ, + convert(Matrix{QQFieldElem}, pm_object(ptree).COPHENETIC_MATRIX) + )::QQMatrix end @doc raw""" @@ -182,7 +182,7 @@ julia> taxa(ptree) ``` """ function taxa(ptree::PhylogeneticTree) - return convert(Array{String}, ptree.pm_ptree.TAXA) + return convert(Array{String}, pm_object(ptree).TAXA)::Array{String} end @doc raw""" @@ -215,7 +215,7 @@ julia> newick(tree_mat) ``` """ function newick(ptree::PhylogeneticTree) - return convert(String, ptree.pm_ptree.NEWICK) + return convert(String, pm_object(ptree).NEWICK)::String end @@ -249,13 +249,11 @@ function tropical_median_consensus(arr::Vector{PhylogeneticTree{T}}) where {T <: n = length(arr) @req n > 0 "The vector must not be empty" - phylo_type = Polymake.bigobject_type(arr[1].pm_ptree) + phylo_type = Polymake.bigobject_type(pm_object(first(arr))) pm_arr = Polymake.Array{Polymake.BigObject}(phylo_type, n) - for i in 1:n - pm_arr[i] = arr[i].pm_ptree - end - + pm_arr .= pm_object.(arr) + pm_cons_tree = Polymake.tropical.tropical_median_consensus(pm_arr) return PhylogeneticTree{T}(pm_cons_tree) end From 3089c3917cfa9fc2a2e31fdf3fa4a724a159bfea Mon Sep 17 00:00:00 2001 From: Antony Della Vecchia Date: Fri, 9 Feb 2024 17:26:23 +0100 Subject: [PATCH 45/46] make Phylogenetic tree immutable --- src/Combinatorics/PhylogeneticTrees.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Combinatorics/PhylogeneticTrees.jl b/src/Combinatorics/PhylogeneticTrees.jl index efe32eb9c7d0..190e4a66bbd8 100644 --- a/src/Combinatorics/PhylogeneticTrees.jl +++ b/src/Combinatorics/PhylogeneticTrees.jl @@ -1,4 +1,4 @@ -mutable struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} +struct PhylogeneticTree{T <: Union{Float64, QQFieldElem}} pm_ptree::Polymake.LibPolymake.BigObjectAllocated end From 52f14eeb2156885704f49f58b5e073fd2d440140 Mon Sep 17 00:00:00 2001 From: antonydellavecchia Date: Fri, 9 Feb 2024 18:06:36 +0100 Subject: [PATCH 46/46] Apply suggestions from code review Co-authored-by: Benjamin Lorenz --- src/Combinatorics/PhylogeneticTrees.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Combinatorics/PhylogeneticTrees.jl b/src/Combinatorics/PhylogeneticTrees.jl index 190e4a66bbd8..5a5a17a9e08a 100644 --- a/src/Combinatorics/PhylogeneticTrees.jl +++ b/src/Combinatorics/PhylogeneticTrees.jl @@ -156,10 +156,7 @@ function cophenetic_matrix(ptree::PhylogeneticTree{Float64}) end function cophenetic_matrix(ptree::PhylogeneticTree{QQFieldElem}) - return matrix( - QQ, - convert(Matrix{QQFieldElem}, pm_object(ptree).COPHENETIC_MATRIX) - )::QQMatrix + return matrix(QQ, pm_object(ptree).COPHENETIC_MATRIX)::QQMatrix end @doc raw"""