ourMELONS/matlab/graph/@phyTree/getCanonical.m

66 lines
2.1 KiB
Mathematica
Raw Normal View History

2019-12-16 16:47:21 +01:00
function [ptrs,dist,names] = getcanonical(tr)
%GETCANONICAL Calculates the canonical form of a phylogenetic tree.
%
% PTRS = GETCANONICAL(TREE) Returns the pointers of the canonical form of
% a phylogenetic tree. In a canonical tree the leaves are ordered
% alphabetically and the branches are ordered first by their width and
% then alphabetically by their first element. A canonical tree is
% isomorphic to all the trees with the same skeleton independently of the
% order of their leaves and branches.
%
% [PTRS,DIST,NAMES] = GETCANONICAL(TREE) Returns also the re-ordered
% distances and node names.
%
% Example:
% % create two trees with same skeleton but slightly different distances
% b = [1 2; 3 4; 5 6; 7 8;9 10];
% tr_1 = phytree(b,[.1 .2 .3 .3 .4 ]');
% tr_2 = phytree(b,[.2 .1 .2 .3 .4 ]');
% plot(tr_1)
% plot(tr_2)
%
% % compare if the two trees are isomorphic
% isequal(getcanonical(tr_1),getcanonical(tr_2))
%
% See also PHYTREE, PHYTREEREAD, PHYTREE/GETBYNAME, PHYTREE/SELECT,
% PHYTREE/SUBTREE.
% Copyright 2003-2006 The MathWorks, Inc.
% $Revision: 1.1.8.2 $ $Author: batserve $ $Date: 2006/06/16 20:06:42 $
if numel(tr)~=1
error('Bioinfo:phytree:getcanonical:NoMultielementArrays',...
'Phylogenetic tree must be an 1-by-1 object.');
end
numBranches = size(tr.tree,1);
numLeaves = numBranches + 1;
numLabels = numBranches + numLeaves;
[dummy,h] = sort(tr.names(1:numLeaves)); %#ok
h(h)=1:numLeaves;
% compute the branch width and the first element for each one
branchWidth = ones(numLabels,1);
firstElement = [h;inf(numBranches,1)];
for ind = 1:numBranches
branchWidth(numLeaves+ind) = sum(branchWidth(tr.tree(ind,:)));
firstElement(numLeaves+ind) = min(firstElement(tr.tree(ind,:)));
end
% find out how to re-order
[dummy,ord]=sortrows([branchWidth firstElement]); %#ok
iord(ord) = 1:numLabels;
% re-order pointers
ptrs = sort(iord(tr.tree(ord(numLeaves+1:numLabels)-numLeaves,:)),2);
if nargout > 1
dist = tr.dist(ord);
end
if nargout > 2
names = tr.names(ord);
end