Mercurial > hg > octave-lyh
diff scripts/sparse/treelayout.m @ 8338:a35bf360b919
Add the cgs and treelayout functions
author | Radek Salac <salac.r@gmail.com> |
---|---|
date | Fri, 21 Nov 2008 15:03:03 +0100 |
parents | |
children | bc982528de11 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/scripts/sparse/treelayout.m @@ -0,0 +1,208 @@ +## Copyright (C) 2008 Ivana Varekova & Radek Salac +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} treelayout (@var{Tree}) +## @deftypefnx {Function File} {} treelayout (@var{Tree}, @var{Permutation}) +## treelayout lays out a tree or a forest. The first argument @var{Tree} is a vector of +## predecessors, optional parameter @var{Permutation} is an optional postorder permutation. +## The complexity of the algorithm is O(n) in +## terms of time and memory requirements. +## @seealso{etreeplot, gplot,treeplot} +## @end deftypefn + +function [XCoordinate, YCoordinate, Height, s] = treelayout (Tree, Permutation) + if (nargin < 1 || nargin > 2 || nargout > 4) + print_usage (); + elseif (! isvector (Tree) || rows (Tree) != 1 || ! isnumeric (Tree) + || any (Tree > length (Tree)) || any (Tree < 0) ) + error ("treelayout: the first input argument must be a vector of predecessors"); + else + ## make it a row vector + Tree = Tree(:)'; + + ## the count of nodes of the graph + NodNumber = length (Tree); + ## the number of children + ChildNumber = zeros (1, NodNumber + 1); + + + ## checking vector of predecessors + for i = 1 : NodNumber + if (Tree (i) < i) + ## this part of graph was checked before + continue; + endif + + ## Try to find cicle in this part of graph + ## we use modified Floyd's cycle-finding algorithm + tortoise = Tree (i); + hare = Tree (tortoise); + + while (tortoise != hare) + ## we end after find a cicle or when we reach a checked part of graph + + if (hare < i) + ## this part of graph was checked before + break + endif + + tortoise = Tree (tortoise); + ## hare will move faster than tortoise so in cicle hare + ## must reach tortoise + hare = Tree (Tree (hare)); + + endwhile + + if (tortoise == hare) + ## if hare reach tortoise we find cicle + error ("treelayout: vector of predecessors has bad format"); + endif + + endfor + ## vector of predecessors has right format + + for i = 1:NodNumber + ## VecOfChild is helping vector which is used to speed up the + ## choose of descendant nodes + + ChildNumber (Tree (i) + 1) = ChildNumber (Tree (i) + 1) + 1; + endfor + + Pos = 1; + for i = 1 : NodNumber + 1 + Start (i) = Pos; + Help (i) = Pos; + Pos += ChildNumber (i); + Stop (i) = Pos; + endfor + + if (nargin == 1) + for i = 1 : NodNumber + VecOfChild (Help (Tree (i) + 1)) = i; + Help (Tree (i) + 1) = Help (Tree (i) + 1) + 1; + endfor + else + VecOfChild = Permutation; + endif + + + ## the number of "parent" (actual) node (it's descendants will be + ## browse in the next iteration) + ParNumber = 0; + + ## the x-coordinate of the left most descendant of "parent node" + ## this value is increased in each leaf + LeftMost = 0; + + ## the level of "parent" node (root level is NodNumber) + Level = NodNumber; + + ## NodNumber - Max is the height of this graph + Max = NodNumber; + + ## main stack - each item consists of two numbers - the number of + ## node and the number it's of parent node on the top of stack + ## there is "parent node" + St = [-1, 0]; + + #number of vertices s in the top-level separator + s = 0; + # flag which says if we are in top level separator + topLevel = 1; + ## the top of the stack + while (ParNumber != -1) + if (Start(ParNumber + 1) < Stop(ParNumber + 1)) + idx = VecOfChild (Start (ParNumber + 1) : Stop (ParNumber + 1) - 1); + else + idx = zeros (1, 0); + endif + + ## add to idx the vector of parent descendants + St = [St ; [idx', ones(fliplr(size(idx))) * ParNumber]]; + + # we are in top level separator when we have one children + ## and the flag is 1 + if (columns(idx) == 1 && topLevel ==1 ) + s += 1; + else + # we arent in top level separator now + topLevel = 0; + endif + ## if there is not any descendant of "parent node": + if (St(end,2) != ParNumber) + LeftMost = LeftMost + 1; + XCoordinateR(ParNumber) = LeftMost; + Max = min (Max, Level); + if ((length(St) > 1) && (find((shift(St,1)-St) == 0) >1) + && St(end,2) != St(end-1,2)) + ## return to the nearest branching the position to return + ## position is the position on the stack, where should be + ## started further search (there are two nodes which has the + ## same parent node) + + Position = (find ((shift (St(:, 2), 1) - St(:, 2)) == 0))(end)+1; + ParNumberVec = St(Position : end, 2); + + ## the vector of removed nodes (the content of stack form + ## position to end) + + Level = Level + length(ParNumberVec); + + ## the level have to be decreased + + XCoordinateR(ParNumberVec) = LeftMost; + St(Position:end, :) = []; + endif + + ## remove the next node from "searched branch" + + St(end, :) = []; + ## choose new "parent node" + ParNumber = St(end, 1); + ## if there is another branch start to search it + if (ParNumber != -1) + YCoordinate(ParNumber) = Level; + XCoordinateL(ParNumber) = LeftMost + 1; + endif + else + + ## there were descendants of "parent nod" choose the last of + ## them and go on through it + Level--; + ParNumber = St(end, 1); + YCoordinate(ParNumber) = Level; + XCoordinateL(ParNumber) = LeftMost+1; + endif + endwhile + + ## calculate the x coordinates (the known values are the position + ## of most left and most right descendants) + XCoordinate = (XCoordinateL + XCoordinateR) / 2; + + Height = NodNumber - Max - 1; + endif +endfunction + +%!demo +%! % Compute a simple tree layout +%! [x,y,h,s]=treelayout([0 1 2 2]) + +%!demo +%! % Compute a simple tree layout with defined postorder permutation +%! [x,y,h,s]=treelayout([0 1 2 2],[1 2 3 4])