From 268271fc8136196b64acf34ad13717aeee59e144 Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Fri, 9 Dec 2022 18:08:48 -0600 Subject: [PATCH 1/9] add utilities; standardize getter names: start --- docs/src/lib/public.md | 24 +++++++++++++++--------- src/PhyloNetworks.jl | 6 ++++-- src/auxiliary.jl | 19 +++++++++++++++++++ src/deprecated.jl | 1 - test/test_moves_semidirected.jl | 2 +- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/docs/src/lib/public.md b/docs/src/lib/public.md index 4ba41508..ae437437 100644 --- a/docs/src/lib/public.md +++ b/docs/src/lib/public.md @@ -22,14 +22,22 @@ Private = false Order = [:type] ``` -## utilities +## basic utilities ```@docs tipLabels -sorttaxa! printEdges printNodes -summarizeDataCF +hassinglechild +singlechildedge +getNodeAges +pairwiseTaxonDistanceMatrix +``` + +## utilities to manipulate networks + +```@docs +sorttaxa! directEdges! checkroot! preorder! @@ -46,15 +54,9 @@ shrink2cycles! shrink3cycles! deleteHybridThreshold! rotate! -getindex(::TraitSimulation, ::Symbol) -getNodeAges -pairwiseTaxonDistanceMatrix biconnectedComponents blobDecomposition treeedgecomponents -getlabels -nparams -mapindividuals nni! ``` @@ -87,6 +89,7 @@ mapAllelesCFtable snaq! topologyMaxQPseudolik! topologyQPseudolik! +summarizeDataCF fittedQuartetCF bootsnaq calibrateFromPairwiseDistances! @@ -131,6 +134,7 @@ regressorShift regressorHybrid sharedPathMatrix vcv +getindex(::TraitSimulation, ::Symbol) ``` ## discrete trait evolution @@ -143,7 +147,9 @@ randomTrait randomTrait! fitdiscrete maxParsimonyNet +getlabels nstates +nparams stationary empiricalDNAfrequencies ``` diff --git a/src/PhyloNetworks.jl b/src/PhyloNetworks.jl index e51b84cd..0e759015 100644 --- a/src/PhyloNetworks.jl +++ b/src/PhyloNetworks.jl @@ -71,10 +71,13 @@ module PhyloNetworks readSnaqNetwork, topologyMaxQPseudolik!, topologyQPseudolik!, - ## Network Manipulation + ## getters # getParent, getParents, getMajorParentEdge, getMinorParentEdge, getChildren, # functions above: first rename them throughout to be consistent with other packages, like: # parent child parents children parentmajor parentminor ancestor sibling offspring + hassinglechild, + singlechildedge, + ## Network Manipulation rootatnode!, rootonedge!, directEdges!, @@ -96,7 +99,6 @@ module PhyloNetworks biconnectedComponents, blobDecomposition!, blobDecomposition, - mapindividuals, nni!, checkroot!, treeedgecomponents, diff --git a/src/auxiliary.jl b/src/auxiliary.jl index 70b5e37f..fa796475 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -273,6 +273,25 @@ returns the first child edge. error("could not find child edge of node $(node.number)") end +""" + hassinglechild(node) + +Boolean: `true` if `node` has a single child edge, +based on the edge's `isChild1` attribute. +""" +hassinglechild(node::PN.Node) = sum(e -> PN.getParent(e) === node, node.edge) == 1 + +""" + singlechildedge(node) + +Child edge of `node`. Checks that it's a single child. +""" +function singlechildedge(node::PN.Node) + ce_ind = findall(e -> PN.getParent(e) === node, node.edge) + length(ce_ind) == 1 || error("node number $(node.number) has $(length(ce_ind)) children instead of 1 child") + return node.edge[ce_ind[1]] +end + # -------------- NETWORK ----------------------- # function getIndex(node::Node, net::Network) diff --git a/src/deprecated.jl b/src/deprecated.jl index 80b9ab3a..9adcb38d 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -1,4 +1,3 @@ -@deprecate fitDiscrete fitdiscrete @deprecate phyloNetworklm phylolm @deprecate sigma2_estim sigma2_phylo @deprecate mu_estim mu_phylo diff --git a/test/test_moves_semidirected.jl b/test/test_moves_semidirected.jl index e04b9e63..ad652433 100644 --- a/test/test_moves_semidirected.jl +++ b/test/test_moves_semidirected.jl @@ -370,7 +370,7 @@ net_level1_s = readTopology(str_level1_s) @test writeTopology(net_level1_s) == str_level1_s # network unchanged @test_logs (:warn, r"^Spaces in \"S1 A\" may cause errors") PhyloNetworks.addindividuals!(net_level1_s, "S1", ["S1 A", "S1B", "S1C"]) @test writeTopology(net_level1_s) == "(((S8,S9),(((((S1_A,S1B,S1C)S1,S4),(S5)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" -# # test mapindividuals! function +# test mapindividuals function net_level1_s = readTopology(str_level1_s) # in net env filename = joinpath(@__DIR__, "..","examples","mappingIndividuals.csv") From f80c60c552b5561d47759f2d1fa4c00812ee931b Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Sun, 11 Dec 2022 22:34:45 -0600 Subject: [PATCH 2/9] parent / child accessors: lower-case names --- docs/src/lib/public.md | 11 +- docs/src/man/netmanipulation.md | 9 +- src/PhyloNetworks.jl | 15 +- src/addHybrid.jl | 12 +- src/addHybrid_snaq.jl | 6 +- src/auxiliary.jl | 246 +++++++++++++++++++------------ src/bootstrap.jl | 14 +- src/compareNetworks.jl | 24 +-- src/deleteHybrid.jl | 12 +- src/graph_components.jl | 10 +- src/interop.jl | 4 +- src/manipulateNet.jl | 123 ++++------------ src/moves_semidirected.jl | 64 ++++---- src/pairwiseDistanceLS.jl | 12 +- src/parsimony.jl | 30 ++-- src/phyLiNCoptimization.jl | 32 ++-- src/readwrite.jl | 10 +- src/traits.jl | 21 ++- src/traitsLikDiscrete.jl | 10 +- test/test_addHybrid.jl | 8 +- test/test_manipulateNet.jl | 28 ++-- test/test_moves_semidirected.jl | 38 ++--- test/test_phyLiNCoptimization.jl | 12 +- 23 files changed, 385 insertions(+), 366 deletions(-) diff --git a/docs/src/lib/public.md b/docs/src/lib/public.md index ae437437..d8a18f7d 100644 --- a/docs/src/lib/public.md +++ b/docs/src/lib/public.md @@ -28,8 +28,17 @@ Order = [:type] tipLabels printEdges printNodes +isparent +ischild hassinglechild -singlechildedge +getchild +getchildren +getchildedge +getparent +getparents +getparentminor +getparentedge +getpartner getNodeAges pairwiseTaxonDistanceMatrix ``` diff --git a/docs/src/man/netmanipulation.md b/docs/src/man/netmanipulation.md index accedd11..8850d4ad 100644 --- a/docs/src/man/netmanipulation.md +++ b/docs/src/man/netmanipulation.md @@ -17,10 +17,11 @@ To traverse or learn something about a network, node or edge, see for example: - [`displayedTrees`](@ref), [`majorTree`](@ref), [`biconnectedComponents`](@ref), [`PhyloNetworks.blobInfo`](@ref) - [`hardwiredCluster`](@ref), [`hardwiredClusters`](@ref) -- [`PhyloNetworks.getPartner`](@ref), - [`PhyloNetworks.getChild`](@ref), [`PhyloNetworks.getChildren`](@ref), [`PhyloNetworks.getChildEdge`](@ref) - [`PhyloNetworks.getParent`](@ref), [`PhyloNetworks.getParents`](@ref), - [`PhyloNetworks.getMajorParent`](@ref), [`PhyloNetworks.getMajorParentEdge`](@ref), +- [`isparent`](@ref), [`ischild`](@ref), [`hassinglechild`](@ref), + [`getpartner`](@ref), + [`getchild`](@ref), [`getchildren`](@ref), [`getchildedge`](@ref) + [`getparent`](@ref), [`getparents`](@ref), + [`getparentminor`](@ref), [`getparentedge`](@ref) To modify a network, for example: - [`rootonedge!`](@ref), [`rootatnode!`](@ref): diff --git a/src/PhyloNetworks.jl b/src/PhyloNetworks.jl index 0e759015..70c366dd 100644 --- a/src/PhyloNetworks.jl +++ b/src/PhyloNetworks.jl @@ -72,11 +72,20 @@ module PhyloNetworks topologyMaxQPseudolik!, topologyQPseudolik!, ## getters - # getParent, getParents, getMajorParentEdge, getMinorParentEdge, getChildren, - # functions above: first rename them throughout to be consistent with other packages, like: + # getMinorParentEdge. fixit: add isleaf, isroot + # functions above: rename them before exporting, like: # parent child parents children parentmajor parentminor ancestor sibling offspring + isparent, + ischild, hassinglechild, - singlechildedge, + getchild, + getchildren, + getchildedge, + getparent, + getparents, + getparentminor, + getparentedge, + getpartner, ## Network Manipulation rootatnode!, rootonedge!, diff --git a/src/addHybrid.jl b/src/addHybrid.jl index 494750a6..9b0899b8 100644 --- a/src/addHybrid.jl +++ b/src/addHybrid.jl @@ -77,8 +77,8 @@ function addhybridedge!(net::HybridNetwork, nohybridladder::Bool, no3cycle::Bool continue # if (e1,e2) was already attempted nattempts += 1 ## check that constraints are met - p1 = getParent(edge1) - p2 = getParent(edge2) + p1 = getparent(edge1) + p2 = getparent(edge2) constraintsmet = true for con in constraints if con.type == 1 # forbid going out of (edge1) or into (edge2) the species group @@ -97,7 +97,7 @@ function addhybridedge!(net::HybridNetwork, nohybridladder::Bool, no3cycle::Bool end ## check for no hybrid ladder, if requested: # edge2 cannot be a hybrid edge or the child of a hybrid node - if nohybridladder && (edge2.hybrid || getParent(edge2).hybrid) + if nohybridladder && (edge2.hybrid || getparent(edge2).hybrid) push!(blacklist, (e1,e2)) continue end @@ -182,7 +182,7 @@ function addhybridedge!(net::HybridNetwork, edge1::Edge, edge2::Edge, hybridpart edgeabovee2.isMajor = false end else - c2 = getChild(edge2) # child of edge2 before we switch its direction + c2 = getchild(edge2) # child of edge2 before we switch its direction i2 = findfirst(isequal(c2), net.node) net.root = i2 # makes c2 the new root node edge2.hybrid = true @@ -245,13 +245,13 @@ Output: `true` if a conflict would arise (non-DAG), `false` if no conflict. """ function directionalconflict(net::HybridNetwork, parent::Node, edge2::Edge, hybridpartnernew::Bool) if hybridpartnernew # all edges would retain their directions: use isChild1 fields - c2 = getChild(edge2) + c2 = getchild(edge2) return parent === c2 || isdescendant(parent, c2) else # after hybrid addition, edge 2 would be reversed: "up" toward its own parent if !edge2.containRoot || edge2.hybrid return true # direction of edge2 cannot be reversed else # net would be a DAG with reversed directions, could even be rooted on edge2 - p2 = getParent(edge2) + p2 = getparent(edge2) return parent === p2 || isdescendant_undirected(parent, p2, edge2) end end diff --git a/src/addHybrid_snaq.jl b/src/addHybrid_snaq.jl index 52d24b55..9ac50593 100644 --- a/src/addHybrid_snaq.jl +++ b/src/addHybrid_snaq.jl @@ -410,8 +410,8 @@ function addHybridBetweenClades!(hybnum::Number,sisnum::Number,net::HybridNetwor sisind = getIndexNode(sisnum,net) ## hybridization ed1->ed2 - edge1 = getMajorParentEdge(net.node[sisind]) - edge2 = getMajorParentEdge(net.node[hybind]) + edge1 = getparentedge(net.node[sisind]) # major parent edges + edge2 = getparentedge(net.node[hybind]) edge3,edge4 = parameters4createHybrid!(edge1, edge2,net) hybridnode = createHybrid!(edge1, edge2, edge3, edge4, net, 0.1) ## gamma=0.1, fixed later @@ -434,7 +434,7 @@ function addHybridBetweenClades!(hybnum::Number,sisnum::Number,net::HybridNetwor edge2.isChild1 = false end ## used gamma=0.1 to make the new edge a minor edge, but we really do not have gamma value: - emaj = getMajorParentEdge(hybridnode) + emaj = getparentedge(hybridnode) emaj.gamma = -1 e = getMinorParentEdge(hybridnode) e.gamma = -1 diff --git a/src/auxiliary.jl b/src/auxiliary.jl index fa796475..24e5fd3a 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -148,28 +148,149 @@ function setNode!(edge::Edge,node::Array{Node,1}) end """ - getChild(edge::Edge) + isparent(node, edge) + ischild(node, edge) -Return child node using the `isChild1` attribute of the edge. +True if `node` is the tail / head, or parent / child, of `edge`; false otherwise. +Assumes that the edge's direction is correct, meaning it's field `isChild1` is +reliable (in sync with the rooting). """ -@inline function getChild(edge::Edge) - edge.node[edge.isChild1 ? 1 : 2] +isparent(node::Node, edge::Edge) = node === getparent(edge) +@doc (@doc isparent) ischild +ischild( node::Node, edge::Edge) = node === getchild(edge) + +""" + hassinglechild(node) + +Boolean: `true` if `node` has a single child (child edge or child node, +which are equivalent), based on the edges `isChild1` field. +""" +hassinglechild(node::Node) = sum(e -> getparent(e) === node, node.edge) == 1 + +""" + getchild(edge) + getchild(node) + +Child node of `edge`; or +single child node of `node` after checking that `node` has a single child. +Relies on the edges direction (from their `isChild1` field). +""" +getchild(edge::Edge) = edge.node[edge.isChild1 ? 1 : 2] +getchild(node::Node) = getchild(getchildedge(node)) + +""" + getchildren(node) + +Vector of all children *nodes* of `node`. +**warning**: assume `isChild1` field (for edges) are correct + +To get all parent *nodes*: see [`getparents`](@ref PhyloNetworks.getparents). +""" +function getchildren(node::Node) + children = Node[] + for e in node.edge + if isparent(node, e) + push!(children, getchild(e)) + end + end + return children end -# getParents defined in manipulateNet.jl """ - getParent(e::Edge) + getchildedge(node) -Return parent node of edge `e` using the `isChild1` attribute of the edge. -To get parents of nodes: see [`getParents`](@ref). +Single child edge of `node`. Checks that it's a single child. """ -@inline function getParent(edge::Edge) - edge.node[edge.isChild1 ? 2 : 1] +function getchildedge(node::Node) + ce_ind = findall(e -> isparent(node, e), node.edge) + length(ce_ind) == 1 || error("node number $(node.number) has $(length(ce_ind)) children instead of 1 child") + return node.edge[ce_ind[1]] end """ - getPartner(edge::Edge) - getPartner(edge::Edge, node::Node) + getparent(edge) + getparent(node) + +Parent node of `edge`, or **major** parent node of `node`. +Warning: usies the `isChild1` attribute of edges. + +See also: [`getparents`](@ref) [`getparentminor`](@ref). +""" +getparent(edge::Edge) = edge.node[edge.isChild1 ? 2 : 1] +@inline function getparent(node::Node) + for e in node.edge + if e.isMajor && ischild(node, e) + return getparent(e) + end + end + error("could not find major parent of node $(node.number)") +end + +""" + getparentminor(node) + +Minor parent node of `node` using the `isChild1` field of edges +(and assuming correct `isMajor` field). +See also [`getparentedge`](@ref) and [`getMinorParentEdge`](@ref). +""" +@inline function getparentminor(node::Node) + for e in node.edge + if !e.isMajor && node == getchild(e) + return getparent(e) + end + end + error("could not find minor parent of node $(node.number)") +end + +""" + getparents(node) + +Vector of all parent nodes of `node`, based on `isChild1` field (for edges). + +See also: [`getparent`](@ref) to get the (major) parent node, +[`getparentedge`](@ref) for the (major) parent edge and +[`getMinorParentEdge`](@ref). +""" +@inline function getparents(node::Node) + parents = Node[] + for e in node.edge + if ischild(node, e) + push!(parents, getparent(e)) + end + end + return parents +end + +""" + getparentedge(node) + getMinorParentEdge(node) + +return the parent edge of `node`: the major / minor if hybrid. +**warning**: assume isChild1 and isMajor attributes are correct + +To get all parent *nodes*: see [`getparents`](@ref). +""" +@inline function getparentedge(n::Node) + for ee in n.edge + if ee.isMajor && ischild(n,ee) + return ee + end + end + error("node $(n.number) has no major parent") +end +@doc (@doc getparentedge) getMinorParentEdge +@inline function getMinorParentEdge(n::Node) + for ee in n.edge + if !ee.isMajor && n == ee.node[(ee.isChild1 ? 1 : 2)] + return ee + end + end + error("node $(n.number) has no minor parent") +end + +""" + getpartner(edge::Edge) + getpartner(edge::Edge, node::Node) Return hybrid partner of edge, that is, hybrid edge pointing to the same child as `edge`. Assumptions (not checked): @@ -180,13 +301,13 @@ child as `edge`. Assumptions (not checked): When `node` is given, it is assumed to be the child of `edge` (the first form calls the second). """ -@inline function getPartner(edge) - node = getChild(edge) - getPartner(edge, node) +@inline function getpartner(edge) + node = getchild(edge) + getpartner(edge, node) end -@inline function getPartner(edge::Edge, node::Node) +@inline function getpartner(edge::Edge, node::Node) for e in node.edge - if e.hybrid && e !== edge && node === getChild(e) + if e.hybrid && e !== edge && node === getchild(e) return e end end @@ -215,7 +336,7 @@ childindices = findall( isequal(:child), labs) # vector. could be empty ``` """ function edgerelation(ee::Edge, n::Node, origin::Edge) - (ee===origin ? :origin : (n===getChild(ee) ? :parent : :child)) + (ee===origin ? :origin : (n===getchild(ee) ? :parent : :child)) end # -------------- NODE -------------------------# @@ -229,68 +350,7 @@ function getOtherNode(edge::Edge, node::Node) edge.node[1] === node ? edge.node[2] : edge.node[1] end -# get[Major|Minor]ParentEdge and getChildren: defined in manipulateNet.jl -""" - getMajorParent(node) - getMinorParent(node) - -Return major or minor parent of a node using the `isChild1` field of edges -(and assuming correct `isMajor` field). -See also [`getMajorParentEdge`](@ref PhyloNetworks.getMajorParentEdge) and `getMinorParentEdge`. -""" -@inline function getMajorParent(node::Node) - for e in node.edge - if e.isMajor && node == getChild(e) - return getParent(e) - end - end - error("could not find major parent of node $(node.number)") -end -@doc (@doc getMajorParent) getMinorParent -@inline function getMinorParent(node::Node) - for e in node.edge - if !e.isMajor && node == getChild(e) - return getParent(e) - end - end - error("could not find minor parent of node $(node.number)") -end -""" - getChildEdge(node::Node) - -Return child edge below a hybrid node. - -Warning: Does not check that the node is a hybrid, or that the node has a single -child edge. If not a hybrid or if there's a polytomy (hybrid with 2 children), -returns the first child edge. -""" -@inline function getChildEdge(node::Node) - for e in node.edge - if node === getParent(e) - return e - end - end - error("could not find child edge of node $(node.number)") -end -""" - hassinglechild(node) - -Boolean: `true` if `node` has a single child edge, -based on the edge's `isChild1` attribute. -""" -hassinglechild(node::PN.Node) = sum(e -> PN.getParent(e) === node, node.edge) == 1 - -""" - singlechildedge(node) - -Child edge of `node`. Checks that it's a single child. -""" -function singlechildedge(node::PN.Node) - ce_ind = findall(e -> PN.getParent(e) === node, node.edge) - length(ce_ind) == 1 || error("node number $(node.number) has $(length(ce_ind)) children instead of 1 child") - return node.edge[ce_ind[1]] -end # -------------- NETWORK ----------------------- # @@ -663,7 +723,7 @@ function printEdges(io::IO, net::HybridNetwork) miss = "" println(io, "edge parent child length hybrid isMajor gamma containRoot inCycle istIdentitiable") for e in net.edge - @printf(io, "%-4d %-6d %-6d ", e.number, getParent(e).number, getChild(e).number) + @printf(io, "%-4d %-6d %-6d ", e.number, getparent(e).number, getchild(e).number) if e.length==-1.0 @printf(io, "%-7s ", miss); else @printf(io, "%-7.3f ", e.length); end @printf(io, "%-6s %-7s ", e.hybrid, e.isMajor) if e.gamma==-1.0 @printf(io, "%-7s ", miss); else @printf(io, "%-7.4g ", e.gamma); end @@ -674,7 +734,7 @@ end function printEdges(io::IO, net::QuartetNetwork) println(io, "edge parent child length hybrid isMajor gamma containRoot inCycle istIdentitiable") for e in net.edge - @printf(io, "%-4d %-6d %-6d ", e.number, getParent(e).number, getChild(e).number) + @printf(io, "%-4d %-6d %-6d ", e.number, getparent(e).number, getchild(e).number) @printf(io, "%-7.3f %-6s %-7s ", e.length, e.hybrid, e.isMajor) @printf(io, "%-7.4g %-11s %-7d %-5s\n", e.gamma, e.containRoot, e.inCycle, e.istIdentifiable) end @@ -909,12 +969,12 @@ function setGamma!(edge::Edge, new_gamma::Float64, changeOther::Bool) new_gamma >= 0.0 || error("gamma has to be positive: $(new_gamma)") new_gamma <= 1.0 || error("gamma has to be less than 1: $(new_gamma)") edge.hybrid || error("cannot change gamma in a tree edge"); - node = getChild(edge) # child of hybrid edge + node = getchild(edge) # child of hybrid edge node.hybrid || @warn "hybrid edge $(edge.number) not pointing at hybrid node" # @debug (node.isBadDiamondI ? "bad diamond situation: gamma not identifiable" : "") partner = Edge[] # list of other hybrid parents of node, other than edge for e in node.edge - if e.hybrid && e != edge && node == getChild(e) + if e.hybrid && e != edge && node == getchild(e) push!(partner, e) end end @@ -1497,9 +1557,9 @@ created, or the new polytomy is below a tree node) """ function shrinkedge!(net::HybridNetwork, edge2shrink::Edge) edge2shrink.hybrid && error("cannot shrink hybrid edge number $(edge2shrink.number)") - cn = getChild(edge2shrink) + cn = getchild(edge2shrink) cn.hybrid && error("cannot shrink tree edge number $(edge2shrink.number): its child node is a hybrid. run directEdges! ?") - pn = getParent(edge2shrink) + pn = getparent(edge2shrink) (cn.leaf || pn.leaf) && error("won't shrink edge number $(edge2shrink.number): it is incident to a leaf") removeEdge!(pn,edge2shrink) @@ -1516,7 +1576,7 @@ function shrinkedge!(net::HybridNetwork, edge2shrink::Edge) deleteNode!(net, cn) badpolytomy = false if pn.hybrid # count the number of pn's children, without relying on isChild1 of tree edges - nc = sum((!e.hybrid || getChild(e) !== pn) for e in pn.edge) + nc = sum((!e.hybrid || getchild(e) !== pn) for e in pn.edge) badpolytomy = (nc > 1) end return badpolytomy @@ -1557,9 +1617,9 @@ function shrink2cycles!(net::HybridNetwork, unroot=false::Bool) while ih > 0 h = net.hybrid[ih] minor = getMinorParentEdge(h) - major = getMajorParentEdge(h) - pmin = getParent(minor) # minor parent node - pmaj = getMajorParent(h) # major parent node + major = getparentedge(h) + pmin = getparent(minor) # minor parent node + pmaj = getparent(major) # major parent node if pmin !== pmaj # no 2-cycle ih -= 1 continue @@ -1617,9 +1677,9 @@ function shrink3cycles!(net::HybridNetwork, unroot=false::Bool) while ih > 0 h = net.hybrid[ih] minor = getMinorParentEdge(h) - major = getMajorParentEdge(h) - pmin = getParent(minor) # minor parent node - pmaj = getMajorParent(h) # major parent node + major = getparentedge(h) + pmin = getparent(minor) # minor parent node + pmaj = getparent(major) # major parent node if pmin === pmaj # 2-cycle foundcycle = true shrink2cycleat!(net, minor, major, unroot) @@ -1706,7 +1766,7 @@ function shrink3cycleat!(net::HybridNetwork, hybrid::Node, edge1::Edge, # identify case type if edge3.hybrid # one of the parent nodes is a hybrid # to shrink this, delete edge connecting these two nodes (edge3 here) - if getChild(edge3) === node1 + if getchild(edge3) === node1 node1, node2 = node2, node1 edge1, edge2 = edge2, edge1 end # now: node1 --edge3--> node2 diff --git a/src/bootstrap.jl b/src/bootstrap.jl index 468bb896..f330ecf2 100644 --- a/src/bootstrap.jl +++ b/src/bootstrap.jl @@ -663,13 +663,13 @@ function hybridBootstrapSupport(nets::Vector{HybridNetwork}, refnet::HybridNetwo skipone = (!rooted && length(reftre.node[reftre.root].edge)<3) # not count same bipartition twice for pe in reftre.edge hwc = hardwiredCluster(pe,taxa) # not very efficient, but human readable - if skipone && refnet.node[refnet.root] ≡ getParent(pe) && sum(hwc)>1 + if skipone && refnet.node[refnet.root] ≡ getparent(pe) && sum(hwc)>1 skipone = false # wrong algo for trivial 2-taxon rooted tree (A,B); println("skip edge $(pe.number)") else push!(clade, hwc) push!(treeedge, pe.number) - cn = getChild(pe) # child node of pe + cn = getchild(pe) # child node of pe push!(treenode, cn.number) push!(leafname, (cn.leaf ? cn.name : "")) end @@ -691,11 +691,11 @@ function hybridBootstrapSupport(nets::Vector{HybridNetwork}, refnet::HybridNetwo push!(minsisedge, hemin.number) for sis in ["min","maj"] he = (sis=="min" ? hemin : hemaj) - pn = getParent(he) # parent node of sister (origin of gene flow if minor) + pn = getparent(he) # parent node of sister (origin of gene flow if minor) atroot = (!rooted && pn ≡ net0.node[net0.root]) # polytomy at root pn of degree 3: will exclude one child edge hwc = zeros(Bool,ntax) # new binding each time. pushed to clade below. for ce in pn.edge # important if polytomy - if ce ≢ he && pn ≡ getParent(ce) + if ce ≢ he && pn ≡ getparent(ce) hw = hardwiredCluster(ce,taxa) if atroot && any(hw .& clade[ic]) # sister clade intersects child clade (hw .& clade[ic]) == clade[ic] || @@ -714,7 +714,7 @@ function hybridBootstrapSupport(nets::Vector{HybridNetwork}, refnet::HybridNetwo if sis=="min" # need to get clade not in main tree: hybrid + minor sister pe = nothing # looking for the (or one) parent edge of pn for ce in pn.edge - if pn ≡ getChild(ce) + if pn ≡ getchild(ce) pe=ce break end @@ -792,13 +792,13 @@ function hybridBootstrapSupport(nets::Vector{HybridNetwork}, refnet::HybridNetwo hardwiredCluster!(hwcChi,hemin,taxa) for sis in ["min","maj"] he = (sis=="min" ? hemin : hemaj) - pn = getParent(he) # parent of hybrid edge + pn = getparent(he) # parent of hybrid edge atroot = (!rooted && pn ≡ net1.node[net1.root]) # if at root: exclude the child edge in the same cycle as he. # its cluster includes hwcChi. all other child edges do not interest hwcChi. # if (atroot) @show i; @warn "$(sis)or edge is at the root!"; end for ce in pn.edge - if ce ≢ he && pn ≡ getParent(ce) + if ce ≢ he && pn ≡ getparent(ce) hwc = hardwiredCluster(ce,taxa) if !atroot || sum(hwc .& hwcChi) == 0 # empty intersection if (sis=="maj") hwcSib .|= hwc; diff --git a/src/compareNetworks.jl b/src/compareNetworks.jl index 7fe40d4d..b5440d62 100644 --- a/src/compareNetworks.jl +++ b/src/compareNetworks.jl @@ -180,7 +180,7 @@ hardwiredCluster!(v::Vector{Bool},edge::Edge,taxa::Union{AbstractVector{String}, function hardwiredCluster!(v::Vector{Bool},edge::Edge,taxa::Union{AbstractVector{String},AbstractVector{Int}}, visited::Vector{Int}) - n = getChild(edge) + n = getchild(edge) if n.leaf j = findall(isequal(n.name), taxa) length(j)==1 || error("taxon $(n.name) was not found in taxon list, or more than once") @@ -192,7 +192,7 @@ function hardwiredCluster!(v::Vector{Bool},edge::Edge,taxa::Union{AbstractVector end push!(visited, n.number) for ce in n.edge - if n === getParent(ce) + if n === getparent(ce) hardwiredCluster!(v,ce,taxa,visited) end end @@ -240,7 +240,7 @@ function descendants(edge::Edge, internal::Bool=false) end function descendants!(des::Vector{Int}, visited::Vector{Int}, edge::Edge, internal::Bool=false) - n = getChild(edge) + n = getchild(edge) if n.hybrid # only need to check previous visits for hybrid nodes n.number in visited && return nothing push!(visited, n.number) @@ -249,7 +249,7 @@ function descendants!(des::Vector{Int}, visited::Vector{Int}, edge::Edge, intern push!(des, n.number) end for ce in n.edge - if n == getParent(ce) + if isparent(n, ce) descendants!(des, visited, ce, internal) end end @@ -266,7 +266,7 @@ for a version that does not use `isChild1`. function isdescendant(des::Node, anc::Node) visited = Int[] for e in anc.edge - anc !== getChild(e) || continue # skip parents of anc + anc !== getchild(e) || continue # skip parents of anc if isdescendant!(visited, des, e) return true end @@ -274,7 +274,7 @@ function isdescendant(des::Node, anc::Node) return false end function isdescendant!(visited::Vector{Int}, des::Node, e::Edge) - n = getChild(e) + n = getchild(e) if n == des return true end @@ -285,7 +285,7 @@ function isdescendant!(visited::Vector{Int}, des::Node, e::Edge) push!(visited, n.number) end for ce in n.edge - if n == getParent(ce) + if isparent(n, ce) if isdescendant!(visited, des, ce) return true; end end end @@ -314,7 +314,7 @@ end function isdescendant_undirected!(visited::Vector{Int}, des::Node, anc::Node, parentedge::Edge) for e in anc.edge e !== parentedge || continue # do not go back up where we came from - !e.hybrid || getParent(e) === anc || continue # do not go back up a parent hybrid edge of anc + !e.hybrid || getparent(e) === anc || continue # do not go back up a parent hybrid edge of anc n = getOtherNode(e, anc) if n === des return true @@ -422,7 +422,7 @@ function ladderpartition(net::HybridNetwork) end below[nn.number] = Vector{Vector{Int}}(undef,0) # initialize !nn.hybrid || error("ladder partitions not implemented for non-tree networks") - children = [getChild(e) for e in nn.edge] + children = [getchild(e) for e in nn.edge] filter!(n -> n!=nn, children) for cc in children allbelowc = union(below[cc.number]...) @@ -437,7 +437,7 @@ function ladderpartition(net::HybridNetwork) # add those above = any above n's parent, using pre-order this time. for nni in 2:nnodes # avoid 1: it's the root, no parent, nothing to update nn = net.nodes_changed[nni] - pn = getMajorParent(nn).number # parent number + pn = getparent(nn).number # major parent number for clade in above[pn] push!(above[nn.number], clade); end end return below,above @@ -511,7 +511,7 @@ function displayedNetworks!(net::HybridNetwork, node::Node, netmin = deepcopy(net) emin = getMinorParentEdge(node) deletehybridedge!(net , emin, nofuse, unroot, multgammas, true, keeporiginalroot) - emaj = getMajorParentEdge(netmin.node[ind]) # hybrid node & edge in netmin + emaj = getparentedge(netmin.node[ind]) # hybrid node & edge in netmin deletehybridedge!(netmin, emaj, nofuse, unroot, multgammas, true, keeporiginalroot) return netmin end @@ -644,7 +644,7 @@ function minorTreeAt(net::HybridNetwork, hybindex::Integer, nofuse=false::Bool, unroot=false::Bool) hybindex <= length(net.hybrid) || error("network has fewer hybrid nodes than index $(hybindex).") tree = deepcopy(net) - hybedge = getMajorParentEdge(tree.hybrid[hybindex]) + hybedge = getparentedge(tree.hybrid[hybindex]) # major parent deletehybridedge!(tree, hybedge, nofuse, unroot) # delete major hybrid edge at reticulation of interest return majorTree(tree; nofuse=nofuse, unroot=unroot) # all remaining minor edges removed: now it's a tree. end diff --git a/src/deleteHybrid.jl b/src/deleteHybrid.jl index aa6eb845..6c6ce1cf 100644 --- a/src/deleteHybrid.jl +++ b/src/deleteHybrid.jl @@ -343,10 +343,10 @@ function deletehybridedge!(net::HybridNetwork, edge::Edge, multgammas=false::Bool, simplify=true::Bool, keeporiginalroot=false::Bool) edge.hybrid || error("edge $(edge.number) has to be hybrid for deletehybridedge!") - n1 = getChild(edge) # child of edge, to be deleted unless nofuse + n1 = getchild(edge) # child of edge, to be deleted unless nofuse n1.hybrid || error("child node $(n1.number) of hybrid edge $(edge.number) should be a hybrid.") n1degree = length(n1.edge) - n2 = getParent(edge) # parent of edge, to be deleted too + n2 = getparent(edge) # parent of edge, to be deleted too n2degree = length(n2.edge) # next: keep hybrid node n1 if it has 4+ edges or if keepNode. # otherwise: detach n1, then delete recursively @@ -361,10 +361,10 @@ function deletehybridedge!(net::HybridNetwork, edge::Edge, pe = nothing # will be other parent (hybrid) edge of n1 ce = nothing # will be child edge of n1, to be merged with pe for e in n1.edge - if e.hybrid && e!==edge && n1===getChild(e) pe = e; end - if !e.hybrid || n1===getParent(e) ce = e; end # does *not* assume correct isChild1 for tree edges :) + if e.hybrid && e!==edge && n1===getchild(e) pe = e; end + if !e.hybrid || n1===getparent(e) ce = e; end # does *not* assume correct isChild1 for tree edges :) end - pn = getParent(pe); # parent node of n1, other than n2 + pn = getparent(pe); # parent node of n1, other than n2 atRoot = (net.node[net.root] ≡ n1) # n1 should not be root, but if so, pn will be new root # if pe may contain the root, then allow the root on ce and below if pe.containRoot @@ -395,7 +395,7 @@ function deletehybridedge!(net::HybridNetwork, edge::Edge, # below: we will need to delete n1 recursively (hence edge) else # n1 has 4+ edges (polytomy) or 3 edges but we want to keep it anyway: # keep n1 but detach it from 'edge', set its remaining parent to major tree edge - pe = getPartner(edge, n1) # partner edge: keep it this time + pe = getpartner(edge, n1) # partner edge: keep it this time if !pe.isMajor pe.isMajor=true; end pe.hybrid = false # note: pe.gamma *not* set to 1.0 here diff --git a/src/graph_components.jl b/src/graph_components.jl index 53979145..29b77b1d 100644 --- a/src/graph_components.jl +++ b/src/graph_components.jl @@ -130,7 +130,7 @@ function biconnectedcomponent_entrynodes(net, bcc, preorder=true::Bool) for bicomp in bcc jmin = length(net.node) for edge in bicomp - n = getParent(edge) + n = getparent(edge) j = findfirst(x -> x===n, net.nodes_changed) isnothing(j) && error("node not found in net's pre-ordering 'nodes_changed'") jmin = min(j, jmin) @@ -171,7 +171,7 @@ function biconnectedcomponent_exitnodes(net, bcc, preorder=true::Bool) exitnode_blobi = Node[] for edge in bicomp edge.isMajor || continue # skip minor edges to avoid duplicating exit node - n = getChild(edge) + n = getchild(edge) for e in n.edge e !== edge || continue if e.inCycle != i # then n is a cut point, incident to another blob @@ -230,7 +230,7 @@ function blobInfo(net, ignoreTrivial=true::Bool; for edge in bicomp if edge.hybrid && edge.isMajor push!(bccMa, edge) - e = getPartner(edge) + e = getpartner(edge) !e.isMajor || @warn "major edge $(edge.number) has a major partner: edge $(e.number)" push!(bccmi, e) end @@ -404,7 +404,7 @@ function treeedgecomponents(net::HybridNetwork) end end else # for hybrid edge, check there is at most one entry node into the TEC - if curnode === getChild(e) + if curnode === getchild(e) if isnothing(entrynode) entrynode = curnode elseif entrynode !== curnode @@ -528,7 +528,7 @@ function checkroot!(net::HybridNetwork, membership::Dict{Node,Int}) if membership[curroot] == tec_root # update containRoot only: true for edges in or out of the root TEC for e in net.edge - e.containRoot = (membership[getParent(e)] == tec_root) + e.containRoot = (membership[getparent(e)] == tec_root) end else net.root = findfirst(n -> (!n.leaf && membership[n] == tec_root), nodes) diff --git a/src/interop.jl b/src/interop.jl index 5a697555..ef0800a4 100644 --- a/src/interop.jl +++ b/src/interop.jl @@ -127,8 +127,8 @@ function minorreticulationmatrix(net::HybridNetwork) j = 1 # row index, row = reticulate edge for e in net.edge if !e.isMajor # minor (hybrid) edges only - reticulation[j,1] = getParent(e).number - reticulation[j,2] = getChild(e).number + reticulation[j,1] = getparent(e).number + reticulation[j,2] = getchild(e).number j += 1 end end diff --git a/src/manipulateNet.jl b/src/manipulateNet.jl index 9d4adc52..24fb1041 100644 --- a/src/manipulateNet.jl +++ b/src/manipulateNet.jl @@ -413,7 +413,7 @@ julia> writeTopology(net) # note extra pair of parentheses around S1 ``` """ function breakedge!(edge::Edge, net::HybridNetwork) - pn = getParent(edge) # parent node + pn = getparent(edge) # parent node # new child edge = old edge, same hybrid attribute removeEdge!(pn,edge) removeNode!(pn,edge) @@ -465,7 +465,7 @@ function fuseedgesat!(i::Integer, net::HybridNetwork, multgammas=false::Bool) if pe.hybrid # unless it's a hybrid: should be --tree--> node i --hybrid--> (ce,pe) = (pe,ce) # keep the hybrid edge: keep its isMajor end - isnodeiparent = (nodei ≡ getParent(ce)) + isnodeiparent = (nodei ≡ getparent(ce)) (!ce.hybrid || isnodeiparent) || error("node $(nodei.number) has 1 tree edge ($(pe.number)) and 1 hybrid edge ($(ce.number)), but is child of the hybrid edge.") pn = getOtherNode(pe,nodei) @@ -596,7 +596,7 @@ function addleaf!(net::HybridNetwork, speciesnode::Node, leafname::String, edgel exterioredge = Edge(maximum(e.number for e in net.edge) + 1, edgelength) # isChild1 = true by default in edge creation pushEdge!(net, exterioredge) setEdge!(speciesnode, exterioredge) - if speciesnode.hybrid || (speciesnode != net.node[net.root] && !getMajorParentEdge(speciesnode).containRoot) + if speciesnode.hybrid || (speciesnode != net.node[net.root] && !getparentedge(speciesnode).containRoot) exterioredge.containRoot = false end newleaf = Node(maximum(n.number for n in net.node) + 1, true, false, [exterioredge]) # Node(number, leaf, hybrid, edge array) @@ -647,7 +647,7 @@ function directEdges!(net::HybridNetwork; checkMajor=true::Bool) nparents = 0 # 0 or 2 normally, but could be >2 if polytomy. nmajor = 0 # there should be exactly 1 major parent if nparents>0 for e in n.edge - if e.hybrid && n == getChild(e) + if e.hybrid && n == getchild(e) nparents += 1 if (e.isMajor) nmajor +=1; end end @@ -673,7 +673,7 @@ end # containroot = true until the path goes through a hybrid node, below which # containroot is turned to false. function traverseDirectEdges!(node::Node, edge::Edge, containroot::Bool) - if edge.hybrid && node==getChild(edge) + if edge.hybrid && node==getchild(edge) throw(RootMismatch( "direction (isChild1) of hybrid edge $(edge.number) conflicts with the root. isChild1 and containRoot were updated for a subset of edges in the network only.")) @@ -691,7 +691,7 @@ isChild1 and containRoot were updated for a subset of edges in the network only. nchildren=0 for e in cn.edge if e==edge continue; end - if (e.hybrid && cn == getChild(e)) continue; end + if (e.hybrid && cn == getchild(e)) continue; end traverseDirectEdges!(cn,e,containroot) nchildren += 1 end @@ -708,71 +708,6 @@ end ## Topological sorting ################################################# -""" - getParents(node) - -Get vector of all parent nodes of `n`, based on `isChild1` field (for edges). -To get the parent node of an edge: see [`getParent`](@ref). -To get individual parent edges (rather than all parent *nodes*): -see [`getMajorParentEdge`](@ref PhyloNetworks.getMajorParentEdge) and `getMinorParentEdge`. -""" -@inline function getParents(node::Node) - parents = Node[] - for e in node.edge - if node == getChild(e) - push!(parents, getParent(e)) - end - end - return parents -end - -# getParent, getMajorParent, getMinorParent: defined in auxiliary.jl - -""" - getMajorParentEdge(node) - getMinorParentEdge(node) - -return the parent edge of a given node: the major / minor if hybrid. -**warning**: assume isChild1 and isMajor attributes are correct - -To get all parent *nodes*: see [`getParents`](@ref). -""" -@inline function getMajorParentEdge(n::Node) - for ee in n.edge - if n == ee.node[(ee.isChild1 ? 1 : 2)] && ee.isMajor - return ee - end - end - error("node $(n.number) has no major parent") -end -@doc (@doc getMajorParentEdge) getMinorParentEdge -@inline function getMinorParentEdge(n::Node) - for ee in n.edge - if !ee.isMajor && n == ee.node[(ee.isChild1 ? 1 : 2)] - return ee - end - end - error("node $(n.number) has no minor parent") -end - -""" - getChildren(node) - -return a vector with all children *nodes* of `node`. -**warning**: assume `isChild1` field (for edges) are correct - -To get all parent *nodes*: see [`PhyloNetworks.getParents`](@ref). -""" -function getChildren(node::Node) - children = Node[] - for e in node.edge - if node === getParent(e) - push!(children, getChild(e)) - end - end - return children -end - """ preorder!(net::HybridNetwork) @@ -796,14 +731,14 @@ function preorder!(net::HybridNetwork) net.visited[currind] = true # visit curr node push!(net.nodes_changed,curr) #push curr into path for e in curr.edge - if curr == getParent(e) - other = getChild(e) + if curr == getparent(e) + other = getchild(e) if !e.hybrid push!(queue,other) # print("queuing: "); @show other.number else - e2 = getPartner(e, other) - parent = getParent(e2) + e2 = getpartner(e, other) + parent = getparent(e2) if net.visited[findfirst(x -> x===parent, net.node)] push!(queue,other) # warning: if simple loop, the same node will be pushed twice: child of "curr" via 2 edges @@ -835,9 +770,9 @@ function cladewiseorder!(net::HybridNetwork) # @show net.node[ni].number push!(net.cladewiseorder_nodeIndex, ni) for e in net.node[ni].edge - if net.node[ni] ≡ getParent(e) # net.node[ni] is parent node of e + if net.node[ni] ≡ getparent(e) # net.node[ni] is parent node of e if e.isMajor - push!(queue, findfirst(isequal(getChild(e)), net.node)) + push!(queue, findfirst(isequal(getchild(e)), net.node)) # print("queuing: "); @show other.number end end @@ -887,7 +822,7 @@ function rotate!(net::HybridNetwork, nnum::Integer; orderedEdgeNum=Int[]::Array{ n = net.node[nind] ci = Int[] # children edge indices for i = 1:length(n.edge) - if n == getParent(n.edge[i]) + if n == getparent(n.edge[i]) push!(ci,i) end end @@ -1038,8 +973,8 @@ function deleteleaf!(net::HybridNetwork, nodeNumber::Integer; e1 = nodei.edge[1] e2 = nodei.edge[2] if e1.hybrid && e2.hybrid - cn = getChild(e1) - cn2 = getChild(e2) + cn = getchild(e1) + cn2 = getchild(e2) if !(nodei ≡ cn && nodei ≡ cn2) # nodei *not* the child of both e1 and e2 # possible at the root, in which case e1,e2 should have same child (i==net.root && cn ≡ cn2) || @@ -1047,7 +982,7 @@ function deleteleaf!(net::HybridNetwork, nodeNumber::Integer; # delete e1,e2,nodei and move the root to their child cn cn.hybrid || error("child node $(cn.number) of hybrid edges $(e1.number) and $(e2.number) should be a hybrid.") # check that cn doesn't have any other parent than e1 and e2 - any(getChild(e) ≡ cn && e !== e1 && e !==e2 for e in cn.edge) && + any(getchild(e) ≡ cn && e !== e1 && e !==e2 for e in cn.edge) && error("root has 2 hybrid edges, but their common child has an extra parent") removeEdge!(cn,e1); removeEdge!(cn,e2) removeHybrid!(net,cn) # removes n1 from net.hybrid, updates net.numHybrids @@ -1062,8 +997,8 @@ function deleteleaf!(net::HybridNetwork, nodeNumber::Integer; return nothing end # by now, nodei is the child of both e1 and e2 - p1 = getParent(e1) # find both parents of hybrid leaf - p2 = getParent(e2) + p1 = getparent(e1) # find both parents of hybrid leaf + p2 = getparent(e2) # remove node1 and both e1, e2 sameparent = (p1≡p2) # 2-cycle removeNode!(p1,e1); removeNode!(p2,e2) # perhaps useless @@ -1084,10 +1019,10 @@ function deleteleaf!(net::HybridNetwork, nodeNumber::Integer; elseif !nofuse e1 = fuseedgesat!(i,net, multgammas) # fused edge if simplify && e1.hybrid # check for 2-cycle at new hybrid edge - cn = getChild(e1) - e2 = getPartner(e1, cn) # companion hybrid edge - pn = getParent(e1) - if pn ≡ getParent(e2) + cn = getchild(e1) + e2 = getpartner(e1, cn) # companion hybrid edge + pn = getparent(e1) + if pn ≡ getparent(e2) # e1 and e2 have same child and same parent. Remove e1. e2.hybrid=false; e2.isMajor=true; @@ -1122,7 +1057,7 @@ function deleteaboveLSA!(net::HybridNetwork, preorder=true::Bool) nodei = popfirst!(net.nodes_changed) for e in nodei.edge # delete all of nodei's edges (which much be outgoing) - cn = getChild(e) + cn = getchild(e) removeEdge!(cn, e) # also updates cn.hasHybEdge empty!(e.node) deleteEdge!(net, e; part=false) @@ -1259,10 +1194,10 @@ function norootbelow!(e::Edge) e.containRoot || return nothing # if already false: stop # if true: turn to false then move down to e's children e.containRoot = false - cn = getChild(e) # cn = child node + cn = getchild(e) # cn = child node for ce in cn.edge ce !== e || continue # skip e - getParent(ce) === cn || continue # skip edges that aren't children of cn + getparent(ce) === cn || continue # skip edges that aren't children of cn norootbelow!(ce) end return nothing @@ -1280,13 +1215,13 @@ or if `n` is a hybrid node, then the edges below `e` or `n` are *not* traversed. function allowrootbelow!(e::Edge) e.containRoot = true e.hybrid && return nothing # e hybrid edge <=> its child hybrid node: stop - allowrootbelow!(getChild(e), e) + allowrootbelow!(getchild(e), e) end function allowrootbelow!(n::Node, pe::Edge) # pe assumed to be the parent of n for ce in n.edge ce !== pe || continue # skip parent edge of n - getParent(ce) === n || continue # skip edges that aren't children of n + getparent(ce) === n || continue # skip edges that aren't children of n allowrootbelow!(ce) end return nothing @@ -1315,9 +1250,9 @@ function unzip_canonical!(net::HybridNetwork) hybchild = Dict{Int,Tuple{Edge,Float64}}() # keys: hybrid node number (immutable) hybladder = Dict{Int,Union{Nothing,Node}}() for h in net.hybrid - ce = getChildEdge(h) + ce = getchildedge(h) hybchild[h.number] = (ce, ce.length) # original lengths before unzipping - hybladder[h.number] = (ce.hybrid ? getChild(ce) : nothing) + hybladder[h.number] = (ce.hybrid ? getchild(ce) : nothing) end hybrid_po = Node[] # will list hybrid nodes with partial post-order hybpriority = PriorityQueue(h => i for (i,h) in enumerate(net.hybrid)) diff --git a/src/moves_semidirected.jl b/src/moves_semidirected.jl index 673f7494..c250a570 100644 --- a/src/moves_semidirected.jl +++ b/src/moves_semidirected.jl @@ -132,7 +132,7 @@ function TopologyConstraint(type::UInt8, taxonnames::Vector{String}, net::Hybrid edgei = findfirst(e -> e.number == edgenum, net.edge) edgei !== nothing || error("hmm. hardwiredClusters on the major tree got an edge number not in the network") stemedge = net.edge[edgei] - mrcanode = getChild(stemedge) + mrcanode = getchild(stemedge) TopologyConstraint(type, taxonnames, taxonnums, stemedge, mrcanode) end function Base.show(io::IO, obj::TopologyConstraint) @@ -159,7 +159,7 @@ function constraintviolated(net::HybridNetwork, constraints::Vector{TopologyCons tree = majorTree(net) for con in constraints # checks directionality of stem edge hasn't changed if con.type in [0x01, 0x02] - getChild(con.edge) === con.node || return true + getchild(con.edge) === con.node || return true tei = findfirst(e -> e.number == con.edge.number, tree.edge) tei !== nothing || error("hmm. edge number $(con.edge.number) was not found in the network's major tree") @@ -226,7 +226,7 @@ function updateconstraints!(constraints::Vector{TopologyConstraint}, net::Hybrid tree = majorTree(net) for con in constraints if con.type in [0x01, 0x02] - getChild(con.edge) === con.node || + getchild(con.edge) === con.node || error("the stem edge and crown node have been disconnected") tei = findfirst(e -> e.number == con.edge.number, tree.edge) tei !== nothing || @@ -360,7 +360,7 @@ function nnimax(e::Edge) # e.hybrid and tree parent: BR case, 3 or 6 NNIs if e is may contain the root # e not hybrid, hyb parent: RB case, 4 NNIs # e not hybrid, tree parent: BB case, 2 NNIs if directed, 8 if undirected - hybparent = getParent(e).hybrid + hybparent = getparent(e).hybrid n = (e.hybrid ? (hybparent ? 0x02 : (e.containRoot ? 0x06 : 0x03)) : # RR & BR (hybparent ? 0x04 : (e.containRoot ? 0x08 : 0x02))) # RB & BB return n @@ -404,16 +404,16 @@ function nni!(net::HybridNetwork, uv::Edge, nummove::UInt8, return nothing end nummove <= nmovemax || error("nummove $(nummove) must be <= $nmovemax for edge number $(uv.number)") - u = getParent(uv) - v = getChild(uv) + u = getparent(uv) + v = getchild(uv) ## TASK 1: grab the edges adjacent to uv: αu, βu, vγ, vδ and adjacent nodes # get edges αu & βu connected to u # α = u's major parent if it exists, β = u's last child or minor parent if u.hybrid - αu = getMajorParentEdge(u) + αu = getparentedge(u) βu = getMinorParentEdge(u) - α = getParent(αu) - β = getParent(βu) + α = getparent(αu) + β = getparent(βu) else # u may not have any parent, e.g. if root node # pick αu = parent edge if possible, first edge of u (other than uv) otherwise labs = [edgerelation(e, u, uv) for e in u.edge] @@ -423,30 +423,30 @@ function nni!(net::HybridNetwork, uv::Edge, nummove::UInt8, length(ci) == 2 || error("node $(u.number) should have 2 children other than node number $(v.number)") pti = popfirst!(ci) αu = u.edge[pti] - α = getChild(αu) + α = getchild(αu) else αu = u.edge[pti] - α = getParent(αu) + α = getparent(αu) end βu = u.edge[ci[1]] - β = getChild(βu) + β = getchild(βu) end # get edges vδ & vγ connected to v # δ = v's last child, γ = other child or v's parent other than u labs = [edgerelation(e, v, uv) for e in v.edge] if v.hybrid # then v must have another parent edge, other than uv - vγ = v.edge[findfirst(isequal(:parent), labs)] # γ = getParent(vδ) ?this should be vγ right? + vγ = v.edge[findfirst(isequal(:parent), labs)] # γ = getparent(vδ) ?this should be vγ right? #on net_hybridladder edge 1 get ERROR: ArgumentError: invalid index: nothing of type Nothing vδ = v.edge[findfirst(isequal(:child), labs)] - γ = getParent(vγ) - δ = getChild(vδ) + γ = getparent(vγ) + δ = getchild(vδ) else ci = findall(isequal(:child), labs) length(ci) == 2 || error("node $(v.number) should have 2 children") - vγ = v.edge[ci[1]] # γ = getChild(vγ) + vγ = v.edge[ci[1]] # γ = getchild(vγ) vδ = v.edge[ci[2]] - γ = getChild(vγ) - δ = getChild(vδ) + γ = getchild(vγ) + δ = getchild(vδ) end ## TASK 2: semi-directed network swaps: ## swap u <-> v, α <-> β if undirected and according to move number @@ -502,8 +502,8 @@ function nni!(net::HybridNetwork, uv::Edge, nummove::UInt8, # moves 1 and 3 will fail if α -> γ # moves 2 and 3 will fail if β -> γ # nummove 3 always creates a nonDAG when u is the root - αparentu = getChild(αu)===u - βparentu = getChild(βu)===u + αparentu = getchild(αu)===u + βparentu = getchild(βu)===u if αparentu if γ === β || isdescendant(γ, β) return nothing; end elseif βparentu @@ -614,9 +614,9 @@ function nni!(αu::Edge, u::Node, uv::Edge, v::Node, vδ::Edge) vδ_in_v = findfirst(e->e===vδ, v.edge) v_in_vδ = findfirst(n->n===v, vδ.node) # none of them should be 'nothing' --not checked - αu_child = getChild(αu) - uv_child = getChild(uv) - vδ_child = getChild(vδ) + αu_child = getchild(αu) + uv_child = getchild(uv) + vδ_child = getchild(vδ) # flip the direction of uv if α->u->v->δ or α<-u<-v<-δ flip = (αu_child === u && uv_child === v && vδ_child !== v) || (αu_child !== u && uv_child === u && vδ_child === v) @@ -689,7 +689,7 @@ function nni!(αu::Edge, u::Node, uv::Edge, v::Node, vδ::Edge, end elseif u.hybrid && v.hybrid # RR: hybrid edges remain hybrids, but switch γs # we could have -αu-> -uv-> -vδ-> or <-αu- <-uv- <-vδ- - hyb = ( getChild(αu) == v ? αu : vδ ) # uv's hybrid parent edge: either αu or vδ + hyb = ( getchild(αu) == v ? αu : vδ ) # uv's hybrid parent edge: either αu or vδ (uv.gamma, hyb.gamma) = (hyb.gamma, uv.gamma) (uv.isMajor, hyb.isMajor) = (hyb.isMajor, uv.isMajor) end @@ -985,15 +985,15 @@ function fliphybrid!(net::HybridNetwork, hybridnode::Node, minor=true::Bool, =# runDirectEdges = false edgetoflip, edgetokeep = minor ? - (getMinorParentEdge(hybridnode), getMajorParentEdge(hybridnode)) : - (getMajorParentEdge(hybridnode), getMinorParentEdge(hybridnode)) - oldchildedge = getChildEdge(hybridnode) - newhybridnode = getParent(edgetoflip) + (getMinorParentEdge(hybridnode), getparentedge(hybridnode)) : + (getparentedge(hybridnode), getMinorParentEdge(hybridnode)) + oldchildedge = getchildedge(hybridnode) + newhybridnode = getparent(edgetoflip) if newhybridnode.hybrid # already has 2 parents: cannot had a third. return nothing end ## choose newhybridedge ## - p2 = getParent(edgetokeep) # parent node + p2 = getparent(edgetokeep) # parent node isdesc = Bool[] for e in newhybridnode.edge # is p2 undirected descendant of nhn via this edge? isp2desc = false @@ -1021,7 +1021,7 @@ function fliphybrid!(net::HybridNetwork, hybridnode::Node, minor=true::Bool, if sum_isdesc == 0 # no risk to create directed cycle. # choose the current parent edge of nhn to: keep its current direction # and keep reaching all nodes from a single root - newhybridedge = getMajorParentEdge(newhybridnode) + newhybridedge = getparentedge(newhybridnode) else newhybridedge = newhybridnode.edge[findfirst(isdesc)] if newhybridedge.hybrid # cannot flip another hybrid edge, but we needed @@ -1051,7 +1051,7 @@ function fliphybrid!(net::HybridNetwork, hybridnode::Node, minor=true::Bool, edgetokeep.isMajor = true # update node order to keep isChild1 attribute of hybrid edges true edgetoflip.isChild1 = !edgetoflip.isChild1 # just switch - if getChild(newhybridedge) !== newhybridnode # includes the case when the newhybridnode was the root + if getchild(newhybridedge) !== newhybridnode # includes the case when the newhybridnode was the root # then flip newhybridedge too: make it point towards newhybridnode newhybridedge.isChild1 = !newhybridedge.isChild1 net.root = findfirst(n -> n === hybridnode, net.node) @@ -1072,7 +1072,7 @@ function fliphybrid!(net::HybridNetwork, hybridnode::Node, minor=true::Bool, # norootbelow in child edges of newhybridedge for ce in newhybridnode.edge ce !== newhybridedge || continue # skip e - getParent(ce) === newhybridnode || continue # skip edges that aren't children of cn + getparent(ce) === newhybridnode || continue # skip edges that aren't children of cn norootbelow!(ce) end # allow root for edges below old hybrid node diff --git a/src/pairwiseDistanceLS.jl b/src/pairwiseDistanceLS.jl index 94ef43fb..3ab5470d 100644 --- a/src/pairwiseDistanceLS.jl +++ b/src/pairwiseDistanceLS.jl @@ -17,8 +17,8 @@ function getNodeAges(net::HybridNetwork) continue end for e in n.edge - if getParent(e) == n # n parent of e - childnode = getChild(e) + if getparent(e) == n # n parent of e + childnode = getchild(e) childIndex = getIndex(childnode, net.nodes_changed) x[i] = x[childIndex] + e.length break # use 1st child, ignores all others @@ -282,12 +282,12 @@ function calibrateFromPairwiseDistances!(net::HybridNetwork, hybGParentI = Int[] # index in 1:nparams of minor (grand-)parent in param list for i in hybInd n = net.nodes_changed[i] - p = getMinorParent(n) + p = getparentminor(n) pi = findfirst(n -> n===p, net.nodes_changed) push!(hybParentInd, pi) pii = findfirst(isequal(pi), parind) while pii===nothing # in case minor parent of n is also hybrid node - p = getMinorParent(p) + p = getparentminor(p) pi = findfirst(n -> n===p, net.nodes_changed) pii = findfirst(isequal(pi), parind) end @@ -328,8 +328,8 @@ function calibrateFromPairwiseDistances!(net::HybridNetwork, nii = findfirst(isequal(i), parind) end for e in n.edge - if getChild(e) == n # n child of e - p = getParent(e) # parent of n + if getchild(e) == n # n child of e + p = getparent(e) # parent of n if forceMinorLength0 && n.hybrid && !e.isMajor continue; end # p and n at same age already pi = findfirst(isequal(p.number), [no.number for no in net.nodes_changed]) diff --git a/src/parsimony.jl b/src/parsimony.jl index d413e4a2..c7b49524 100644 --- a/src/parsimony.jl +++ b/src/parsimony.jl @@ -179,14 +179,14 @@ function parsimonyBottomUpSoftwired!(node::Node, blobroot::Node, nchar::Integer, return nothing # isExtBadTriangle=dummy leaf: root of another blob end for e in node.edge - if (e.hybrid && e.fromBadDiamondI) || getChild(e) == node continue; end # fromBadDiamondI= edge switched off - son = getChild(e) + if (e.hybrid && e.fromBadDiamondI) || getchild(e) == node continue; end # fromBadDiamondI= edge switched off + son = getchild(e) parsimonyBottomUpSoftwired!(son, blobroot, nchar, w, parsimonyscore) end for s in 1:nchar for e in node.edge - if (e.hybrid && e.fromBadDiamondI) || getChild(e) == node continue; end - son = getChild(e) + if (e.hybrid && e.fromBadDiamondI) || getchild(e) == node continue; end + son = getchild(e) bestMin = Inf # best score from to this one child starting from s at the node for sf in 1:nchar # best assignement for the son minpars = parsimonyscore[son.number,sf] @@ -681,11 +681,11 @@ function parsimonyGF(net::HybridNetwork, species::Array{String}, for melist in minorEdges # minor edge list for one single blob + loop over blobs guessedparentBlob = Node[] for e in melist - p = getParent(e) + p = getparent(e) if p ∉ guessedparentBlob push!(guessedparentBlob, p) for e2 in p.edge - p == getParent(e2) || continue + p == getparent(e2) || continue e2.fromBadDiamondI = true # cut the edge: not followed in recursive call end end @@ -707,14 +707,14 @@ function parsimonyGF(net::HybridNetwork, species::Array{String}, # first: calculate inCycle = # of detached parents for e in net.edge e.fromBadDiamondI || continue # to next edge if current edge not cut - n = getChild(e) + n = getchild(e) n.inCycle += 1 end # second: make inCycle = 0 if node has a non-detached parent for n in net.node n.inCycle > 0 || continue # to next node if inCycle = 0 already for e in n.edge - n == getChild(e) || continue + n == getchild(e) || continue !e.fromBadDiamondI || continue n.inCycle = 0 # if e parent of n and e not cut: make inCycle 0 break @@ -879,14 +879,14 @@ function parsimonyBottomUpGF!(node::Node, blobroot::Node, nchar::Integer, if !node.leaf && (!node.isExtBadTriangle || node == blobroot) # isExtBadTriangle=dummy leaf: root of another blob for e in node.edge # post-order traversal according to major tree: detached edges were minor. - if !e.isMajor || getChild(e) == node continue; end # Even if we didn't visit one parent (yet), - son = getChild(e) # that parent is a minor parent with an assigned guessed state. + if !e.isMajor || getchild(e) == node continue; end # Even if we didn't visit one parent (yet), + son = getchild(e) # that parent is a minor parent with an assigned guessed state. parsimonyBottomUpGF!(son, blobroot, nchar, w, parsimonyscore, costmatrix1, costmatrix2) end # check to see if "node" has guessed value: by checking to see if all its children edges were cut cutparent = false for e in node.edge - if getChild(e) == node continue; end + if getchild(e) == node continue; end if e.fromBadDiamondI # if true: one child edge is cut, so all are cut cutparent = true break @@ -894,13 +894,13 @@ function parsimonyBottomUpGF!(node::Node, blobroot::Node, nchar::Integer, end if !cutparent # look at best assignment of children, to score each assignment at node for e in node.edge # avoid edges that were cut: those for which fromBadDiamondI is true - son = getChild(e) + son = getchild(e) if son == node continue; end bestpars = [Inf for s in 1:nchar] # best score, so far, for state s at node. # calculate cost to go from each s (and from parents' guesses, stored in w) to son state: if son.hybrid # find potential other parent of son, detached with guessed states - p2 = getMinorParent(son) + p2 = getparentminor(son) k = findfirst(isequal(0.0), w[p2.number, 1:nchar]) # guess made for parent p2 for sfinal in 1:nchar pars = parsimonyscore[son.number, sfinal] .+ costmatrix2[k][1:nchar,sfinal] @@ -937,7 +937,7 @@ function parsimonyBottomUpGF!(node::Node, blobroot::Node, nchar::Integer, cost = 0.0 # variable external to 'for' loops below if node.inCycle == 1 # 1 detached parent, no non-detached parents for e in node.edge - par = getParent(e) + par = getparent(e) if par == node continue; end # now 'par' is the single detached parent k = findfirst(isequal(0.0), w[par.number, 1:nchar]) # guess at parent @@ -949,7 +949,7 @@ function parsimonyBottomUpGF!(node::Node, blobroot::Node, nchar::Integer, else # node.inCycle should be 2: 2 detached parents k1 = 0 # guess made on first detached parent for e in node.edge - par = getParent(e) + par = getparent(e) if par == node continue; end # now 'par' is one of the 2 guessed parents if k1 == 0 diff --git a/src/phyLiNCoptimization.jl b/src/phyLiNCoptimization.jl index 095ea0d9..b5fcf849 100644 --- a/src/phyLiNCoptimization.jl +++ b/src/phyLiNCoptimization.jl @@ -211,7 +211,7 @@ function phyLiNC(net::HybridNetwork, fastafile::String, modSymbol::Symbol, end unzip_canonical!(obj.net) for e in obj.net.edge # bring branch lengths inside bounds - if e.length < BLmin && !getParent(e).hybrid + if e.length < BLmin && !getparent(e).hybrid e.length = BLmin elseif e.length > BLmax e.length = BLmax @@ -488,7 +488,7 @@ function phyLiNCone!(obj::SSM, maxhybrid::Int, no3cycle::Bool, alphamin=alphamin,alphamax=alphamax, pinvmin=pinvmin,pinvmax=pinvmax) optimizealllengths_LiNC!(obj, lcache) # 1 edge at a time, random order for i in Random.shuffle(1:obj.net.numHybrids) - e = getMajorParentEdge(obj.net.hybrid[i]) + e = getparentedge(obj.net.hybrid[i]) optimizelocalgammas_LiNC!(obj, e, ftolAbs, γcache) end ghosthybrid = false # find hybrid edges with γ=0, to delete them @@ -805,16 +805,16 @@ function addhybridedgeLiNC!(obj::SSM, currLik::Float64, isnothing(result) && return nothing newhybridnode, newhybridedge = result # next: increase length of split edges if they became < BLmin - splitedges = getParent(newhybridedge).edge # new hybrid edge = splitedges[3] + splitedges = getparent(newhybridedge).edge # new hybrid edge = splitedges[3] # splitedges[1] and splitedges[2] have length 1/2 of original edge... # except if hybrid ladder was created (and unzipped) for e in splitedges[1:2] - if e.length < BLmin && !getParent(e).hybrid + if e.length < BLmin && !getparent(e).hybrid e.length = BLmin end end # unzip only at new node and its child edge - unzipat_canonical!(newhybridnode, getChildEdge(newhybridnode)) + unzipat_canonical!(newhybridnode, getchildedge(newhybridnode)) updateSSM!(obj) #, true; constraints=constraints) optimizelocalgammas_LiNC!(obj, newhybridedge, ftolAbs, γcache) if newhybridedge.gamma == 0.0 @@ -912,7 +912,7 @@ function deletehybridedgeLiNC!(obj::SSM, currLik::Float64, setGamma!(minorhybridedge, 0.0) l1mγ = log(1.0-γ0) nt, hase = updatecache_hase!(γcache, obj, minorhybridedge.number, - getMajorParentEdge(hybridnode).number) + getparentedge(hybridnode).number) for it in 1:nt @inbounds h = hase[it] ismissing(h) && continue # tree has unchanged weight: skip below @@ -925,7 +925,7 @@ function deletehybridedgeLiNC!(obj::SSM, currLik::Float64, if hybrid ladder (minor parent is hybrid node): not identifiable at all otherwise: only their sum is identifiable, but not individual lengths so: optimize length of major hybrid edge only =# - majhyb = getMajorParentEdge(hybridnode) + majhyb = getparentedge(hybridnode) len0 = majhyb.length # to restore later if deletion rejected update_logtrans(obj) # fixit: is that really needed? optimizelength_LiNC!(obj, majhyb, lcache, Q(obj.model)) @@ -992,7 +992,7 @@ function fliphybridedgeLiNC!(obj::SSM, currLik::Float64, nohybridladder::Bool, # reassign old child edge to BLmin (was zero) oldchildedge.length = BLmin # adjacent to flippedge, saved above # unzip only at new node and its child edge - getChildEdge(newhybridnode).length = 0.0 # adjacent to flippedge, saved above + getchildedge(newhybridnode).length = 0.0 # adjacent to flippedge, saved above updateSSM!(obj) #, true; constraints=constraints) # displayed trees have changed optimizelocalgammas_LiNC!(obj, flippededge, ftolAbs, γcache) # don't delete a flipped edge with γ=0: to be able to undo the flip @@ -1275,13 +1275,13 @@ function updatecache_edge!(lcache::CacheLengthLiNC, obj::SSM, focusedge) nt = length(tree) # could be less than dimensions in lcache # ! a sister edge in network may be absent in a displayed tree # but: edge & node numbers are the same in net and in trees - v = getParent(focusedge) # ! focus edge needs same direction in displayed trees + v = getparent(focusedge) # ! focus edge needs same direction in displayed trees vnum = v.number - unum = getChild(focusedge).number + unum = getchild(focusedge).number enum = focusedge.number snum = Int[] for e in v.edge - if e !== focusedge && v == getParent(e) # then e sister to focus edge + if e !== focusedge && v == getparent(e) # then e sister to focus edge push!(snum, e.number) end end @@ -1354,7 +1354,7 @@ function optimizealllengths_LiNC!(obj::SSM, lcache::CacheLengthLiNC) if !isempty(obj.net.hybrid) @inbounds for i in length(edges):-1:1 e = edges[i] - (getParent(e).hybrid || e.gamma == 0.0) && deleteat!(edges, i) + (getparent(e).hybrid || e.gamma == 0.0) && deleteat!(edges, i) end end # reduce edge lengths beyond upper bounds @@ -1421,7 +1421,7 @@ function optimizelocalBL_LiNC!(obj::SSM, focusedge::Edge, lcache::CacheLengthLiN if !isempty(obj.net.hybrid) @inbounds for i in length(neighboredges):-1:1 e = neighboredges[i] - (getParent(e).hybrid || e.gamma == 0.0) && deleteat!(neighboredges, i) + (getparent(e).hybrid || e.gamma == 0.0) && deleteat!(neighboredges, i) end end # reduce edge lengths beyond upper bounds: can appear from unzipping, @@ -1449,7 +1449,7 @@ Warning: displayed trees are assumed up-to-date, with nodes preordered """ function optimizelength_LiNC!(obj::SSM, focusedge::Edge, lcache::CacheLengthLiNC, qmat) - getParent(focusedge).hybrid && return nothing # keep the reticulation unzipped + getparent(focusedge).hybrid && return nothing # keep the reticulation unzipped # the length of focus edge should be 0. stay as is. cfg = updatecache_edge!(lcache, obj, focusedge) ismissing(cfg) && return nothing @@ -1659,7 +1659,7 @@ function optimizelocalgammas_LiNC!(obj::SSM, edge::Edge, for i in length(neighborhybs):-1:1 e = neighborhybs[i] e.isMajor || continue # skip below for minor edges - p = getPartner(e) # minor partner + p = getpartner(e) # minor partner j = findfirst(x -> x===p, neighborhybs) if isnothing(j) neighborhybs[i] = p # replace major e by its minor partner @@ -1711,7 +1711,7 @@ function optimizegamma_LiNC!(obj::SSM, focusedge::Edge, ftolAbs::Float64, cache::CacheGammaLiNC, maxNR=10::Int) ## step 1: prepare vectors constant during the search edgenum = focusedge.number - partner = getPartner(focusedge) + partner = getpartner(focusedge) partnernum = partner.number clike = cache.clike # conditional likelihood under focus edge clikp = cache.clikp # conditional likelihood under partner edge diff --git a/src/readwrite.jl b/src/readwrite.jl index c77c04ae..0dda1f8e 100644 --- a/src/readwrite.jl +++ b/src/readwrite.jl @@ -359,7 +359,7 @@ nor that `n` is the child of `e`. @inline function synchronizePartnersData!(e::Edge, n::Node) partners = Edge[] # The edges having n as a child, other than e for e2 in n.edge - if e2.hybrid && e2!=e && n==getChild(e2) + if e2.hybrid && e2!=e && n==getchild(e2) push!(partners, e2) end end @@ -615,7 +615,7 @@ function checkNumHybEdges!(net::HybridNetwork) elseif hyb >=2 # check: exactly 2 incoming, no more. nhybparents = 0 for e in n.edge - if n == getChild(e) + if n == getchild(e) if e.hybrid nhybparents += 1 else @error "node $(n.number) has parent tree edge $(e.number): wrong isChild1 for this edge?" @@ -1039,9 +1039,9 @@ function writeSubTree!(s::IO, n::Node, parent::Union{Edge,Nothing}, for e in n.edge e != parent || continue # skip parent edge where we come from if parent == nothing # skip if n = child of e - n != getChild(e) || continue + n != getchild(e) || continue end - (e.hybrid && getChild(e)==n) && continue # no going up minor hybrid + (e.hybrid && getchild(e)==n) && continue # no going up minor hybrid firstchild || print(s, ",") firstchild = false child = getOtherNode(e,n) @@ -1473,7 +1473,7 @@ function writeTopology(net::HybridNetwork, s::IO, for e in net.edge # parents of hybrid edges should be sufficient, but gives weird look #if e.hybrid - i = getIndex(getParent(e), net) + i = getIndex(getparent(e), net) net.root = i try directEdges!(net) diff --git a/src/traits.jl b/src/traits.jl index 45a86cbe..967c8716 100644 --- a/src/traits.jl +++ b/src/traits.jl @@ -111,7 +111,7 @@ function updatePreOrder!(i::Int, updateTree::Function, updateHybrid::Function, params) - parent = getParents(nodes[i]) #array of nodes (empty, size 1 or 2) + parent = getparents(nodes[i]) # vector of nodes (empty, size 1 or 2) if(isempty(parent)) #nodes[i] is root updateRoot(V, i, params) elseif(length(parent) == 1) #nodes[i] is tree @@ -181,7 +181,7 @@ function updatePostOrder!(i::Int, updateTip::Function, updateNode::Function, params) - children = getChildren(nodes[i]) #array of nodes (empty, size 1 or 2) + children = getchildren(nodes[i]) # vector of nodes (empty, size 1 or 2) if(isempty(children)) #nodes[i] is a tip updateTip(V, i, params) else @@ -573,7 +573,7 @@ end function regressorShift(edge::Vector{Edge}, net::HybridNetwork; checkPreorder=true::Bool) - childs = [getChild(ee) for ee in edge] + childs = [getchild(ee) for ee in edge] return(regressorShift(childs, net; checkPreorder=checkPreorder)) end @@ -679,7 +679,7 @@ AIC: 7.4012043891 [`phylolm`](@ref), [`descendenceMatrix`](@ref), [`regressorShift`](@ref). """ function regressorHybrid(net::HybridNetwork; checkPreorder=true::Bool) - childs = [getChildren(nn)[1] for nn in net.hybrid] + childs = [getchild(nn) for nn in net.hybrid] # checks that each hybrid node has a single child dfr = regressorShift(childs, net; checkPreorder=checkPreorder) dfr[!,:sum] = sum.(eachrow(select(dfr, Not(:tipNames), copycols=false))) return(dfr) @@ -747,7 +747,7 @@ end function ShiftNet(edge::Vector{Edge}, value::Union{AbstractVector, AbstractMatrix}, net::HybridNetwork; checkPreorder=true::Bool) - childs = [getChild(ee) for ee in edge] + childs = [getchild(ee) for ee in edge] return(ShiftNet(childs, value, net; checkPreorder=checkPreorder)) end @@ -780,7 +780,7 @@ function shiftHybrid(value::Union{Matrix{T}, Vector{T}} where T<:Real, if length(net.hybrid) != size(value, 1) error("You must provide as many values as the number of hybrid nodes.") end - childs = [getChildren(nn)[1] for nn in net.hybrid] + childs = [getchild(nn) for nn in net.hybrid] # checks for single child return(ShiftNet(childs, value, net; checkPreorder=checkPreorder)) end shiftHybrid(value::Real, net::HybridNetwork; checkPreorder=true::Bool) = shiftHybrid([value], net; checkPreorder=checkPreorder) @@ -799,7 +799,7 @@ end function getMajorParentEdgeNumber(n::Node) try - getMajorParentEdge(n).number + getparentedge(n).number catch -1 end @@ -1804,7 +1804,12 @@ function setGammas!(net::HybridNetwork, gammas::Vector) if isHybrid[i] nod = net.nodes_changed[i] majorHybrid = [edg.hybrid & edg.isMajor for edg in nod.edge] - # worry: assume tree-child network? getMajorParent and getMinorParent would be safer + #= worry: assume tree-child network? getMajorParent and getMinorParent would be safer + fixit fixit fixit! + use getparentedge(nod) and getparentedgeminor instead; + change & to && . ex: check impact on [isodd(x) & x<3 for x in [4,3,2,1]] + don't do if/else below: !any is different from !all. Or if unsyncing major & minor is intentional: then document it. + =# minorHybrid = [edg.hybrid & !edg.isMajor for edg in nod.edge] nod.edge[majorHybrid][1].gamma = gammas[i] if any(minorHybrid) # case where gamma = 0.5 exactly diff --git a/src/traitsLikDiscrete.jl b/src/traitsLikDiscrete.jl index 781a4017..fcb4ff41 100644 --- a/src/traitsLikDiscrete.jl +++ b/src/traitsLikDiscrete.jl @@ -765,7 +765,7 @@ function discrete_corelikelihood_trait!(obj::SSM, t::Integer, ci::Integer, ri::I end else # forward likelihood = product of direct likelihood over all children edges for e in n.edge - n == getParent(e) || continue # to next edge if n is not parent of e + n == getparent(e) || continue # to next edge if n is not parent of e forwardlik[:,nnum] .+= view(directlik, :,e.number) end end @@ -776,7 +776,7 @@ function discrete_corelikelihood_trait!(obj::SSM, t::Integer, ci::Integer, ri::I # if we keep going, n is not the root # calculate direct likelihood on the parent edge of n for e in n.edge - if n == getChild(e) + if n == getchild(e) lt = view(obj.logtrans, :,:,e.number, ri) for i in 1:k # state at parent node directlik[i,e.number] = logsumexp(view(lt,i,:) + view(forwardlik,:,nnum)) @@ -1082,11 +1082,11 @@ function discrete_backwardlikelihood_trait!(obj::SSM, t::Integer, ri::Integer) if ni == 1 # n is the root backwardlik[:,nnum] = logprior else - pe = getMajorParentEdge(n) - pn = getParent(pe) + pe = getparentedge(n) + pn = getparent(pe) bkwtmp[:] = backwardlik[:,pn.number] # use bktmp's original memory for se in pn.edge - if se != pe && pn == getParent(se) # then se is sister edge to pe + if se != pe && pn == getparent(se) # then se is sister edge to pe bkwtmp .+= view(directlik, :,se.number) end end diff --git a/test/test_addHybrid.jl b/test/test_addHybrid.jl index 11ec30f4..1b968ffd 100644 --- a/test/test_addHybrid.jl +++ b/test/test_addHybrid.jl @@ -13,13 +13,13 @@ Random.seed!(5432); @test tree.numHybrids == 1 @test !isnothing(PhyloNetworks.addhybridedge!(tree, true, true)) # should be able to add a hybrid @test tree.numHybrids == 2 -@test !any([n.hybrid for n in PhyloNetworks.getParents(tree.hybrid[2])]) # tests if network is treechild +@test !any([n.hybrid for n in PhyloNetworks.getparents(tree.hybrid[2])]) # tests if network is treechild str_level1 = "(((S8,S9),((((S1,S4),(S5)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" netl1 = readTopology(str_level1) @test !isnothing(PhyloNetworks.addhybridedge!(netl1, true, true)) @test netl1.numHybrids == 3 -@test !any([n.hybrid for n in PhyloNetworks.getParents(netl1.hybrid[3])]) # tests if network has no hybrid ladder +@test !any([n.hybrid for n in PhyloNetworks.getparents(netl1.hybrid[3])]) # tests if network has no hybrid ladder netl1 = readTopology(str_level1) newhybridnode, newhybridedge = PhyloNetworks.addhybridedge!(netl1, false, true) @@ -35,7 +35,7 @@ str_level1 = "(((S8,S9),((((S1,S4),(S5)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" netl1 = readTopology(str_level1) newhybridnode, newhybridedge = PhyloNetworks.addhybridedge!(netl1, netl1.edge[3], netl1.edge[9], true, 0.0, 0.2) @test newhybridnode.hybrid -@test PhyloNetworks.getMajorParentEdge(newhybridnode).gamma == 0.8 +@test PhyloNetworks.getparentedge(newhybridnode).gamma == 0.8 @test PhyloNetworks.getMinorParentEdge(newhybridnode).gamma == 0.2 netl1 = readTopology(str_level1); @test !isnothing(PhyloNetworks.addhybridedge!(netl1, netl1.edge[15], netl1.edge[3], true)) @@ -69,7 +69,7 @@ netl1 = readTopology(str_level1); # directional: throws error if the new network would not be a DAG, e.g. if edge 1 is a directed descendant of edge 2 # case 6 -nodeS145 = PhyloNetworks.getParent(netl1.edge[6]) +nodeS145 = PhyloNetworks.getparent(netl1.edge[6]) @test PhyloNetworks.directionalconflict(netl1, nodeS145, netl1.edge[15], true) # case 2 @test PhyloNetworks.directionalconflict(netl1, nodeS145, netl1.edge[18], true) diff --git a/test/test_manipulateNet.jl b/test/test_manipulateNet.jl index a544c388..f6fc9548 100644 --- a/test/test_manipulateNet.jl +++ b/test/test_manipulateNet.jl @@ -37,22 +37,22 @@ node leaf hybrid hasHybEdge name inCycle edges'numbers 10 false false true S4 -1 3 11 """ close(s); -@test_throws ErrorException PhyloNetworks.getMinorParent(net.node[1]) -@test PhyloNetworks.getMajorParent(net.node[1]).number == 2 -@test PhyloNetworks.getMinorParent(net.node[3]).number == 6 -@test PhyloNetworks.getMajorParent(net.node[3]).number == 10 -@test PhyloNetworks.getMajorParentEdge(net.node[6]).number == 7 +@test_throws ErrorException PhyloNetworks.getparentminor(net.node[1]) +@test PhyloNetworks.getparent(net.node[1]).number == 2 +@test PhyloNetworks.getparentminor(net.node[3]).number == 6 +@test PhyloNetworks.getparent(net.node[3]).number == 10 +@test PhyloNetworks.getparentedge(net.node[6]).number == 7 @test_throws ErrorException PhyloNetworks.getMinorParentEdge(net.node[6]) -@test PhyloNetworks.getMajorParentEdge(net.node[2]).number == 2 +@test PhyloNetworks.getparentedge(net.node[2]).number == 2 @test PhyloNetworks.getMinorParentEdge(net.node[2]).number == 8 -@test [n.number for n in PhyloNetworks.getChildren(net.node[4])] == [] # leaf -@test [n.number for n in PhyloNetworks.getChildren(net.node[2])] == [1] # hybrid node -@test [n.number for n in PhyloNetworks.getChildren(net.node[9])] == [6,8] # tree node -@test [n.number for n in PhyloNetworks.getChildren(net.node[10])] == [3,9] # at root -@test [n.number for n in PhyloNetworks.getChildren(net.node[6])] == [4,5,3] # polytomy -@test PhyloNetworks.getParent(net.edge[8]).number == 8 -@test [n.number for n in PhyloNetworks.getParents(net.node[3])] == [10, 6] -@test [n.number for n in PhyloNetworks.getParents(net.node[6])] == [9] +@test [n.number for n in PhyloNetworks.getchildren(net.node[4])] == [] # leaf +@test [n.number for n in PhyloNetworks.getchildren(net.node[2])] == [1] # hybrid node +@test [n.number for n in PhyloNetworks.getchildren(net.node[9])] == [6,8] # tree node +@test [n.number for n in PhyloNetworks.getchildren(net.node[10])] == [3,9] # at root +@test [n.number for n in PhyloNetworks.getchildren(net.node[6])] == [4,5,3] # polytomy +@test PhyloNetworks.getparent(net.edge[8]).number == 8 +@test [n.number for n in PhyloNetworks.getparents(net.node[3])] == [10, 6] +@test [n.number for n in PhyloNetworks.getparents(net.node[6])] == [9] @test_throws ErrorException deleteleaf!(net, net.node[9]) n = deepcopy(net) @test_logs deleteleaf!(n, n.node[7]) diff --git a/test/test_moves_semidirected.jl b/test/test_moves_semidirected.jl index ad652433..49f20e9b 100644 --- a/test/test_moves_semidirected.jl +++ b/test/test_moves_semidirected.jl @@ -37,10 +37,10 @@ net_hybridladder = readTopology(str_hybridladder); # check directionality if move in [3, 4, 5, 7] # keeping α, β or flipping uv keeps node -4 as child of edge 3 - @test PhyloNetworks.getChild(net_level1.edge[3]).number == -4 + @test PhyloNetworks.getchild(net_level1.edge[3]).number == -4 else # switching α, β AND flipping uv or doing neither makes node -3 child of edge 3 - @test PhyloNetworks.getChild(net_level1.edge[3]).number == -3 + @test PhyloNetworks.getchild(net_level1.edge[3]).number == -3 end # undo move nni!(undoinfo...); @@ -59,7 +59,7 @@ end # of level1 edge 3: BB undirected @test 8 in nodes # check that edge α connected to v nodes = [n.number for n in net_level1.edge[11].node] @test !(-11 in nodes) - @test PhyloNetworks.getChild(net_level1.edge[13]).number == -11 + @test PhyloNetworks.getchild(net_level1.edge[13]).number == -11 nni!(undoinfo...); # undo move @test writeTopology(net_level1) == "(((S8,S9),(((((S1,S2,S3),S4),(S5:0.0)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" # confirm we're back to original topology (but now with 0.0 branch lengths) @@ -80,7 +80,7 @@ end # of level1 edge 3: BB undirected @test !(-11 in nodes) end # check directionality - @test PhyloNetworks.getChild(net_level1.edge[13]).number == 8 + @test PhyloNetworks.getchild(net_level1.edge[13]).number == 8 nni!(undoinfo...); # undo move @test writeTopology(net_level1) == "(((S8,S9),(((((S1,S2,S3),S4),(S5:0.0)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));"# confirm we're back to original topology end @@ -98,7 +98,7 @@ end # of level1 edge 13: BR directed @test -11 in nodes end # check directionality node -11 child of edge 16 in both cases - @test PhyloNetworks.getChild(net_level1.edge[16]).number == -11 + @test PhyloNetworks.getchild(net_level1.edge[16]).number == -11 nni!(undoinfo...); # undo move @test writeTopology(net_level1) == "(((S8,S9),(((((S1,S2,S3),S4),(S5:0.0)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" # confirm we're back to original topology @@ -120,7 +120,7 @@ end #of level1 edge 16: BB directed #check that edge γ connected to v @test -11 in nodes # check directionality node -6 child of edge 17 in both cases - @test PhyloNetworks.getChild(net_level1.edge[17]).number == -6 + @test PhyloNetworks.getchild(net_level1.edge[17]).number == -6 nni!(undoinfo...); # undo move @test writeTopology(net_level1) == "(((S8,S9),(((((S1,S2,S3),S4),(S5:0.0)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" else @@ -132,7 +132,7 @@ end #of level1 edge 16: BB directed #check that edge γ connected to u @test -6 in nodes # check directionality node -11 child of edge 17 in both cases - @test PhyloNetworks.getChild(net_level1.edge[17]).number == -6 + @test PhyloNetworks.getchild(net_level1.edge[17]).number == -6 nni!(undoinfo...); # undo move @test writeTopology(net_level1) == "(((S8,S9),(((((S1,S2,S3),S4),(S5:0.0)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" end @@ -155,7 +155,7 @@ end # of level1 edge 17: BB directed @test !(11 in nodes) end #check directionality (should point toward u, node 11) - @test PhyloNetworks.getChild(net_level1.edge[18]).number == 11 + @test PhyloNetworks.getchild(net_level1.edge[18]).number == 11 nni!(undoinfo...); # edge constrained at 0.0 now @test writeTopology(net_level1) == "(((S8,S9),(((((S1,S2,S3),S4),(S5:0.0)#H1),(#H1,(S6,S7))):0.0)#H2),(#H2,S10));" @@ -181,7 +181,7 @@ end # of level1 edge 18: RR (directed) @test !(3 in nodes) end #check directionality (should point toward u, node 3) - @test PhyloNetworks.getChild(net_nontreechild.edge[3]).number == 3 + @test PhyloNetworks.getchild(net_nontreechild.edge[3]).number == 3 #undo move nni!(undoinfo...); # keep constrained edges at 0.0, but otherwise topology completely restored @@ -207,7 +207,7 @@ end #of non tree child net edge 5: RB (directed) nodes = [n.number for n in net_hybridladder.edge[4].node] # δ's connections @test -2 in nodes # check that edge δ is connected to u # check directionality (edge should point toward u, node -2) - @test PhyloNetworks.getChild(net_hybridladder.edge[1]).number == 1 + @test PhyloNetworks.getchild(net_hybridladder.edge[1]).number == 1 nni!(undoinfo...); @test writeTopology(net_hybridladder)== "(#H2:::0.2,((C,((B)#H1:0.0)#H2:::0.8),(#H1,(A1,A2))),O);" # restored but edge below hybrid node constrained at 0.0 elseif move == 0x02 @@ -217,7 +217,7 @@ end #of non tree child net edge 5: RB (directed) nodes = [n.number for n in net_hybridladder.edge[4].node] # δ's connections @test -2 in nodes # δ connected to u # check directionality (edge should point toward u, node -2) - @test PhyloNetworks.getChild(net_hybridladder.edge[1]).number == 1 + @test PhyloNetworks.getchild(net_hybridladder.edge[1]).number == 1 nni!(undoinfo...); @test writeTopology(net_hybridladder) == "(#H2:::0.2,((C,((B)#H1:0.0)#H2:::0.8),(#H1,(A1,A2))),O);" # restored but edge below hybrid node constrained at 0.0 end @@ -237,7 +237,7 @@ end # of hybrid ladder net edge 1: BR undirected nodes = [n.number for n in net_hybridladder.edge[3].node] @test 1 in nodes #check directionality (should point toward u, node 1) - @test PhyloNetworks.getChild(net_hybridladder.edge[4]).number == 1 + @test PhyloNetworks.getchild(net_hybridladder.edge[4]).number == 1 #undo move nni!(undoinfo...); @test writeTopology(net_hybridladder) == "(#H2:::0.2,((C,((B)#H1:0.0)#H2:::0.8),(#H1,(A1,A2))),O);" # restored but edge below hybrid node constrained at 0.0 @@ -271,9 +271,9 @@ end #of hybrid ladder net edge 4: RR (directed) #check directionality if move in [0x01, 0x05] #(edge should point toward u, node -4) - @test PhyloNetworks.getChild(net_hybridladder.edge[5]).number == -4 + @test PhyloNetworks.getchild(net_hybridladder.edge[5]).number == -4 else - @test PhyloNetworks.getChild(net_hybridladder.edge[5]).number == 1 + @test PhyloNetworks.getchild(net_hybridladder.edge[5]).number == 1 end #undo move nni!(undoinfo...); @@ -302,7 +302,7 @@ end #of hybrid ladder net edge 5: BR undirected @test !(-2 in nodes) end #check directionality - @test PhyloNetworks.getChild(net_hybridladder.edge[12]).number == -3 + @test PhyloNetworks.getchild(net_hybridladder.edge[12]).number == -3 #undo move nni!(undoinfo...); @test writeTopology(net_hybridladder) == "(#H2:::0.2,((C,((B)#H1:0.0)#H2:::0.8),(#H1,(A1,A2))),O);" # restored but edge below hybrid node constrained at 0.0 @@ -340,8 +340,8 @@ newnode, newedge = PhyloNetworks.breakedge!(net_level1_s.edge[4], net_level1_s); @test length(net_level1_s.edge) == 21 @test newnode.edge[1].number == 4 @test newnode.edge[2].number == 21 -@test PhyloNetworks.getParent(net_level1_s.edge[4]) === newnode -@test PhyloNetworks.getChild(newedge) === newnode +@test PhyloNetworks.getparent(net_level1_s.edge[4]) === newnode +@test PhyloNetworks.getchild(newedge) === newnode # test addleaf! function net_level1_s = readTopology(str_level1_s) @@ -351,8 +351,8 @@ PhyloNetworks.addleaf!(net_level1_s, net_level1_s.node[4], "S1B"); PhyloNetworks.addleaf!(net_level1_s, net_level1_s.node[4], "S1C"); @test net_level1_s.edge[21].containRoot == false # check containRoot on edge 4 and exterior edges @test net_level1_s.edge[22].containRoot == false -@test PhyloNetworks.getChild(net_level1_s.edge[21]).name == "S1A" -@test PhyloNetworks.getChild(net_level1_s.edge[22]).name == "S1B" +@test PhyloNetworks.getchild(net_level1_s.edge[21]).name == "S1A" +@test PhyloNetworks.getchild(net_level1_s.edge[22]).name == "S1B" # test addleaf! on edge net_level1_s = readTopology(str_level1_s) PhyloNetworks.addleaf!(net_level1_s, net_level1_s.edge[4], "S1A"); diff --git a/test/test_phyLiNCoptimization.jl b/test/test_phyLiNCoptimization.jl index 12eaed3a..0309a088 100644 --- a/test/test_phyLiNCoptimization.jl +++ b/test/test_phyLiNCoptimization.jl @@ -32,7 +32,7 @@ e = PhyloNetworks.optimizelocalBL_LiNC!(obj, obj.net.edge[6], # ## Local Gamma γcache = PhyloNetworks.CacheGammaLiNC(obj) -hybridmajorparent = PhyloNetworks.getMajorParentEdge(obj.net.hybrid[1]) +hybridmajorparent = PhyloNetworks.getparentedge(obj.net.hybrid[1]) @test_nowarn PhyloNetworks.optimizelocalgammas_LiNC!(obj, hybridmajorparent, 1e-6, γcache) @test hybridmajorparent.gamma != 0.9 @test PhyloNetworks.getMinorParentEdge(obj.net.hybrid[1]).gamma != 0.1 @@ -88,7 +88,7 @@ lengthe = obj.net.edge[44].length γcache = PhyloNetworks.CacheGammaLiNC(obj) @test_nowarn PhyloNetworks.optimizelocalgammas_LiNC!(obj, obj.net.edge[4], 1e-6,γcache) @test obj.net.edge[4].gamma == 0.0 -@test PhyloNetworks.getMajorParentEdge(obj.net.hybrid[1]).gamma == 1.0 +@test PhyloNetworks.getparentedge(obj.net.hybrid[1]).gamma == 1.0 # gamma at a hybrid ladder: when some displayed trees don't have the focus edge # 2 unzipped reticulations in a hybrid ladder, reasonable (small) branch lengths @@ -142,7 +142,7 @@ for edge in net.edge # reset network setLength!(edge,1.0) end for h in net.hybrid - setGamma!(PhyloNetworks.getMajorParentEdge(h),0.6) + setGamma!(PhyloNetworks.getparentedge(h),0.6) end obj = (@test_logs (:warn, r"pruned") PhyloNetworks.StatisticalSubstitutionModel(net, fasta8sites, :JC69)) @test length(obj.net.leaf) == 22 @@ -164,7 +164,7 @@ netstr = "(#H2:0.1::0.2,((C:0.2,((B:0.3)#H1:0.4)#H2:0.5::0.8):0.6,(#H1:0.7,((A1: net = readTopology(netstr) # 2 reticulation in a hybrid ladder, and another isolated reticulation undoinfo = PhyloNetworks.unzip_canonical!(net) -@test all(PhyloNetworks.getChildEdge(h).length == 0.0 for h in net.hybrid) # unzipped +@test all(PhyloNetworks.getchildedge(h).length == 0.0 for h in net.hybrid) # unzipped @test writeTopology(net, round=true) == "(#H2:0.8::0.2,((C:0.2,((B:0.0)#H1:0.0)#H2:1.2::0.8):0.6,(#H1:1.0,((A1:0.0)#H3:0.81,(A2:0.9,#H3:0.82):0.03):1.0):1.1):1.2,O:1.3);" PhyloNetworks.rezip_canonical!(undoinfo...) @test writeTopology(net, round=true) == netstr @@ -313,7 +313,7 @@ net_level1_i.node[22].number = 100 PhyloNetworks.updateconstraints!(c_species, net_level1_i) @test c_species[1].taxonnums == Set([8,9,100]) @test c_species[1].node.number == 21 -@test PhyloNetworks.getParent(net_level1_i.node[22].edge[1]).number == 21 +@test PhyloNetworks.getparent(net_level1_i.node[22].edge[1]).number == 21 obj = PhyloNetworks.StatisticalSubstitutionModel(net_level1_i,fastaindiv,:JC69,:GI,2) # obj.net = deepcopy of input net, so we need to rebuild the constraints @@ -353,7 +353,7 @@ obj = PhyloNetworks.phyLiNC(net_level1_s, # missing BLs, so BLs are re-estimated # test that species stayed together after optimization, as the only polytomy function polytomyS1(node) length(node.edge) > 3 || return false - return Set(n.name for n in PhyloNetworks.getChildren(node)) == Set(["S1A", "S1B", "S1C"]) + return Set(n.name for n in PhyloNetworks.getchildren(node)) == Set(["S1A", "S1B", "S1C"]) end @test sum(polytomyS1(nod) for nod in obj.net.node) == 1 end From 082d04dbebf1a3869c854d16c2f78e02661fd808 Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Wed, 14 Dec 2022 15:38:51 -0600 Subject: [PATCH 3/9] isleaf, isexternal, getparentedgeminor, getroot, isrootof, isparentof, ischildof --- docs/src/lib/public.md | 9 +++- docs/src/man/netmanipulation.md | 10 +++-- src/PhyloNetworks.jl | 14 +++--- src/addHybrid_snaq.jl | 2 +- src/auxiliary.jl | 77 ++++++++++++++++++++++---------- src/compareNetworks.jl | 12 ++--- src/graph_components.jl | 2 +- src/manipulateNet.jl | 6 +-- src/moves_semidirected.jl | 10 ++--- src/phyLiNCoptimization.jl | 12 ++--- src/readwrite.jl | 2 +- test/test_addHybrid.jl | 4 +- test/test_manipulateNet.jl | 4 +- test/test_phyLiNCoptimization.jl | 2 +- 14 files changed, 104 insertions(+), 62 deletions(-) diff --git a/docs/src/lib/public.md b/docs/src/lib/public.md index d8a18f7d..1854c39e 100644 --- a/docs/src/lib/public.md +++ b/docs/src/lib/public.md @@ -28,8 +28,12 @@ Order = [:type] tipLabels printEdges printNodes -isparent -ischild +getroot +isrootof +isleaf +isexternal +isparentof +ischildof hassinglechild getchild getchildren @@ -38,6 +42,7 @@ getparent getparents getparentminor getparentedge +getparentedgeminor getpartner getNodeAges pairwiseTaxonDistanceMatrix diff --git a/docs/src/man/netmanipulation.md b/docs/src/man/netmanipulation.md index 8850d4ad..5d94eaa8 100644 --- a/docs/src/man/netmanipulation.md +++ b/docs/src/man/netmanipulation.md @@ -17,11 +17,13 @@ To traverse or learn something about a network, node or edge, see for example: - [`displayedTrees`](@ref), [`majorTree`](@ref), [`biconnectedComponents`](@ref), [`PhyloNetworks.blobInfo`](@ref) - [`hardwiredCluster`](@ref), [`hardwiredClusters`](@ref) -- [`isparent`](@ref), [`ischild`](@ref), [`hassinglechild`](@ref), - [`getpartner`](@ref), - [`getchild`](@ref), [`getchildren`](@ref), [`getchildedge`](@ref) +- [`getroot`](@ref), [`isrootof`](@ref), + [`isleaf`](@ref), [`isexternal`](@ref), [`isparentof`](@ref), [`ischildof`](@ref), + [`hassinglechild`](@ref), +- [`getchild`](@ref), [`getchildren`](@ref), [`getchildedge`](@ref) [`getparent`](@ref), [`getparents`](@ref), - [`getparentminor`](@ref), [`getparentedge`](@ref) + [`getparentminor`](@ref), [`getparentedge`](@ref), [`getparentedgeminor`](@ref), + [`getpartner`](@ref) To modify a network, for example: - [`rootonedge!`](@ref), [`rootatnode!`](@ref): diff --git a/src/PhyloNetworks.jl b/src/PhyloNetworks.jl index 70c366dd..4c82b755 100644 --- a/src/PhyloNetworks.jl +++ b/src/PhyloNetworks.jl @@ -72,11 +72,14 @@ module PhyloNetworks topologyMaxQPseudolik!, topologyQPseudolik!, ## getters - # getMinorParentEdge. fixit: add isleaf, isroot - # functions above: rename them before exporting, like: - # parent child parents children parentmajor parentminor ancestor sibling offspring - isparent, - ischild, + # fixit: add isroot, getpartneredge + # ancestors sibling offspring + getroot, + isrootof, + isleaf, + isexternal, + isparentof, + ischildof, hassinglechild, getchild, getchildren, @@ -85,6 +88,7 @@ module PhyloNetworks getparents, getparentminor, getparentedge, + getparentedgeminor, getpartner, ## Network Manipulation rootatnode!, diff --git a/src/addHybrid_snaq.jl b/src/addHybrid_snaq.jl index 9ac50593..469f0e9c 100644 --- a/src/addHybrid_snaq.jl +++ b/src/addHybrid_snaq.jl @@ -436,7 +436,7 @@ function addHybridBetweenClades!(hybnum::Number,sisnum::Number,net::HybridNetwor ## used gamma=0.1 to make the new edge a minor edge, but we really do not have gamma value: emaj = getparentedge(hybridnode) emaj.gamma = -1 - e = getMinorParentEdge(hybridnode) + e = getparentedgeminor(hybridnode) e.gamma = -1 return e.number end diff --git a/src/auxiliary.jl b/src/auxiliary.jl index 24e5fd3a..f19064af 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -148,22 +148,53 @@ function setNode!(edge::Edge,node::Array{Node,1}) end """ - isparent(node, edge) - ischild(node, edge) + getroot(net) -True if `node` is the tail / head, or parent / child, of `edge`; false otherwise. +Node used to root `net`. If `net` is to be considered as semi-directed or +unrooted, this root node is used to write the networks' Newick parenthetical +description or for network traversals. +""" +getroot(net::HybridNetwork) = net.node[net.root] + +""" + isrootof(node, net) + +`true` if `node` is the root of `net` (or used as such for network traversals +in case the network is considered as semi-directed); `false` otherwise. +""" +isrootof(node::Node, net::HybridNetwork) = node === getroot(net) + +""" + isleaf(node) + +`true` if `node` is a leaf, `false` otherwise. +""" +isleaf(node::Node) = node.leaf + +""" + isexternal(edge) + +`true` if `edge` is adjacent to a leaf, `false` otherwise. +""" +isexternal(edge::Edge) = any(isleaf.(edge.node)) + +""" + isparentof(node, edge) + ischildof(node, edge) + +`true` if `node` is the tail / head, or parent / child, of `edge`; `false` otherwise. Assumes that the edge's direction is correct, meaning it's field `isChild1` is reliable (in sync with the rooting). """ -isparent(node::Node, edge::Edge) = node === getparent(edge) -@doc (@doc isparent) ischild -ischild( node::Node, edge::Edge) = node === getchild(edge) +isparentof(node::Node, edge::Edge) = node === getparent(edge) +@doc (@doc isparentof) ischildof +ischildof( node::Node, edge::Edge) = node === getchild(edge) """ hassinglechild(node) -Boolean: `true` if `node` has a single child (child edge or child node, -which are equivalent), based on the edges `isChild1` field. +`true` if `node` has a single child, based on the edges `isChild1` field; +`false` otherwise. """ hassinglechild(node::Node) = sum(e -> getparent(e) === node, node.edge) == 1 @@ -189,7 +220,7 @@ To get all parent *nodes*: see [`getparents`](@ref PhyloNetworks.getparents). function getchildren(node::Node) children = Node[] for e in node.edge - if isparent(node, e) + if isparentof(node, e) push!(children, getchild(e)) end end @@ -202,7 +233,7 @@ end Single child edge of `node`. Checks that it's a single child. """ function getchildedge(node::Node) - ce_ind = findall(e -> isparent(node, e), node.edge) + ce_ind = findall(e -> isparentof(node, e), node.edge) length(ce_ind) == 1 || error("node number $(node.number) has $(length(ce_ind)) children instead of 1 child") return node.edge[ce_ind[1]] end @@ -219,7 +250,7 @@ See also: [`getparents`](@ref) [`getparentminor`](@ref). getparent(edge::Edge) = edge.node[edge.isChild1 ? 2 : 1] @inline function getparent(node::Node) for e in node.edge - if e.isMajor && ischild(node, e) + if e.isMajor && ischildof(node, e) return getparent(e) end end @@ -231,7 +262,7 @@ end Minor parent node of `node` using the `isChild1` field of edges (and assuming correct `isMajor` field). -See also [`getparentedge`](@ref) and [`getMinorParentEdge`](@ref). +See also [`getparentedge`](@ref) and [`getparentedgeminor`](@ref). """ @inline function getparentminor(node::Node) for e in node.edge @@ -249,12 +280,12 @@ Vector of all parent nodes of `node`, based on `isChild1` field (for edges). See also: [`getparent`](@ref) to get the (major) parent node, [`getparentedge`](@ref) for the (major) parent edge and -[`getMinorParentEdge`](@ref). +[`getparentedgeminor`](@ref). """ @inline function getparents(node::Node) parents = Node[] for e in node.edge - if ischild(node, e) + if ischildof(node, e) push!(parents, getparent(e)) end end @@ -263,7 +294,7 @@ end """ getparentedge(node) - getMinorParentEdge(node) + getparentedgeminor(node) return the parent edge of `node`: the major / minor if hybrid. **warning**: assume isChild1 and isMajor attributes are correct @@ -272,14 +303,14 @@ To get all parent *nodes*: see [`getparents`](@ref). """ @inline function getparentedge(n::Node) for ee in n.edge - if ee.isMajor && ischild(n,ee) + if ee.isMajor && ischildof(n,ee) return ee end end error("node $(n.number) has no major parent") end -@doc (@doc getparentedge) getMinorParentEdge -@inline function getMinorParentEdge(n::Node) +@doc (@doc getparentedge) getparentedgeminor +@inline function getparentedgeminor(n::Node) for ee in n.edge if !ee.isMajor && n == ee.node[(ee.isChild1 ? 1 : 2)] return ee @@ -444,7 +475,7 @@ function getIndexHybrid(node::Node, net::Network) end # function that given a hybrid node, it gives you the minor hybrid edge -# warning: assumes level-1 network: see getMinorParentEdge for a general network +# warning: assumes level-1 network: see getparentedgeminor for a general network function getHybridEdge(node::Node) node.hybrid || error("node $(node.number) is not hybrid node, cannot get hybrid edges") a = nothing; @@ -1532,7 +1563,7 @@ This makes the network not treechild, assuming it is fully resolved. """ function hashybridladder(net::HybridNetwork) for h in net.hybrid - if any(n.hybrid for n in getParents(h)) + if any(n.hybrid for n in getparents(h)) return true end end @@ -1560,7 +1591,7 @@ function shrinkedge!(net::HybridNetwork, edge2shrink::Edge) cn = getchild(edge2shrink) cn.hybrid && error("cannot shrink tree edge number $(edge2shrink.number): its child node is a hybrid. run directEdges! ?") pn = getparent(edge2shrink) - (cn.leaf || pn.leaf) && + isexternal(edge2shrink) && # (isleaf(cn) || isleaf(pn)) && error("won't shrink edge number $(edge2shrink.number): it is incident to a leaf") removeEdge!(pn,edge2shrink) empty!(edge2shrink.node) # should help gc @@ -1616,7 +1647,7 @@ function shrink2cycles!(net::HybridNetwork, unroot=false::Bool) ih = nh # hybrids deleted from the end while ih > 0 h = net.hybrid[ih] - minor = getMinorParentEdge(h) + minor = getparentedgeminor(h) major = getparentedge(h) pmin = getparent(minor) # minor parent node pmaj = getparent(major) # major parent node @@ -1676,7 +1707,7 @@ function shrink3cycles!(net::HybridNetwork, unroot=false::Bool) ih = nh # hybrids deleted from the end while ih > 0 h = net.hybrid[ih] - minor = getMinorParentEdge(h) + minor = getparentedgeminor(h) major = getparentedge(h) pmin = getparent(minor) # minor parent node pmaj = getparent(major) # major parent node diff --git a/src/compareNetworks.jl b/src/compareNetworks.jl index b5440d62..bdd52d18 100644 --- a/src/compareNetworks.jl +++ b/src/compareNetworks.jl @@ -42,7 +42,7 @@ function tree2Matrix(T::HybridNetwork, S::Union{Vector{String},Vector{Int}}; roo ie = [1] # index of next edge to be documented: row index in M for e in T.node[T.root].edge child = getOtherNode(e,T.node[T.root]) - if (!child.leaf) + if !isleaf(child) traverseTree2Matrix!(T.node[T.root],e,ie,M,S) end end @@ -249,7 +249,7 @@ function descendants!(des::Vector{Int}, visited::Vector{Int}, edge::Edge, intern push!(des, n.number) end for ce in n.edge - if isparent(n, ce) + if isparentof(n, ce) descendants!(des, visited, ce, internal) end end @@ -285,7 +285,7 @@ function isdescendant!(visited::Vector{Int}, des::Node, e::Edge) push!(visited, n.number) end for ce in n.edge - if isparent(n, ce) + if isparentof(n, ce) if isdescendant!(visited, des, ce) return true; end end end @@ -476,7 +476,7 @@ function deleteHybridThreshold!(net::HybridNetwork, gamma::Float64, for i = net.numHybrids:-1:1 # starting from last because net.hybrid changes as hybrids are removed. Empty range if 0 hybrids. i > lastindex(net.hybrid) && continue # removing 1 hybrid could remove several, if non-tree child net - e = getMinorParentEdge(net.hybrid[i]) + e = getparentedgeminor(net.hybrid[i]) # remove minor edge e if γ < threshold OR threshold=0.5 # warning: no check if γ and isMajor are in conflict if e.gamma < gamma || gamma == 0.5 # note: γ=-1 if missing, so < gamma threshold @@ -509,7 +509,7 @@ function displayedNetworks!(net::HybridNetwork, node::Node, ind = findfirst(x -> x===node, net.node) ind !== nothing || error("node $(node.number) was not found in net") netmin = deepcopy(net) - emin = getMinorParentEdge(node) + emin = getparentedgeminor(node) deletehybridedge!(net , emin, nofuse, unroot, multgammas, true, keeporiginalroot) emaj = getparentedge(netmin.node[ind]) # hybrid node & edge in netmin deletehybridedge!(netmin, emaj, nofuse, unroot, multgammas, true, keeporiginalroot) @@ -666,7 +666,7 @@ function displayedNetworkAt!(net::HybridNetwork, node::Node, for i = net.numHybrids:-1:1 # starting from last because net.hybrid changes as hybrids are removed. Empty range if 0 hybrids. net.hybrid[i] != node || continue - emin = getMinorParentEdge(net.hybrid[i]) + emin = getparentedgeminor(net.hybrid[i]) deletehybridedge!(net, emin, nofuse, unroot, multgammas) end end diff --git a/src/graph_components.jl b/src/graph_components.jl index 29b77b1d..674968eb 100644 --- a/src/graph_components.jl +++ b/src/graph_components.jl @@ -239,7 +239,7 @@ function blobInfo(net, ignoreTrivial=true::Bool; push!(bccMinor, bccmi) end # add the network root, if it was in a trivial bi-component (no hybrids) - rootnode = net.node[net.root] + rootnode = getroot(net) if !any(n -> n === rootnode, bccRoots) push!(bccRoots, rootnode) push!(bccMajor, Edge[]) diff --git a/src/manipulateNet.jl b/src/manipulateNet.jl index 24fb1041..2e7d848f 100644 --- a/src/manipulateNet.jl +++ b/src/manipulateNet.jl @@ -535,10 +535,10 @@ julia> writeTopology(net, round=true) # the root was kept ``` """ function removedegree2nodes!(net::HybridNetwork, keeproot=false::Bool) - rootnode = net.node[net.root] + rootnode = getroot(net) # caution: the root and its incident edges may change when degree-2 nodes # are removed. Indices of nodes to be removed would change too. - rootin2cycle(nn) = nn ≡ net.node[net.root] && all(e.hybrid for e in nn.edge) + rootin2cycle(nn) = isrootof(nn,net) && all(e.hybrid for e in nn.edge) toberemoved(nn) = (keeproot ? length(nn.edge) == 2 && nn !== rootnode : length(nn.edge) == 2 && !rootin2cycle(nn)) ndegree2nodes = sum(toberemoved.(net.node)) @@ -596,7 +596,7 @@ function addleaf!(net::HybridNetwork, speciesnode::Node, leafname::String, edgel exterioredge = Edge(maximum(e.number for e in net.edge) + 1, edgelength) # isChild1 = true by default in edge creation pushEdge!(net, exterioredge) setEdge!(speciesnode, exterioredge) - if speciesnode.hybrid || (speciesnode != net.node[net.root] && !getparentedge(speciesnode).containRoot) + if speciesnode.hybrid || (!isrootof(speciesnode, net) && !getparentedge(speciesnode).containRoot) exterioredge.containRoot = false end newleaf = Node(maximum(n.number for n in net.node) + 1, true, false, [exterioredge]) # Node(number, leaf, hybrid, edge array) diff --git a/src/moves_semidirected.jl b/src/moves_semidirected.jl index c250a570..a8e9f729 100644 --- a/src/moves_semidirected.jl +++ b/src/moves_semidirected.jl @@ -411,7 +411,7 @@ function nni!(net::HybridNetwork, uv::Edge, nummove::UInt8, # α = u's major parent if it exists, β = u's last child or minor parent if u.hybrid αu = getparentedge(u) - βu = getMinorParentEdge(u) + βu = getparentedgeminor(u) α = getparent(αu) β = getparent(βu) else # u may not have any parent, e.g. if root node @@ -869,7 +869,7 @@ function moveroot!(net::HybridNetwork, constraints=TopologyConstraint[]::Vector{ for newrooti in newrootrandomorder newrooti != oldroot || continue newrootnode = net.node[newrooti] - newrootnode.leaf && continue # try next potential new root if current is a leaf + isleaf(newrootnode) && continue # try next potential new root if current is a leaf # Check the new root is NOT at the top or inside contraint clade or within pecies newrootfound = true for con in constraints @@ -985,8 +985,8 @@ function fliphybrid!(net::HybridNetwork, hybridnode::Node, minor=true::Bool, =# runDirectEdges = false edgetoflip, edgetokeep = minor ? - (getMinorParentEdge(hybridnode), getparentedge(hybridnode)) : - (getparentedge(hybridnode), getMinorParentEdge(hybridnode)) + (getparentedgeminor(hybridnode), getparentedge(hybridnode)) : + (getparentedge(hybridnode), getparentedgeminor(hybridnode)) oldchildedge = getchildedge(hybridnode) newhybridnode = getparent(edgetoflip) if newhybridnode.hybrid # already has 2 parents: cannot had a third. @@ -1006,7 +1006,7 @@ function fliphybrid!(net::HybridNetwork, hybridnode::Node, minor=true::Bool, =# if e !== edgetoflip # e cannot be hybrid --e-> nhn because earlier check neibr = getOtherNode(e, newhybridnode) # neighbor of new hybrid node via e - if !neibr.leaf && (p2 === neibr || + if !isleaf(neibr) && (p2 === neibr || isdescendant_undirected(p2, neibr, e)) isp2desc = true end diff --git a/src/phyLiNCoptimization.jl b/src/phyLiNCoptimization.jl index b5fcf849..66204cf4 100644 --- a/src/phyLiNCoptimization.jl +++ b/src/phyLiNCoptimization.jl @@ -493,7 +493,7 @@ function phyLiNCone!(obj::SSM, maxhybrid::Int, no3cycle::Bool, end ghosthybrid = false # find hybrid edges with γ=0, to delete them for h in obj.net.hybrid - minorhybridedge = getMinorParentEdge(h) + minorhybridedge = getparentedgeminor(h) minorhybridedge.gamma == 0.0 || continue ghosthybrid = true deletehybridedge!(obj.net, minorhybridedge, false,true,false,false,false) @@ -827,7 +827,7 @@ function addhybridedgeLiNC!(obj::SSM, currLik::Float64, return false elseif newhybridedge.gamma == 1.0 # ≃ subtree prune and regraft (SPR) move # loglik better because γ=1 better than γ=0, yet without new reticulation: accept - deletehybridedge!(obj.net, getMinorParentEdge(newhybridnode), false,true,false,false,false) + deletehybridedge!(obj.net, getparentedgeminor(newhybridnode), false,true,false,false,false) (no3cycle ? shrink3cycles!(obj.net, true) : shrink2cycles!(obj.net, true)) # loglik will be updated in optimizeallgammas right after, in optimizestructure updateSSM!(obj, true; constraints=constraints) @@ -887,7 +887,7 @@ function deletehybridedgeLiNC!(obj::SSM, currLik::Float64, nh = length(obj.net.hybrid) hybridnode = obj.net.hybrid[Random.rand(1:nh)] - minorhybridedge = getMinorParentEdge(hybridnode) + minorhybridedge = getparentedgeminor(hybridnode) #= if type-3 constraints: check that proposed deletion meets constraints the constraint's stem edge must be a tree edge -> not disrupted species (type 1) or clade type-2 constraints: no problem, because @@ -898,7 +898,7 @@ function deletehybridedgeLiNC!(obj::SSM, currLik::Float64, edgenotfound = true for hi in hybindices hybridnode = obj.net.hybrid[hi] - minorhybridedge = getMinorParentEdge(hybridnode) + minorhybridedge = getparentedgeminor(hybridnode) # edgenotfound = whether any type-3 constraints is violated edgenotfound || break end @@ -1575,7 +1575,7 @@ function optimizeallgammas_LiNC!(obj::SSM, ftolAbs::Float64, hybnodes = obj.net.hybrid nh = length(hybnodes) # also = obj.net.numHybrids if nh==0 return false; end # no gammas to optimize - hybs = [getMinorParentEdge(h) for h in hybnodes] + hybs = [getparentedgeminor(h) for h in hybnodes] discrete_corelikelihood!(obj) # prerequisite for optimizegamma_LiNC! nevals = 0 ll = obj.loglik @@ -1591,7 +1591,7 @@ function optimizeallgammas_LiNC!(obj::SSM, ftolAbs::Float64, ghosthybrid = false hi = nh while hi > 0 - he = getMinorParentEdge(hybnodes[hi]) + he = getparentedgeminor(hybnodes[hi]) if he.gamma == 0.0 deletehybridedge!(obj.net, he, false,true,false,false,false) ghosthybrid = true diff --git a/src/readwrite.jl b/src/readwrite.jl index 0dda1f8e..247eb5f1 100644 --- a/src/readwrite.jl +++ b/src/readwrite.jl @@ -984,7 +984,7 @@ Use `internallabel=false` to suppress the labels of internal nodes. """ function writeSubTree!(s::IO, net::HybridNetwork, di::Bool, namelabel::Bool, roundBL::Bool, digits::Integer, internallabel::Bool) - rootnode = net.node[net.root] + rootnode = getroot(net) if net.numNodes > 1 print(s,"(") degree = length(rootnode.edge) diff --git a/test/test_addHybrid.jl b/test/test_addHybrid.jl index 1b968ffd..9849835a 100644 --- a/test/test_addHybrid.jl +++ b/test/test_addHybrid.jl @@ -25,7 +25,7 @@ netl1 = readTopology(str_level1) newhybridnode, newhybridedge = PhyloNetworks.addhybridedge!(netl1, false, true) @test !isnothing(newhybridnode) @test netl1.numHybrids == 3 -PhyloNetworks.deletehybridedge!(netl1, PhyloNetworks.getMinorParentEdge(newhybridnode)) +PhyloNetworks.deletehybridedge!(netl1, PhyloNetworks.getparentedgeminor(newhybridnode)) @test hardwiredClusterDistance(netl1, readTopology(str_level1), true) == 0 end # of addhybridedge! top function @@ -36,7 +36,7 @@ netl1 = readTopology(str_level1) newhybridnode, newhybridedge = PhyloNetworks.addhybridedge!(netl1, netl1.edge[3], netl1.edge[9], true, 0.0, 0.2) @test newhybridnode.hybrid @test PhyloNetworks.getparentedge(newhybridnode).gamma == 0.8 -@test PhyloNetworks.getMinorParentEdge(newhybridnode).gamma == 0.2 +@test PhyloNetworks.getparentedgeminor(newhybridnode).gamma == 0.2 netl1 = readTopology(str_level1); @test !isnothing(PhyloNetworks.addhybridedge!(netl1, netl1.edge[15], netl1.edge[3], true)) @test writeTopology(netl1) == "(((((((S1,S4),(S5)#H1),(#H1,(S6,S7))),#H3))#H2,((S8,S9))#H3),(#H2,S10));" diff --git a/test/test_manipulateNet.jl b/test/test_manipulateNet.jl index f6fc9548..c82236d4 100644 --- a/test/test_manipulateNet.jl +++ b/test/test_manipulateNet.jl @@ -42,9 +42,9 @@ close(s); @test PhyloNetworks.getparentminor(net.node[3]).number == 6 @test PhyloNetworks.getparent(net.node[3]).number == 10 @test PhyloNetworks.getparentedge(net.node[6]).number == 7 -@test_throws ErrorException PhyloNetworks.getMinorParentEdge(net.node[6]) +@test_throws ErrorException PhyloNetworks.getparentedgeminor(net.node[6]) @test PhyloNetworks.getparentedge(net.node[2]).number == 2 -@test PhyloNetworks.getMinorParentEdge(net.node[2]).number == 8 +@test PhyloNetworks.getparentedgeminor(net.node[2]).number == 8 @test [n.number for n in PhyloNetworks.getchildren(net.node[4])] == [] # leaf @test [n.number for n in PhyloNetworks.getchildren(net.node[2])] == [1] # hybrid node @test [n.number for n in PhyloNetworks.getchildren(net.node[9])] == [6,8] # tree node diff --git a/test/test_phyLiNCoptimization.jl b/test/test_phyLiNCoptimization.jl index 0309a088..a432d38a 100644 --- a/test/test_phyLiNCoptimization.jl +++ b/test/test_phyLiNCoptimization.jl @@ -35,7 +35,7 @@ e = PhyloNetworks.optimizelocalBL_LiNC!(obj, obj.net.edge[6], hybridmajorparent = PhyloNetworks.getparentedge(obj.net.hybrid[1]) @test_nowarn PhyloNetworks.optimizelocalgammas_LiNC!(obj, hybridmajorparent, 1e-6, γcache) @test hybridmajorparent.gamma != 0.9 -@test PhyloNetworks.getMinorParentEdge(obj.net.hybrid[1]).gamma != 0.1 +@test PhyloNetworks.getparentedgeminor(obj.net.hybrid[1]).gamma != 0.1 end @testset "optimize local BL & gammas, complex network and 8 sites" begin From 432a9fab7bbab5c539d494efe12543232058739b Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Wed, 14 Dec 2022 19:33:21 -0600 Subject: [PATCH 4/9] deprecations, getpartner -> getpartneredge --- docs/src/lib/public.md | 2 +- docs/src/man/netmanipulation.md | 2 +- src/PhyloNetworks.jl | 5 ++--- src/auxiliary.jl | 21 ++++++++++----------- src/deleteHybrid.jl | 2 +- src/deprecated.jl | 10 ++++++++++ src/graph_components.jl | 2 +- src/manipulateNet.jl | 4 ++-- src/phyLiNCoptimization.jl | 4 ++-- 9 files changed, 30 insertions(+), 22 deletions(-) diff --git a/docs/src/lib/public.md b/docs/src/lib/public.md index 1854c39e..af6375a3 100644 --- a/docs/src/lib/public.md +++ b/docs/src/lib/public.md @@ -43,7 +43,7 @@ getparents getparentminor getparentedge getparentedgeminor -getpartner +getpartneredge getNodeAges pairwiseTaxonDistanceMatrix ``` diff --git a/docs/src/man/netmanipulation.md b/docs/src/man/netmanipulation.md index 5d94eaa8..3a33432b 100644 --- a/docs/src/man/netmanipulation.md +++ b/docs/src/man/netmanipulation.md @@ -23,7 +23,7 @@ To traverse or learn something about a network, node or edge, see for example: - [`getchild`](@ref), [`getchildren`](@ref), [`getchildedge`](@ref) [`getparent`](@ref), [`getparents`](@ref), [`getparentminor`](@ref), [`getparentedge`](@ref), [`getparentedgeminor`](@ref), - [`getpartner`](@ref) + [`getpartneredge`](@ref) To modify a network, for example: - [`rootonedge!`](@ref), [`rootatnode!`](@ref): diff --git a/src/PhyloNetworks.jl b/src/PhyloNetworks.jl index 4c82b755..3dcd9eff 100644 --- a/src/PhyloNetworks.jl +++ b/src/PhyloNetworks.jl @@ -72,8 +72,7 @@ module PhyloNetworks topologyMaxQPseudolik!, topologyQPseudolik!, ## getters - # fixit: add isroot, getpartneredge - # ancestors sibling offspring + # fixit: add ancestors? getsibling? getdescendants (currently descendants)? getroot, isrootof, isleaf, @@ -89,7 +88,7 @@ module PhyloNetworks getparentminor, getparentedge, getparentedgeminor, - getpartner, + getpartneredge, ## Network Manipulation rootatnode!, rootonedge!, diff --git a/src/auxiliary.jl b/src/auxiliary.jl index f19064af..91ca639d 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -320,23 +320,22 @@ end end """ - getpartner(edge::Edge) - getpartner(edge::Edge, node::Node) + getpartneredge(edge::Edge) + getpartneredge(edge::Edge, node::Node) -Return hybrid partner of edge, that is, hybrid edge pointing to the same -child as `edge`. Assumptions (not checked): +Edge that is the hybrid partner of `edge`, meaning that is has the same child +`node` as `edge`. This child `node` is given as an argument in the second version. +Assumptions, not checked: -- correct `isChild1` field for `edge` and for hybrid edges - no in-coming polytomy: a node has 0, 1 or 2 parents, no more - -When `node` is given, it is assumed to be the child of `edge` -(the first form calls the second). +- when `node` is given, it is assumed to be the child of `edge` + (the first method calls the second). """ -@inline function getpartner(edge) +@inline function getpartneredge(edge) node = getchild(edge) - getpartner(edge, node) + getpartneredge(edge, node) end -@inline function getpartner(edge::Edge, node::Node) +@inline function getpartneredge(edge::Edge, node::Node) for e in node.edge if e.hybrid && e !== edge && node === getchild(e) return e diff --git a/src/deleteHybrid.jl b/src/deleteHybrid.jl index 6c6ce1cf..50b860fe 100644 --- a/src/deleteHybrid.jl +++ b/src/deleteHybrid.jl @@ -395,7 +395,7 @@ function deletehybridedge!(net::HybridNetwork, edge::Edge, # below: we will need to delete n1 recursively (hence edge) else # n1 has 4+ edges (polytomy) or 3 edges but we want to keep it anyway: # keep n1 but detach it from 'edge', set its remaining parent to major tree edge - pe = getpartner(edge, n1) # partner edge: keep it this time + pe = getpartneredge(edge, n1) # partner edge: keep it this time if !pe.isMajor pe.isMajor=true; end pe.hybrid = false # note: pe.gamma *not* set to 1.0 here diff --git a/src/deprecated.jl b/src/deprecated.jl index 9adcb38d..afa7a7e1 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -1,3 +1,13 @@ @deprecate phyloNetworklm phylolm @deprecate sigma2_estim sigma2_phylo @deprecate mu_estim mu_phylo +@deprecate getChild getchild false +@deprecate getChildren getchildren false +@deprecate getChildEdge getchildedge false +@deprecate getParents getparents false +@deprecate getParent getparent false +@deprecate getMajorParent getparent false +@deprecate getMinorParent getparentminor false +@deprecate getMajorParentEdge getparentedge false +@deprecate getMinorParentEdge getparentedgeminor false +@deprecate getPartner getpartneredge false diff --git a/src/graph_components.jl b/src/graph_components.jl index 674968eb..0e38044a 100644 --- a/src/graph_components.jl +++ b/src/graph_components.jl @@ -230,7 +230,7 @@ function blobInfo(net, ignoreTrivial=true::Bool; for edge in bicomp if edge.hybrid && edge.isMajor push!(bccMa, edge) - e = getpartner(edge) + e = getpartneredge(edge) !e.isMajor || @warn "major edge $(edge.number) has a major partner: edge $(e.number)" push!(bccmi, e) end diff --git a/src/manipulateNet.jl b/src/manipulateNet.jl index 2e7d848f..48bb2714 100644 --- a/src/manipulateNet.jl +++ b/src/manipulateNet.jl @@ -737,7 +737,7 @@ function preorder!(net::HybridNetwork) push!(queue,other) # print("queuing: "); @show other.number else - e2 = getpartner(e, other) + e2 = getpartneredge(e, other) parent = getparent(e2) if net.visited[findfirst(x -> x===parent, net.node)] push!(queue,other) @@ -1020,7 +1020,7 @@ function deleteleaf!(net::HybridNetwork, nodeNumber::Integer; e1 = fuseedgesat!(i,net, multgammas) # fused edge if simplify && e1.hybrid # check for 2-cycle at new hybrid edge cn = getchild(e1) - e2 = getpartner(e1, cn) # companion hybrid edge + e2 = getpartneredge(e1, cn) # companion hybrid edge pn = getparent(e1) if pn ≡ getparent(e2) # e1 and e2 have same child and same parent. Remove e1. diff --git a/src/phyLiNCoptimization.jl b/src/phyLiNCoptimization.jl index 66204cf4..ec422160 100644 --- a/src/phyLiNCoptimization.jl +++ b/src/phyLiNCoptimization.jl @@ -1659,7 +1659,7 @@ function optimizelocalgammas_LiNC!(obj::SSM, edge::Edge, for i in length(neighborhybs):-1:1 e = neighborhybs[i] e.isMajor || continue # skip below for minor edges - p = getpartner(e) # minor partner + p = getpartneredge(e) # minor partner j = findfirst(x -> x===p, neighborhybs) if isnothing(j) neighborhybs[i] = p # replace major e by its minor partner @@ -1711,7 +1711,7 @@ function optimizegamma_LiNC!(obj::SSM, focusedge::Edge, ftolAbs::Float64, cache::CacheGammaLiNC, maxNR=10::Int) ## step 1: prepare vectors constant during the search edgenum = focusedge.number - partner = getpartner(focusedge) + partner = getpartneredge(focusedge) partnernum = partner.number clike = cache.clike # conditional likelihood under focus edge clikp = cache.clikp # conditional likelihood under partner edge From e375987416e9cefaff2f0579ae3bd5bd991c4281 Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Wed, 14 Dec 2022 21:09:17 -0600 Subject: [PATCH 5/9] doc: new section to list utilities --- docs/make.jl | 2 +- docs/src/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index eae15921..88a404ce 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -16,7 +16,7 @@ makedocs( "Home" => "index.md", "Manual" => [ "Installation" => "man/installation.md", - #"Network manipulation" => "man/netmanipulation.md", + "Network manipulation" => "man/netmanipulation.md", "Input Data for SNaQ" => "man/inputdata.md", "TICR pipeline" => "man/ticr_howtogetQuartetCFs.md", "Network estimation and display" => "man/snaq_plot.md", diff --git a/docs/src/index.md b/docs/src/index.md index 0759149c..920bec01 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -55,7 +55,7 @@ for network inference: ```@contents Pages = [ "man/installation.md", - # "man/netmanipulation.md", + "man/netmanipulation.md", "man/inputdata.md", "man/ticr_howtogetQuartetCFs.md", "man/snaq_plot.md", From 6e54c51a5aa9db9495ace480803b5cb4f6365f87 Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Wed, 14 Dec 2022 21:45:40 -0600 Subject: [PATCH 6/9] fix jldoctest --- src/addHybrid.jl | 4 ++-- src/manipulateNet.jl | 10 +++++----- src/moves_semidirected.jl | 2 +- src/types.jl | 8 +++++--- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/addHybrid.jl b/src/addHybrid.jl index 9b0899b8..e1a0b02f 100644 --- a/src/addHybrid.jl +++ b/src/addHybrid.jl @@ -48,7 +48,7 @@ julia> PhyloNetworks.addhybridedge!(net, true, true) name:H3 hybrid node attached to 3 edges, numbered: 5 16 17 -, PhyloNetworks.Edge: +, PhyloNetworks.EdgeT{PhyloNetworks.Node}: number:17 length:0.01 minor hybrid edge with gamma=0.32771460911632916 @@ -151,7 +151,7 @@ julia> hybnode, hybedge = PhyloNetworks.addhybridedge!(net, net.edge[13], net.ed name:H3 hybrid node attached to 3 edges, numbered: 8 16 17 -, PhyloNetworks.Edge: +, PhyloNetworks.EdgeT{PhyloNetworks.Node}: number:17 length:0.0 minor hybrid edge with gamma=0.2 diff --git a/src/manipulateNet.jl b/src/manipulateNet.jl index 48bb2714..e7c1feab 100644 --- a/src/manipulateNet.jl +++ b/src/manipulateNet.jl @@ -148,7 +148,7 @@ which must in the same cycle. `net` is assumed to be of level 1, but **no checks** are made and fields are supposed up-to-date. Called by `hybridatnode!(net, node number)`, which is itself -called by [`undirectedOtherNetworks`](@ref). +called by [`undirectedOtherNetworks`](@ref PhyloNetworks.undirectedOtherNetworks). """ function hybridatnode!(net::HybridNetwork, hybrid::Node, newNode::Node) hybrid.hybrid || error("node $(hybrid.number) should be hybrid, but it is not") @@ -383,7 +383,7 @@ julia> length(net.node) 19 julia> net.edge[4] # edge 4 goes from node -8 to 3 -PhyloNetworks.Edge: +PhyloNetworks.EdgeT{PhyloNetworks.Node}: number:4 length:-1.0 attached to 2 node(s) (parent first): -8 3 @@ -395,14 +395,14 @@ julia> length(net.node) # one more than before 20 julia> newedge # new edge 21 goes from node -8 and 11 (new) -PhyloNetworks.Edge: +PhyloNetworks.EdgeT{PhyloNetworks.Node}: number:21 length:-1.0 attached to 2 node(s) (parent first): -8 11 julia> net.edge[4] # original edge 4 now goes from node 11 (new) to 3 -PhyloNetworks.Edge: +PhyloNetworks.EdgeT{PhyloNetworks.Node}: number:4 length:-1.0 attached to 2 node(s) (parent first): 11 3 @@ -1283,7 +1283,7 @@ end """ unzipat_canonical!(hyb::Node, childedge::Edge) -Unzip the reticulation a node `hyb`. See [`unzip_canonical!`](ref). +Unzip the reticulation a node `hyb`. See [`unzip_canonical!`](@ref PhyloNetworks.unzip_canonical!). Warning: no check that `hyb` has a single child. Output: constrained edge (child of `hyb`) and its original length. diff --git a/src/moves_semidirected.jl b/src/moves_semidirected.jl index a8e9f729..fa9f0397 100644 --- a/src/moves_semidirected.jl +++ b/src/moves_semidirected.jl @@ -763,7 +763,7 @@ S1,S1A S1,S1B S1,S1C -julia> individual_net, species_constraints = mapindividuals(species_net, filename); +julia> individual_net, species_constraints = PhyloNetworks.mapindividuals(species_net, filename); julia> writeTopology(individual_net, internallabel=true) "(((S8,S9),(((((S1A,S1B,S1C)S1,S4),(S5)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" diff --git a/src/types.jl b/src/types.jl index 2c6aeadc..99117424 100644 --- a/src/types.jl +++ b/src/types.jl @@ -6,13 +6,15 @@ Abstract node. An object of type [`EdgeT`](@ref) has a `node` attribute, which is an vector of 2 objects of some subtype of `ANode`. The concrete type [`Node`](@ref) is a subtype of `ANode`, -and has an `edge` attribute, which is vector of [`Edge`](@ref) objects +and has an `edge` attribute, which is vector of [`Edge`](@ref PhyloNetworks.EdgeT) objects (where Edge is an alias for EdgeT{Node}). """ abstract type ANode end """ - Edge(number) + EdgeT{node type} + Edge = EdgeT{Node} + Edge(number, length=1.0) Data structure for an edge and its various attributes. Most notably: - `number` (integer): serves as unique identifier; @@ -88,7 +90,7 @@ Data structure for a node and its various attributes. Most notably: - `leaf` (boolean): whether the node is a leaf (with data typically) or an internal node (no data typically) - `name` (string): taxon name for leaves; internal node may or may not have a name -- `edge`: vector of [`Edge`](@ref)s that the node is attached to; +- `edge`: vector of [`Edge`](@ref PhyloNetworks.EdgeT)s that the node is attached to; 1 if the node is a leaf, 2 if the node is the root, 3 otherwise, and potentially more if the node has a polytomy - `hybrid` (boolean): whether the node is a hybrid node (with 2 or more parents) From 3d1a6a2214e40f9f67a6eeb6157ac1fdb167d515 Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Sat, 14 Jan 2023 16:10:42 -0600 Subject: [PATCH 7/9] consolidated docstrings (-7 of them); new tests for better coverage --- docs/src/lib/public.md | 18 ++--- docs/src/man/netmanipulation.md | 12 ++-- src/auxiliary.jl | 120 +++++++++++++++++--------------- src/manipulateNet.jl | 2 +- src/parsimony.jl | 2 +- test/test_auxillary.jl | 5 +- test/test_manipulateNet.jl | 41 ++++++----- 7 files changed, 112 insertions(+), 88 deletions(-) diff --git a/docs/src/lib/public.md b/docs/src/lib/public.md index af6375a3..c71dd6f2 100644 --- a/docs/src/lib/public.md +++ b/docs/src/lib/public.md @@ -30,19 +30,19 @@ printEdges printNodes getroot isrootof -isleaf -isexternal +#isleaf +#isexternal isparentof -ischildof +#ischildof hassinglechild getchild -getchildren -getchildedge +#getchildren +#getchildedge getparent -getparents -getparentminor -getparentedge -getparentedgeminor +#getparents +#getparentminor +#getparentedge +#getparentedgeminor getpartneredge getNodeAges pairwiseTaxonDistanceMatrix diff --git a/docs/src/man/netmanipulation.md b/docs/src/man/netmanipulation.md index 3a33432b..376ec788 100644 --- a/docs/src/man/netmanipulation.md +++ b/docs/src/man/netmanipulation.md @@ -18,11 +18,15 @@ To traverse or learn something about a network, node or edge, see for example: [`biconnectedComponents`](@ref), [`PhyloNetworks.blobInfo`](@ref) - [`hardwiredCluster`](@ref), [`hardwiredClusters`](@ref) - [`getroot`](@ref), [`isrootof`](@ref), - [`isleaf`](@ref), [`isexternal`](@ref), [`isparentof`](@ref), [`ischildof`](@ref), + [`isleaf`](@ref PhyloNetworks.isrootof), [`isexternal`](@ref PhyloNetworks.isrootof), + [`isparentof`](@ref), [`ischildof`](@ref PhyloNetworks.isparentof), [`hassinglechild`](@ref), -- [`getchild`](@ref), [`getchildren`](@ref), [`getchildedge`](@ref) - [`getparent`](@ref), [`getparents`](@ref), - [`getparentminor`](@ref), [`getparentedge`](@ref), [`getparentedgeminor`](@ref), +- [`getchild`](@ref), [`getchildren`](@ref PhyloNetworks.getchild), + [`getchildedge`](@ref PhyloNetworks.getchild) + [`getparent`](@ref), [`getparents`](@ref PhyloNetworks.getparent), + [`getparentminor`](@ref PhyloNetworks.getparent), + [`getparentedge`](@ref PhyloNetworks.getparent), + [`getparentedgeminor`](@ref PhyloNetworks.getparent), [`getpartneredge`](@ref) To modify a network, for example: diff --git a/src/auxiliary.jl b/src/auxiliary.jl index 91ca639d..7a2fb1e1 100644 --- a/src/auxiliary.jl +++ b/src/auxiliary.jl @@ -153,6 +153,8 @@ end Node used to root `net`. If `net` is to be considered as semi-directed or unrooted, this root node is used to write the networks' Newick parenthetical description or for network traversals. + +See also: [`isrootof`](@ref) """ getroot(net::HybridNetwork) = net.node[net.root] @@ -161,21 +163,21 @@ getroot(net::HybridNetwork) = net.node[net.root] `true` if `node` is the root of `net` (or used as such for network traversals in case the network is considered as semi-directed); `false` otherwise. -""" -isrootof(node::Node, net::HybridNetwork) = node === getroot(net) -""" isleaf(node) + isexternal(edge) -`true` if `node` is a leaf, `false` otherwise. -""" -isleaf(node::Node) = node.leaf +`true` if `node` is a leaf or `edge` is adjacent to a leaf, `false` otherwise. +See also: [`getroot`](@ref), +[`getparent`](@ref), [`getchild`](@ref) """ - isexternal(edge) +isrootof(node::Node, net::HybridNetwork) = node === getroot(net) -`true` if `edge` is adjacent to a leaf, `false` otherwise. -""" +@doc (@doc isrootof) isleaf +isleaf(node::Node) = node.leaf + +@doc (@doc isrootof) isexternal isexternal(edge::Edge) = any(isleaf.(edge.node)) """ @@ -185,6 +187,8 @@ isexternal(edge::Edge) = any(isleaf.(edge.node)) `true` if `node` is the tail / head, or parent / child, of `edge`; `false` otherwise. Assumes that the edge's direction is correct, meaning it's field `isChild1` is reliable (in sync with the rooting). + +See also: [`getparent`](@ref), [`getchild`](@ref), [`isrootof`](@ref) """ isparentof(node::Node, edge::Edge) = node === getparent(edge) @doc (@doc isparentof) ischildof @@ -193,30 +197,40 @@ ischildof( node::Node, edge::Edge) = node === getchild(edge) """ hassinglechild(node) -`true` if `node` has a single child, based on the edges `isChild1` field; +`true` if `node` has a single child, based on the edges' `isChild1` field; `false` otherwise. + +See also: [`getchild`](@ref), [`getparent`](@ref) """ hassinglechild(node::Node) = sum(e -> getparent(e) === node, node.edge) == 1 """ getchild(edge) getchild(node) + getchildren(node) -Child node of `edge`; or -single child node of `node` after checking that `node` has a single child. -Relies on the edges direction (from their `isChild1` field). -""" -getchild(edge::Edge) = edge.node[edge.isChild1 ? 1 : 2] -getchild(node::Node) = getchild(getchildedge(node)) +Get child(ren) **node(s)**. +- `getchild`: single child node of `edge`, or of `node` after checking that + `node` has a single child. +- `getchildren`: vector of all children *nodes* of `node`. -""" - getchildren(node) -Vector of all children *nodes* of `node`. -**warning**: assume `isChild1` field (for edges) are correct + getchildedge(node) -To get all parent *nodes*: see [`getparents`](@ref PhyloNetworks.getparents). +Single child **edge** of `node`. Checks that it's a single child. + +*Warning*: these functions rely on correct edge direction, via their `isChild1` field. + +See also: +[`getparent`](@ref), +[`getpartneredge`](@ref), +[`isparentof`](@ref), +[`hassinglechild`](@ref). """ +getchild(edge::Edge) = edge.node[edge.isChild1 ? 1 : 2] +getchild(node::Node) = getchild(getchildedge(node)) + +@doc (@doc getchild) getchildren function getchildren(node::Node) children = Node[] for e in node.edge @@ -227,11 +241,7 @@ function getchildren(node::Node) return children end -""" - getchildedge(node) - -Single child edge of `node`. Checks that it's a single child. -""" +@doc (@doc getchild) getchildedge function getchildedge(node::Node) ce_ind = findall(e -> isparentof(node, e), node.edge) length(ce_ind) == 1 || error("node number $(node.number) has $(length(ce_ind)) children instead of 1 child") @@ -241,11 +251,29 @@ end """ getparent(edge) getparent(node) + getparentminor(node) + getparents(node) + +Get parental **node(s)**. +- `getparent`: **major** (or only) parent node of `edge` or `node` +- `getparentminor`: minor parent node of `node` +- `getparents`: vector of all parent nodes of `node`. + -Parent node of `edge`, or **major** parent node of `node`. -Warning: usies the `isChild1` attribute of edges. + getparentedge(node) + getparentedgeminor(node) + +Get one parental **edge** of a `node`. +- `getparentedge`: major parent edge. For a tree node, it's its only parent edge. +- `getparentedgeminor`: minor parent edge, if `node` is hybrid + (with an error if `node` has no minor parent). +If `node` has multiple major (resp. minor) parent edges, the first one would be +returned without any warning or error. + +*Warning*: these functions use the field `isChild1` of edges. -See also: [`getparents`](@ref) [`getparentminor`](@ref). +See also: [`getchild`](@ref), +[`getpartneredge`](@ref). """ getparent(edge::Edge) = edge.node[edge.isChild1 ? 2 : 1] @inline function getparent(node::Node) @@ -257,13 +285,7 @@ getparent(edge::Edge) = edge.node[edge.isChild1 ? 2 : 1] error("could not find major parent of node $(node.number)") end -""" - getparentminor(node) - -Minor parent node of `node` using the `isChild1` field of edges -(and assuming correct `isMajor` field). -See also [`getparentedge`](@ref) and [`getparentedgeminor`](@ref). -""" +@doc (@doc getparent) getparentminor @inline function getparentminor(node::Node) for e in node.edge if !e.isMajor && node == getchild(e) @@ -273,15 +295,7 @@ See also [`getparentedge`](@ref) and [`getparentedgeminor`](@ref). error("could not find minor parent of node $(node.number)") end -""" - getparents(node) - -Vector of all parent nodes of `node`, based on `isChild1` field (for edges). - -See also: [`getparent`](@ref) to get the (major) parent node, -[`getparentedge`](@ref) for the (major) parent edge and -[`getparentedgeminor`](@ref). -""" +@doc (@doc getparent) getparents @inline function getparents(node::Node) parents = Node[] for e in node.edge @@ -292,15 +306,7 @@ See also: [`getparent`](@ref) to get the (major) parent node, return parents end -""" - getparentedge(node) - getparentedgeminor(node) - -return the parent edge of `node`: the major / minor if hybrid. -**warning**: assume isChild1 and isMajor attributes are correct - -To get all parent *nodes*: see [`getparents`](@ref). -""" +@doc (@doc getparent) getparentedge @inline function getparentedge(n::Node) for ee in n.edge if ee.isMajor && ischildof(n,ee) @@ -309,7 +315,7 @@ To get all parent *nodes*: see [`getparents`](@ref). end error("node $(n.number) has no major parent") end -@doc (@doc getparentedge) getparentedgeminor +@doc (@doc getparent) getparentedgeminor @inline function getparentedgeminor(n::Node) for ee in n.edge if !ee.isMajor && n == ee.node[(ee.isChild1 ? 1 : 2)] @@ -324,12 +330,14 @@ end getpartneredge(edge::Edge, node::Node) Edge that is the hybrid partner of `edge`, meaning that is has the same child -`node` as `edge`. This child `node` is given as an argument in the second version. +`node` as `edge`. This child `node` is given as an argument in the second method. Assumptions, not checked: - no in-coming polytomy: a node has 0, 1 or 2 parents, no more - when `node` is given, it is assumed to be the child of `edge` (the first method calls the second). + +See also: [`getparent`](@ref), [`getchild`](@ref) """ @inline function getpartneredge(edge) node = getchild(edge) diff --git a/src/manipulateNet.jl b/src/manipulateNet.jl index e7c1feab..f09233c3 100644 --- a/src/manipulateNet.jl +++ b/src/manipulateNet.jl @@ -148,7 +148,7 @@ which must in the same cycle. `net` is assumed to be of level 1, but **no checks** are made and fields are supposed up-to-date. Called by `hybridatnode!(net, node number)`, which is itself -called by [`undirectedOtherNetworks`](@ref PhyloNetworks.undirectedOtherNetworks). +called by [`undirectedOtherNetworks`](@ref). """ function hybridatnode!(net::HybridNetwork, hybrid::Node, newNode::Node) hybrid.hybrid || error("node $(hybrid.number) should be hybrid, but it is not") diff --git a/src/parsimony.jl b/src/parsimony.jl index c7b49524..5aa5462b 100644 --- a/src/parsimony.jl +++ b/src/parsimony.jl @@ -1003,7 +1003,7 @@ All return their optimized network. Only maxParsimonyNet returns a rooted networ to modify the topology according to random NNI/move origin/move target moves. It then calls maxParsimonyNetRun1! on the modified network - maxParsimonyNetRun1! proposes new network with various moves (same moves as snaq), and stops when it finds the - most parsimonious network, using [`parsimonyGF`](@ref). + most parsimonious network, using [`parsimonyGF`](@ref PhyloNetworks.parsimonyGF). None of these functions allow for multiple alleles yet. diff --git a/test/test_auxillary.jl b/test/test_auxillary.jl index ab8cff51..fc22ef71 100644 --- a/test/test_auxillary.jl +++ b/test/test_auxillary.jl @@ -39,13 +39,16 @@ PhyloNetworks.addhybridedge!(tree, tree.edge[2], tree.edge[1], true) end # of testing hashybridladder @testset "shrink edges and cycles" begin -# shrink 1 edge +# shrink 1 edge, and hassinglechild net = readTopology("((A:2.0,(((B1,B2):1.0)0.01)#H1:0.1::0.9):1.5,(C:0.6,#H1:1.0::0.1):1.0):0.5);") @test !PhyloNetworks.shrinkedge!(net, net.edge[10]) @test_throws Exception PhyloNetworks.shrinkedge!(net, net.edge[6]) # hybrid edge @test_throws Exception PhyloNetworks.shrinkedge!(net, net.edge[3]) # external edge +@test hassinglechild(net.hybrid[1]) +@test hassinglechild(net.node[5]) && !net.node[5].hybrid # degree-2 tree node @test !PhyloNetworks.shrinkedge!(net, net.edge[5]) @test PhyloNetworks.shrinkedge!(net, net.edge[4]) +@test !hassinglechild(net.hybrid[1]) # shrink cycles net = readTopology("(((A:2.0,(B:1.0)#H1:0.1::0.9):1.5,(C:0.6,#H1:1.0::0.1):1.0):0.5,D:2.0);") @test !shrink2cycles!(net) diff --git a/test/test_manipulateNet.jl b/test/test_manipulateNet.jl index c82236d4..baca3521 100644 --- a/test/test_manipulateNet.jl +++ b/test/test_manipulateNet.jl @@ -37,22 +37,31 @@ node leaf hybrid hasHybEdge name inCycle edges'numbers 10 false false true S4 -1 3 11 """ close(s); -@test_throws ErrorException PhyloNetworks.getparentminor(net.node[1]) -@test PhyloNetworks.getparent(net.node[1]).number == 2 -@test PhyloNetworks.getparentminor(net.node[3]).number == 6 -@test PhyloNetworks.getparent(net.node[3]).number == 10 -@test PhyloNetworks.getparentedge(net.node[6]).number == 7 -@test_throws ErrorException PhyloNetworks.getparentedgeminor(net.node[6]) -@test PhyloNetworks.getparentedge(net.node[2]).number == 2 -@test PhyloNetworks.getparentedgeminor(net.node[2]).number == 8 -@test [n.number for n in PhyloNetworks.getchildren(net.node[4])] == [] # leaf -@test [n.number for n in PhyloNetworks.getchildren(net.node[2])] == [1] # hybrid node -@test [n.number for n in PhyloNetworks.getchildren(net.node[9])] == [6,8] # tree node -@test [n.number for n in PhyloNetworks.getchildren(net.node[10])] == [3,9] # at root -@test [n.number for n in PhyloNetworks.getchildren(net.node[6])] == [4,5,3] # polytomy -@test PhyloNetworks.getparent(net.edge[8]).number == 8 -@test [n.number for n in PhyloNetworks.getparents(net.node[3])] == [10, 6] -@test [n.number for n in PhyloNetworks.getparents(net.node[6])] == [9] +originalstdout = stdout +redirect_stdout(devnull) +printEdges(net) # method without io argument +printNodes(net) +redirect_stdout(originalstdout) + +@test_throws ErrorException getparent(net.node[net.root]) +@test_throws ErrorException getparentedge(net.node[net.root]) +@test_throws ErrorException getparentedgeminor(net.node[net.root]) +@test_throws ErrorException getparentminor(net.node[1]) +@test getparent(net.node[1]).number == 2 +@test getparentminor(net.node[3]).number == 6 +@test getparent(net.node[3]).number == 10 +@test getparentedge(net.node[6]).number == 7 +@test_throws ErrorException getparentedgeminor(net.node[6]) +@test getparentedge(net.node[2]).number == 2 +@test getparentedgeminor(net.node[2]).number == 8 +@test [n.number for n in getchildren(net.node[4])] == [] # leaf +@test [n.number for n in getchildren(net.node[2])] == [1] # hybrid node +@test [n.number for n in getchildren(net.node[9])] == [6,8] # tree node +@test [n.number for n in getchildren(net.node[10])] == [3,9] # at root +@test [n.number for n in getchildren(net.node[6])] == [4,5,3] # polytomy +@test getparent(net.edge[8]).number == 8 +@test [n.number for n in getparents(net.node[3])] == [10, 6] +@test [n.number for n in getparents(net.node[6])] == [9] @test_throws ErrorException deleteleaf!(net, net.node[9]) n = deepcopy(net) @test_logs deleteleaf!(n, n.node[7]) From e1f8c7ef74e46698e43c3b1e66cf2d85dd9448e1 Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Sat, 14 Jan 2023 18:24:48 -0600 Subject: [PATCH 8/9] get and setGammas: fixed to work with non-tree-child networks --- src/traits.jl | 53 ++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/traits.jl b/src/traits.jl index 967c8716..e28c6c56 100644 --- a/src/traits.jl +++ b/src/traits.jl @@ -1771,17 +1771,21 @@ end """ getGammas(net) -Get inheritance γ's of major hybrid edges. Assume pre-order calculated already -(with up-to-date field `nodes_changed`). See [`setGammas!`](@ref) +Vector of inheritance γ's of all major edges (tree edges and major hybrid edges), +ordered according to the pre-order index of their child node, +assuming this pre-order is already calculated +(with up-to-date field `nodes_changed`). +Here, a "major" edge is an edge with field `isMajor` set to true, +regardless of its actual γ (below, at or above 0.5). + +See [`setGammas!`](@ref) """ function getGammas(net::HybridNetwork) - isHybrid = [n.hybrid for n in net.nodes_changed] - gammas = ones(size(isHybrid)) - for i in 1:size(isHybrid, 1) - if isHybrid[i] - majorHybrid = [n.hybrid & n.isMajor for n in net.nodes_changed[i].edge] - gammas[i] = net.nodes_changed[i].edge[majorHybrid][1].gamma - end + gammas = ones(length(net.nodes_changed)) + for (i,node) in enumerate(net.nodes_changed) + node.hybrid || continue # skip tree nodes: their gamma is already set to 1 + majorhybedge = getparentedge(node) # major + gammas[i] = majorhybedge.gamma end return gammas end @@ -1793,31 +1797,20 @@ Set inheritance γ's of hybrid edges, using input vector for *major* edges. Assume pre-order calculated already, with up-to-date field `nodes_changed`. See [`getGammas`](@ref). -Very different from [`setGamma!`](@ref), which focuses on a single hybrid event, +**Warning**: very different from [`setGamma!`](@ref), which focuses on a +single hybrid event, updates the field `isMajor` according to the new γ, and is not used here. -May assume a tree-child network. +**Assumption**: each hybrid node has only 2 parents, a major and a minor parent +(according to the edges' field `isMajor`). """ function setGammas!(net::HybridNetwork, gammas::Vector) - isHybrid = [n.hybrid for n in net.nodes_changed] - for i in 1:size(isHybrid, 1) - if isHybrid[i] - nod = net.nodes_changed[i] - majorHybrid = [edg.hybrid & edg.isMajor for edg in nod.edge] - #= worry: assume tree-child network? getMajorParent and getMinorParent would be safer - fixit fixit fixit! - use getparentedge(nod) and getparentedgeminor instead; - change & to && . ex: check impact on [isodd(x) & x<3 for x in [4,3,2,1]] - don't do if/else below: !any is different from !all. Or if unsyncing major & minor is intentional: then document it. - =# - minorHybrid = [edg.hybrid & !edg.isMajor for edg in nod.edge] - nod.edge[majorHybrid][1].gamma = gammas[i] - if any(minorHybrid) # case where gamma = 0.5 exactly - nod.edge[minorHybrid][1].gamma = 1 - gammas[i] - else - nod.edge[majorHybrid][2].gamma = 1 - gammas[i] - end - end + for (i,nod) in enumerate(net.nodes_changed) + nod.hybrid || continue # skip tree nodes: nothing to do + majorhyb = getparentedge(nod) # major + minorhyb = getparentedgeminor(nod) # error if doesn't exit + majorhyb.gamma = gammas[i] + minorhyb.gamma = 1 - gammas[i] end return nothing end From 1112fbcb82f78b69d2ff213538e3d63094f2db7f Mon Sep 17 00:00:00 2001 From: Cecile Ane Date: Sun, 15 Jan 2023 22:50:39 -0600 Subject: [PATCH 9/9] documentation for clusters and hardwired cluster distance --- src/compareNetworks.jl | 116 +++++++++++++++++++++++++++++++++++++---- src/manipulateNet.jl | 14 +++-- 2 files changed, 114 insertions(+), 16 deletions(-) diff --git a/src/compareNetworks.jl b/src/compareNetworks.jl index bdd52d18..881f6a88 100644 --- a/src/compareNetworks.jl +++ b/src/compareNetworks.jl @@ -55,12 +55,16 @@ function tree2Matrix(T::HybridNetwork, S::Union{Vector{String},Vector{Int}}; roo end """ -`hardwiredClusters(net::HybridNetwork, S::Union{AbstractVector{String},AbstractVector{Int}})` + hardwiredClusters(net::HybridNetwork, taxon_labels) -Returns a matrix describing all the hardwired clusters in a network. -Warnings: Clusters are rooted, so the root must be correct. - Allows for missing taxa, with entries all 0. +Returns a matrix describing all the hardwired clusters in a network, with +taxa listed in same order as in `taxon_labels` to describe their membership +in each cluster. Allows for missing taxa, with entries all 0. + +Warnings: +- clusters are rooted, so the root must be correct. +- each hybrid node is assumed to have exactly 2 parents (no more). Each row corresponds to one internal edge, that is, external edges are excluded. If the root is a leaf node, the external edge to that leaf is included (first row). @@ -69,6 +73,8 @@ Both parent hybrid edges to a given hybrid node only contribute a single row (th - first column: edge number - next columns: 0/1. 1=descendant of edge, 0=not a descendant, or missing taxon. - last column: 10/11 values. 10=tree edge, 11=hybrid edge + +See also [`hardwiredClusterDistance`](@ref) and [`hardwiredCluster`](@ref). """ function hardwiredClusters(net::HybridNetwork, S::Union{AbstractVector{String},AbstractVector{Int}}) ne = length(net.edge)-net.numTaxa # number of internal branch lengths @@ -168,6 +174,8 @@ julia> hardwiredCluster(net5.edge[12], taxa) # descendants of 12th edge = CEF 1 0 ``` + +See also [`hardwiredClusterDistance`](@ref) and [`hardwiredClusters`](@ref) """ function hardwiredCluster(edge::Edge,taxa::Union{AbstractVector{String},AbstractVector{Int}}) v = zeros(Bool,length(taxa)) @@ -675,19 +683,105 @@ end """ hardwiredClusterDistance(net1::HybridNetwork, net2::HybridNetwork, rooted::Bool) -Takes 2 networks and returns their hardwired cluster distance, that is, -the number of hardwired clusters found in one network and not in the other. -Note that this is not a distance per se on the full space of hybrid networks: -there are pairs of different networks for which this measure is 0. -But it is a distance on some network subspaces. +Hardwired cluster distance between the topologies of `net1` and `net2`, that is, +the number of hardwired clusters found in one network and not in the other +(with multiplicity, see below). If the 2 networks are trees, this is the Robinson-Foulds distance. -If rooted=false, the trees are considered unrooted. +If rooted=false, then both networks are considered as semi-directed. + +Networks are assumed bicombining (each hybrid has exactly 2 parents, no more). + +## Dissimilarity vs distance -If rooted is false and one of the phylogenies is not a tree (1+ reticulations), +This is *not* a distance per se on the full space of phylogenetic networks: +there are pairs of distinct networks for which this dissimilarity is 0. +But it is a distance on some classes of networks, such as the class of +tree-child networks that are "normal" (without shortcuts), or the class of +tree-child networks that can be assigned node ages such that hybrid edges +have length 0 and tree edges have non-negative lengths. See +[Cardona, Rossello & Valiente (2008)](https://doi.org/10.1016/j.mbs.2007.11.003), +[Cardona, Llabres, Rossello & Valiente (2008)](https://doi.org/10.1109/TCBB.2008.70), +and [Huson, Rupp, Scornavacca (2010)](https://doi.org/10.1017/CBO9780511974076). + +## Example + +```jldoctest +julia> net1 = readTopology("(t6,(t5,((t4,(t3,((t2,t1))#H1)),#H1)));"); + +julia> taxa = sort(tipLabels(net1)); # t1 through t6, sorted alphabetically + +julia> # using PhyloPlots; plot(net1, showedgenumber=true); + +julia> # in matrix below: column 1: edge number. last column: tree (10) vs hybrid (11) edge + # middle columns: for 'taxa': t1,...t6. 1=descendant, 0=not descendant + hardwiredClusters(net1, taxa) +6×8 Matrix{Int64}: + 13 1 1 1 1 1 0 10 + 12 1 1 1 1 0 0 10 + 10 1 1 1 1 0 0 10 + 9 1 1 1 0 0 0 10 + 8 1 1 0 0 0 0 11 + 7 1 1 0 0 0 0 10 + +julia> net2 = readTopology("(t6,(t5,((t4,(t3)#H1),(#H1,(t1,t2)))));"); + +julia> hardwiredClusters(net2, taxa) +6×8 Matrix{Int64}: + 13 1 1 1 1 1 0 10 + 12 1 1 1 1 0 0 10 + 6 0 0 1 1 0 0 10 + 5 0 0 1 0 0 0 11 + 11 1 1 1 0 0 0 10 + 10 1 1 0 0 0 0 10 + +julia> hardwiredClusterDistance(net1, net2, true) # true: as rooted networks +4 +``` + +## What is a hardwired cluster? + +Each edge in a network is associated with its *hardwired cluster*, that is, +the set of all its descendant taxa (leaves). The set of hardwired cluster +of a network is the set of its edges' hardwired clusters. The dissimilarity +`d_hard` defined in [Huson, Rupp, Scornavacca (2010)](https://doi.org/10.1017/CBO9780511974076) +is the number of hardwired clusters that are in one network but not in the other. + +This implementation is a slightly more discriminative version of `d_hard`, where +each cluster is counted with multiplicity and annotated with its edge's hybrid +status, as follows: +- External edges are not counted (they are tree edges to a leaf, shared by all + phylogenetic networks). +- A cluster is counted for each edge for which it's the hardwired cluster. +- At a given hybrid node, both hybrid partner edges have the same cluster, + so this cluster is only counted once for both partners. +- A given cluster is matched between the two networks only if it's the cluster + from a tree edge in both networks, or from a hybrid edge in both networks. + +In the example above, `net1` has a shortcut (hybrid edge 11) resulting in 2 tree +edges (12 and 10) with the same cluster {t1,t2,t3,t4}. So cluster {t1,t2,t3,t4} +has multiplicity 2 in `net1`. `net2` also has this cluster, but only associated +with 1 tree edge, so this cluster contributes (2-1)=1 towards the hardwired cluster +distance between the two networks. The distance of 4 corresponds to these 4 clusters: +- {t1,t2,t3,t4}: twice in net1, once in net2 +- {t3,t4}: absent in net1, once in net2 +- {t1,t2}: twice in net1 (from a hybrid edge & a tree edge), once in net2 +- {t3}: absent in net1 (because external edges are not counted), + once in net2 (from a hybrid edge). + +Degree-2 nodes cause multiple edges to have the same cluster, so counting +clusters with multiplicity distinguishes a network with extra degree-2 nodes +from the "same" network after these nodes have been suppressed +(e.g. with [`PhyloNetworks.fuseedgesat!`](@ref) or [`PhyloNetworks.shrinkedge!`](@ref)). + +## Networks as semi-directed + +If `rooted` is false and one of the phylogenies is not a tree (1+ reticulations), then all degree-2 nodes are removed before comparing the hardwired clusters, and the minimum distance is returned over all possible ways to root the networks at internal nodes. + +See also: [`hardwiredClusters`](@ref), [`hardwiredCluster`](@ref) """ function hardwiredClusterDistance(net1::HybridNetwork, net2::HybridNetwork, rooted::Bool) bothtrees = (net1.numHybrids == 0 && net2.numHybrids == 0) diff --git a/src/manipulateNet.jl b/src/manipulateNet.jl index f09233c3..c5747559 100644 --- a/src/manipulateNet.jl +++ b/src/manipulateNet.jl @@ -95,11 +95,14 @@ end """ hybridatnode!(net::HybridNetwork, nodeNumber::Integer) + hybridatnode(net, nodeNumber) Change the status of edges in network `net`, to move the hybrid node in a cycle to the node with number `nodeNumber`. This node must be in one (and only one) cycle, otherwise an error will be thrown. +The second method does not modify `net`, checks that it's of level 1, and +returns the new network after hybrid modification. `net` is assumed to be of level 1, that is, each blob has a single cycle with a single reticulation. @@ -175,11 +178,10 @@ function hybridatnode!(net::HybridNetwork, hybrid::Node, newNode::Node) end end -# function to change the hybrid node in a cycle -# does not assume that the network was read with readTopologyUpdate -# does not modify net0 because it needs to update all attributes -# so, it returns the new network # Not used anywhere, but tested +# does not call hybridatnode! but repeats its code: oops! violates DRY principle +# nodeNumber should correspond to the number assigned by readTopologyLevel1, +# and the node numbers in `net` are irrelevant. @doc (@doc hybridatnode!) hybridatnode function hybridatnode(net0::HybridNetwork, nodeNumber::Integer) net = readTopologyLevel1(writeTopologyLevel1(net0)) # we need inCycle attributes @@ -411,6 +413,8 @@ PhyloNetworks.EdgeT{PhyloNetworks.Node}: julia> writeTopology(net) # note extra pair of parentheses around S1 "(((S8,S9),((((S4,(S1)),(S5)#H1),(#H1,(S6,S7))))#H2),(#H2,S10));" ``` + +See also: [`fuseedgesat!`](@ref) """ function breakedge!(edge::Edge, net::HybridNetwork) pn = getparent(edge) # parent node @@ -447,7 +451,7 @@ The parent and child edges of this node are fused. If either of the edges is hybrid, the hybrid edge is retained. Otherwise, the edge with the lower edge number is retained. -Reverts the action of breakedge!. +Reverts the action of [`breakedge!`](@ref). returns the fused edge. """