//--------------------------------------------------------------------------- // // Project: OpenWalnut ( http://www.openwalnut.org ) // // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS // For more information see http://www.openwalnut.org/copying // // This file is part of OpenWalnut. // // OpenWalnut is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // OpenWalnut 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenWalnut. If not, see . // //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // // Project: hClustering // // Whole-Brain Connectivity-Based Hierarchical Parcellation Project // David Moreno-Dominguez // d.mor.dom@gmail.com // moreno@cbs.mpg.de // www.cbs.mpg.de/~moreno// // This file is also part of OpenWalnut ( http://www.openwalnut.org ). // // For more reference on the underlying algorithm and research they have been used for refer to: // - Moreno-Dominguez, D., Anwander, A., & Knösche, T. R. (2014). // A hierarchical method for whole-brain connectivity-based parcellation. // Human Brain Mapping, 35(10), 5000-5025. doi: http://dx.doi.org/10.1002/hbm.22528 // - Moreno-Dominguez, D. (2014). // Whole-brain cortical parcellation: A hierarchical method based on dMRI tractography. // PhD Thesis, Max Planck Institute for Human Cognitive and Brain Sciences, Leipzig. // ISBN 978-3-941504-45-5 // // hClustering is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // http://creativecommons.org/licenses/by-nc/3.0 // // hClustering 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 Lesser General Public License for more details. // //--------------------------------------------------------------------------- // std library #include #include #include #include #include #include #include "core/common/WStringUtils.h" #include "WHtree.h" #define NEWBOOST true WHtree::WHtree(): m_loadStatus( false ), m_cpcc( 0 ) { } WHtree::WHtree( std::string filename ): m_loadStatus( false ), m_cpcc( 0 ) { readTree( filename ); } WHtree::WHtree( std::string treeName, HC_GRID datasetGridInit, WHcoord datasetSizeInit, size_t numStreamlinesInit, float logFactorInit, std::vector< WHnode > leavesInit, std::vector< WHnode > nodesInit, std::vector< size_t > trackidInit, std::vector< WHcoord > coordInit, std::list< WHcoord > discardInit, float cpccInit ) : m_loadStatus( false ), m_datasetSize( datasetSizeInit ), m_datasetGrid( datasetGridInit ), m_numStreamlines( numStreamlinesInit ), m_logFactor( logFactorInit ), m_cpcc( cpccInit ), m_treeName( treeName ), m_leaves( leavesInit ), m_nodes( nodesInit ), m_coordinates( coordInit ), m_trackids( trackidInit ), m_discarded( discardInit ) { if( check() ) { m_loadStatus = true; } } WHtree::WHtree( const WHtree &object ) : m_loadStatus( object.m_loadStatus ), m_datasetSize( object.m_datasetSize ), m_datasetGrid( object.m_datasetGrid ), m_numStreamlines( object.m_numStreamlines ), m_logFactor( object.m_logFactor ), m_cpcc( object.m_cpcc ), m_treeName( object.m_treeName ), m_leaves( object.m_leaves ), m_nodes( object.m_nodes ), m_coordinates( object.m_coordinates ), m_trackids( object.m_trackids ), m_discarded( object.m_discarded ), m_containedLeaves( object.m_containedLeaves ) { } WHtree::~WHtree() { //Cleanup } // === PUBLIC MEMBER FUNCTIONS === std::string WHtree::getReport( bool longMsg ) const { if( !m_loadStatus) { return "tree not loaded"; } std::string reportMessage( "Tree has " + string_utils::toString( m_leaves.size() ) + " leaves and " + string_utils::toString( m_nodes.size() ) + " nodes" ); if( longMsg ) { reportMessage += "\nDataset size is: " + m_datasetSize.getNameString() + " in " + getGridString( m_datasetGrid ) + " format"; if( m_cpcc != 0 ) { reportMessage += ". CPCC: " + string_utils::toString( m_cpcc ); } } return reportMessage; } // end getReport() ------------------------------------------------------------------------------------- bool WHtree::check() const { if( m_nodes.empty() || m_leaves.size() < 2 ) { std::cerr << "ERROR @ WHtree::check(): only 0-1 leaf / no nodes" << std::endl; return false; } if( m_nodes.size() >= m_leaves.size() ) { std::cerr << "ERROR @ WHtree::check(): same number of nodes as leaves" << std::endl; return false; } std::vector sumLeafParents( m_leaves.size(), 0 ); std::vector sumNodeParents( m_nodes.size(), 0 ); std::vector sumNodeKids( m_nodes.size(), 0 ); // loop through leaves for( std::vector::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter ) { nodeID_t parentID( leafIter->getParent() ); if( !parentID.first ) { std::cerr << "ERROR @ WHtree::check(): leaf has a leaf as parent" << std::endl; return false; } std::vector kids = getNode( parentID ).getChildren(); if( find( kids.begin(), kids.end(), leafIter->getFullID() ) == kids.end() ) { std::cerr << "ERROR @ WHtree::check(): leaf parent doesnt have leaf ID among its children" << std::endl; return false; } if( leafIter->getSize() != 1 ) { std::cerr << "ERROR @ WHtree::check(): leaf has a size other than 1" << std::endl; return false; } if( leafIter->getHLevel() != 0 ) { std::cerr << "ERROR @ WHtree::check(): leaf has hLevel other than 0" << std::endl; return false; } ++sumNodeKids[parentID.second]; } // loop through nodes for( std::vector::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter) { std::vector kids = nodeIter->getChildren(); size_t currentHLevel( 0 ), currentSize( 0 ); for( std::vector::const_iterator kidIter( kids.begin() ); kidIter != kids.end(); ++kidIter ) { currentHLevel = std::max( currentHLevel, getNode( *kidIter ).getHLevel()+1 ); currentSize += getNode( *kidIter ).getSize(); nodeID_t kidParent = getNode( *kidIter ).getParent(); if( kidParent != nodeIter->getFullID() ) { std::cerr << "ERROR @ WHtree::check(): node child (" << kidIter->first << "-" << kidIter->second << ") doesnt have node ID ("; std::cerr << nodeIter->isNode() << "-" << nodeIter->getID() << ") as its parent but instead has (" << kidParent.first << "-" << kidParent.second << ")" << std::flush; return false; } if( kidIter->first ) { ++sumNodeParents[kidIter->second]; } else { ++sumLeafParents[kidIter->second]; } } nodeID_t parentID( nodeIter->getParent() ); if( ( !parentID.first) && ( ( nodeIter+1 ) != m_nodes.end() ) ) { std::cerr << "ERROR @ WHtree::check(): node has a leaf as parent" << std::endl; return false; } if( ( !nodeIter->isRoot() ) && ( ( nodeIter+1 ) == m_nodes.end() ) ) { std::cerr << "ERROR @ WHtree::check(): last node does not have 0-0 as parent" << std::endl; return false; } if( !nodeIter->isRoot() ) { std::vector kids = getNode( parentID ).getChildren(); if( find( kids.begin(), kids.end(), nodeIter->getFullID() ) == kids.end() ) { std::cerr << "ERROR @ WHtree::check(): node parent doesnt have node ID among its children" << std::endl; return false; } ++sumNodeKids[parentID.second]; } if( nodeIter->getSize() != currentSize ) { std::cerr << "ERROR @ WHtree::check(): node " << nodeIter->getID() << " size (" << nodeIter->getSize() << ") is not sum of its children sizes (" << currentSize << ")" << std::endl; return false; } if( nodeIter->getHLevel() != currentHLevel ) { std::cerr << "ERROR @ WHtree::check(): node hLevel is not one more than its highest child" << std::endl; return false; } } //check consistency of counters for( std::vector::const_iterator iter( sumLeafParents.begin() ); iter != sumLeafParents.end(); ++iter ) { if( *iter != 1 ) { std::cerr << "ERROR @ WHtree::check(): more than one node has the same leaf as child" << std::endl; return false; } } for( std::vector::const_iterator iter( sumNodeParents.begin() ); iter != sumNodeParents.end()-1; ++iter ) { if( *iter != 1 ) { std::cerr << "ERROR @ WHtree::check(): more than one node has the same node as child" << std::endl; return false; } } if( sumNodeParents.back() != 0 ) { std::cerr << "ERROR @ WHtree::check(): at least one node has the root node as child" << std::endl; return false; } for( std::vector::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter) { std::vector kids = nodeIter->getChildren(); if( kids.size() != sumNodeKids[nodeIter->getID()] ) { std::cerr << "ERROR @ WHtree::check(): node children vector size does not match the number of nodes/leafs that have it as parent"; std::cerr << std::endl << nodeIter->printAllData() << std::endl; return false; } } return true; // everything checked out fine } // end check() ------------------------------------------------------------------------------------- const WHnode& WHtree::getNode( const nodeID_t &thisNode ) const { if( thisNode.first ) { return getNode( thisNode.second ); } else { return getLeaf( thisNode.second ); } } // end getNode() ------------------------------------------------------------------------------------- const WHnode& WHtree::getNode( const size_t thisNode ) const { if( thisNode >= m_nodes.size() ) { std::cerr << "ERROR @ WHtree::getNode: index is out of boundaries(" << thisNode << ". total nodes: " << m_nodes.size() << "), returning first node" << std::endl; return m_nodes.front(); } else { return ( m_nodes[thisNode] ); } } // end getNode() ------------------------------------------------------------------------------------- const WHnode& WHtree::getLeaf( const size_t thisLeaf ) const { if( thisLeaf >= m_leaves.size() ) { std::cerr << "ERROR @ WHtree::getLeaf: index is out of boundaries (" << thisLeaf << ". total leaves: " << m_leaves.size() << "), returning first leaf" << std::endl; return m_leaves.front(); } else { return ( m_leaves[thisLeaf] ); } } // end getLeaf() ------------------------------------------------------------------------------------- const WHnode& WHtree::getRoot() const { return ( m_nodes.back() ); } // end getRoot() ------------------------------------------------------------------------------------- size_t WHtree::getLeafID( const WHcoord &thisCoord ) const { std::vector::const_iterator findIter( std::find( m_coordinates.begin(), m_coordinates.end(), thisCoord ) ); if( findIter == m_coordinates.end() ) { throw std::runtime_error( "ERROR @ WHtree::getLeafID(): coordinate is not in the tree" ); } else { return( findIter-m_coordinates.begin() ); } } // end getLeafID() ------------------------------------------------------------------------------------- std::vector WHtree::getLeaves4node( const size_t nodeID ) const { std::vector returnVector; if( nodeID >= m_nodes.size() ) { std::cerr << "ERROR @ WHtree::coordinate4leaf(): leafID is out of boundaries" << std::endl; return returnVector; } else { if( !m_containedLeaves.empty() ) // if contained leaves for each node have already been calculated, just return them { return m_containedLeaves[nodeID]; } else // if not, calculate them for this node { std::list worklist; worklist.push_back( nodeID ); while( !worklist.empty() ) { size_t currentNode( worklist.front() ); worklist.pop_front(); std::vector kids( getNode( currentNode ).getChildren() ); for( std::vector::const_iterator iter( kids.begin() ); iter != kids.end(); ++iter ) { if( iter->first) // is node { worklist.push_back( iter->second ); } else // is leaf { returnVector.push_back( iter->second ); } } } std::sort( returnVector.begin(), returnVector.end() ); return returnVector; } } } // end getLeaves4node() ------------------------------------------------------------------------------------- std::vector WHtree::getLeaves4node( const nodeID_t &nodeID ) const { if( nodeID.first ) { return getLeaves4node( nodeID.second ); } else { return std::vector( 1, nodeID.second ); } } // end getLeaves4node() ------------------------------------------------------------------------------------- std::vector WHtree::getBranchNodes( const size_t nodeID ) const { std::vector returnVector; if( nodeID >= getNumNodes() ) { std::cerr << "ERROR @ WHtree::getBranchNodes(): nodeID is out of boundaries" << std::endl; return returnVector; } else { std::list worklist; worklist.push_back( nodeID ); while( !worklist.empty() ) { size_t currentNode( worklist.front() ); worklist.pop_front(); returnVector.push_back( currentNode ); std::vector kids( getNode( currentNode ).getChildren() ); for( std::vector::const_iterator iter( kids.begin() ); iter != kids.end(); ++iter ) { if( iter->first ) { worklist.push_back( iter->second ); // is node } } } std::sort( returnVector.begin(), returnVector.end() ); return returnVector; } } // end getBranchNodes() ------------------------------------------------------------------------------------- WHcoord WHtree::getCoordinate4leaf( const size_t leafID ) const { if( leafID >= m_coordinates.size() ) { std::cerr << "ERROR @ WHtree::coordinate4leaf(): leafID is out of boundaries" << std::endl; return WHcoord( 0, 0, 0 ); } else { return m_coordinates[leafID]; } } // end getCoordinate4leaf() ------------------------------------------------------------------------------------- std::vector WHtree::getCoordinates4node( const size_t nodeID ) const { std::vector returnVector; std::vector containedLeaves( getLeaves4node( nodeID ) ); for( std::vector::const_iterator iter( containedLeaves.begin() ); iter != containedLeaves.end(); ++iter ) { returnVector.push_back( getCoordinate4leaf( *iter ) ); } return returnVector; } // end getCoordinates4node() ------------------------------------------------------------------------------------- std::vector WHtree::getCoordinates4node( const nodeID_t &nodeID ) const { if( nodeID.first ) { return getCoordinates4node( nodeID.second ); } else { return std::vector( 1, getCoordinate4leaf( nodeID.second ) ); } } // end getCoordinates4node() ------------------------------------------------------------------------------------- WHcoord WHtree::getMeanCoordinate4node( const size_t nodeID ) const { WHcoord baseCoord; { std::vector bnCoords( getCoordinates4node( nodeID ) ); size_t sumX( 0 ), sumY( 0 ), sumZ( 0 ); for( std::vector::const_iterator coordIter( bnCoords.begin() ); coordIter != bnCoords.end(); ++coordIter ) { sumX += coordIter->m_x; sumY += coordIter->m_y; sumZ += coordIter->m_z; } baseCoord.m_x = sumX/bnCoords.size(); baseCoord.m_y = sumY/bnCoords.size(); baseCoord.m_z = sumZ/bnCoords.size(); } return baseCoord; } // end getMeanCoordinate4node() ------------------------------------------------------------------------------------- WHcoord WHtree::getMeanCoordinate4node( const nodeID_t &nodeID ) const { if( nodeID.first ) { return getMeanCoordinate4node( nodeID.second ); } else { return getCoordinate4leaf( nodeID.second ); } } // end getMeanCoordinate4node() ------------------------------------------------------------------------------------- size_t WHtree::getCommonAncestor( const size_t nodeID1, const size_t nodeID2 ) const { if( nodeID1 == nodeID2 ) { return nodeID1; } else { size_t tempID1( getNode( nodeID1 ).getID() ), tempID2( getNode( nodeID2 ).getID() ); while( tempID1 != tempID2 ) { if( tempID1 < tempID2 ) // node 1 is lower in the hierarchy { tempID1 = ( getNode( tempID1 ).getParent() ).second; } else // seed 2 is is lower in the hierarchy { tempID2 = ( getNode( tempID2 ).getParent() ).second; } } return tempID1; } } // end hTree::getCommonAncestor() ------------------------------------------------------------------------------------- nodeID_t WHtree::getCommonAncestor( const nodeID_t &nodeID1, const nodeID_t &nodeID2 ) const { if( nodeID1 == nodeID2 ) { return nodeID1; } else { size_t node1, node2; if( !nodeID1.first ) // its a leaf { node1 = ( getLeaf( nodeID1.second ).getParent() ).second; } else { node1 = ( nodeID1.second ); } if( !nodeID2.first ) // its a leaf { node2 = ( getLeaf( nodeID2.second ).getParent() ).second; } else { node2 = ( nodeID2.second ); } return std::make_pair( true, getCommonAncestor( node1, node2 ) ); } } // end hTree::getCommonAncestor() ------------------------------------------------------------------------------------- std::vector WHtree::getRoute2Root( const nodeID_t &nodeID ) const { std::vector returnVector; if( ( nodeID.first ) && ( nodeID.second >= m_nodes.size() ) ) { std::cerr << "ERROR @ WHtree::route2Root(): leafID is out of boundaries" << std::endl; return returnVector; } const WHnode& root( getRoot() ); const WHnode* current( &getNode( nodeID ) ); returnVector.reserve( root.getHLevel() - current->getHLevel() ); returnVector.push_back( nodeID ); while( !current->isRoot() ) { current = &getNode( current->getParent() ); returnVector.push_back( current->getFullID() ); } return returnVector; } // end hTree::getRoute2Root() ------------------------------------------------------------------------------------- unsigned int WHtree::getTripletOrder( const nodeID_t &nodeIDa, const nodeID_t &nodeIDb, const nodeID_t &nodeIDc ) const { //0="non resolved" (a,b,c join same parent), 1="ab before c", 2="ac before b", 3="bc before a" nodeID_t ancestorAB( getCommonAncestor( nodeIDa, nodeIDb ) ); nodeID_t ancestorAC( getCommonAncestor( nodeIDa, nodeIDc ) ); nodeID_t ancestorBC( getCommonAncestor( nodeIDb, nodeIDc ) ); if( ancestorAB == ancestorAC ) { if( ancestorAB == ancestorBC ) { return 0; // all join toghether } else { return 3; // a is the last to join } } else if( ancestorAB == ancestorBC ) { return 2; // b is the last to join } else { return 1; // c is the last to join } } // end hTree::getTripletOrder() ------------------------------------------------------------------------------------- std::vector WHtree::getBaseNodes( const size_t root ) const { if( root > getRoot().getID() ) { std::cerr << "ERROR @ WHtree::getBaseNodes(): branch root ID is out of boundaries (ID: " << root << ", # nodes: " << getNumNodes() << ")." << std::endl; return std::vector (); } std::list baseList; for( std::vector::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter ) { baseList.push_back( ( leafIter->getParent() ).second ); } baseList.sort(); baseList.unique(); std::vector returnVector; if( root != getRoot().getID() ) { for( std::list::iterator listIter( baseList.begin() ); listIter != baseList.end(); ++listIter ) { const WHnode* current( &getNode( *listIter ) ); while( !current->isRoot() ) { if( current->getID() ==root ) { returnVector.push_back( getNode( *listIter ).getID() ); break; } current = &getNode( current->getParent() ); } } } else { for( std::list::const_iterator baseIter( baseList.begin() ); baseIter != baseList.end(); ++baseIter ) { returnVector.push_back( *baseIter ); } } return returnVector; } // end getBaseNodes() ------------------------------------------------------------------------------------- std::vector WHtree::getBaseNodes( const nodeID_t &root ) const { std::vector returnVector; if( !root.first ) // if its a leaf { return std::vector(); } else { std::vector bases( getBaseNodes( root.second ) ); for( size_t i = 0; i < bases.size(); ++i ) { returnVector.push_back( std::make_pair( true, bases[i] ) ); } return returnVector; } } // end getBaseNodes() ------------------------------------------------------------------------------------- std::vector WHtree::getRootBaseNodes() const { return getBaseNodes( getRoot().getID() ); } // end getRootBaseNodes() ------------------------------------------------------------------------------------- bool WHtree::testRootBaseNodes() const { std::vector bases( getRootBaseNodes() ); for( size_t i = 0; i < bases.size(); ++i ) { if( getNode( bases[i] ).getHLevel() > 1 ) { return false; } } return true; } // end testRootBaseNodes() ------------------------------------------------------------------------------------- dist_t WHtree::getDistance( const size_t nodeID1, const size_t nodeID2 ) const { size_t ancestor( getCommonAncestor( nodeID1, nodeID2 ) ); return getNode( ancestor ).getDistLevel(); } // end hTree::getNodeDistance() ------------------------------------------------------------------------------------- dist_t WHtree::getDistance( const nodeID_t &nodeID1, const nodeID_t &nodeID2 ) const { nodeID_t ancestor( getCommonAncestor( nodeID1, nodeID2 ) ); return getNode( ancestor ).getDistLevel(); } // end hTree::getDistance() ------------------------------------------------------------------------------------- dist_t WHtree::getDistance( const WHcoord &coord1, const WHcoord &coord2 ) const { nodeID_t nodeID1( std::make_pair( false, getLeafID( coord1 ) ) ); nodeID_t nodeID2( std::make_pair( false, getLeafID( coord2 ) ) ); return getDistance( nodeID1, nodeID2 ); } // end hTree::distance() ------------------------------------------------------------------------------------- dist_t WHtree::getLeafDistance( const size_t leafID1, const size_t leafID2 ) const { nodeID_t ancestor( getCommonAncestor( std::make_pair( false, leafID1 ), std::make_pair( false, leafID2 ) ) ); return getNode( ancestor ).getDistLevel(); } // end hTree::getLeafDistance() ------------------------------------------------------------------------------------- void WHtree::sortBySize( std::vector* nodeVector ) const { std::vector &nodeVectorRef( *nodeVector ); for( size_t i = 0; i < nodeVectorRef.size(); ++i ) { if( nodeVectorRef[i] >= getNumNodes() ) { std::cerr << "ERROR @ WHtree::sortBySize(): indices out of bounds (" << nodeVectorRef[i]; std::cerr << ". total nodes: " << getNumNodes() << ")" << std::endl; return; } } std::sort( nodeVectorRef.begin(), nodeVectorRef.end(), compSize( this ) ); return; } // end sortBySize() ------------------------------------------------------------------------------------- void WHtree::sortBySize( std::list* nodeList ) const { std::list &nodeListRef( *nodeList ); for( std::list::const_iterator iter = nodeListRef.begin(); iter != nodeListRef.end(); ++iter ) { if( *iter >= getNumNodes() ) { std::cerr << "ERROR @ WHtree::sortBySize(): indices out of bounds (" << *iter << ". total nodes: " << getNumNodes() << ")" << std::endl; return; } } nodeListRef.sort( compSize( this ) ); return; } // end sortBySize() ------------------------------------------------------------------------------------- void WHtree::sortBySize( std::vector* nodeVector ) const { std::vector &nodeVectorRef( *nodeVector ); for( size_t i = 0; i < nodeVectorRef.size(); ++i ) { if( ( nodeVectorRef[i].first && nodeVectorRef[i].second >= getNumNodes() ) || ( !nodeVectorRef[i].first && nodeVectorRef[i].second >= getNumLeaves() ) ) { std::cerr << "ERROR @ WHtree::sortBySize(): indices out of bounds(" << nodeVectorRef[i].first << "-" << nodeVectorRef[i].second << ". total leaves: " << getNumLeaves() << ". total nodes: " << getNumNodes() << ")" << std::endl; return; } } std::sort( nodeVectorRef.begin(), nodeVectorRef.end(), compSize( this ) ); return; } // end sortBySize() ------------------------------------------------------------------------------------- void WHtree::sortBySize( std::list* nodeList ) const { std::list &nodeListRef( *nodeList ); for( std::list::const_iterator iter = nodeListRef.begin(); iter != nodeListRef.end(); ++iter ) { if( ( iter->first && iter->second >= getNumNodes() ) || ( !iter->first && iter->second >= getNumLeaves() ) ) { std::cerr << "ERROR @ WHtree::sortBySize(): indices out of bounds(" << iter->first << "-" << iter->second << ". total leaves: " << getNumLeaves() << ". total nodes: " << getNumNodes() << ")" << std::endl; return; } } nodeListRef.sort( compSize( this ) ); return; } // end sortBySize() ------------------------------------------------------------------------------------- void WHtree::sortByHLevel( std::vector* nodeVector ) const { std::sort( nodeVector->begin(), nodeVector->end(), compHLevel( this ) ); return; } // end sortByHLevel() ------------------------------------------------------------------------------------- void WHtree::sortByHLevel( std::vector* nodeVector ) const { std::sort( nodeVector->begin(), nodeVector->end(), compHLevel( this ) ); return; } // end sortByHLevel() ------------------------------------------------------------------------------------- void WHtree::sortByHLevel( std::list* nodeList ) const { nodeList->sort( compHLevel( this ) ); return; } // end sortByHLevel() ------------------------------------------------------------------------------------- void WHtree::sortByHLevel( std::list* nodeList ) const { nodeList->sort( compHLevel( this ) ); return; } // end sortByHLevel() ------------------------------------------------------------------------------------- void WHtree::loadContainedLeaves() { std::vector emptyVect; m_containedLeaves.resize( m_nodes.size(), emptyVect ); for( std::vector::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter ) { nodeID_t thisParent( leafIter->getParent() ); m_containedLeaves[thisParent.second].push_back( leafIter->getID() ); } for( std::vector::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter ) { std::sort( m_containedLeaves[nodeIter->getID()].begin(), m_containedLeaves[nodeIter->getID()].end() ); if( !nodeIter->isRoot() ) { m_containedLeaves[nodeIter->getParent().second].insert( m_containedLeaves[nodeIter->getParent().second].end(), m_containedLeaves[nodeIter->getID()].begin(), m_containedLeaves[nodeIter->getID()].end() ); } } } // end loadContainedLeaves() ------------------------------------------------------------------------------------- void WHtree::clearContainedLeaves() { std::vector > emptyThing; m_containedLeaves.swap( emptyThing ); } // end clearContainedLeaves() ------------------------------------------------------------------------------------- bool WHtree::convert2grid( const HC_GRID newGrid ) { if( m_datasetGrid == newGrid ) { return false; } else if( m_datasetGrid == HC_VISTA && newGrid == HC_NIFTI ) { for( std::vector::iterator iter( m_coordinates.begin() ); iter != m_coordinates.end(); ++iter ) { WHcoord tempCoord = *iter; *iter = tempCoord.vista2nifti( m_datasetSize ); } for( std::list::iterator iter( m_discarded.begin() ); iter != m_discarded.end(); ++iter ) { WHcoord tempCoord = *iter; *iter = tempCoord.vista2nifti( m_datasetSize ); } m_datasetGrid = HC_NIFTI; return true; } else if( m_datasetGrid == HC_NIFTI && newGrid == HC_VISTA ) { for( std::vector::iterator iter( m_coordinates.begin() ); iter != m_coordinates.end(); ++iter ) { WHcoord tempCoord = *iter; *iter = tempCoord.nifti2vista( m_datasetSize ); } for( std::list::iterator iter( m_discarded.begin() ); iter != m_discarded.end(); ++iter ) { WHcoord tempCoord=*iter; *iter = tempCoord.nifti2vista( m_datasetSize ); } m_datasetGrid = HC_VISTA; return true; } else { std::cerr << "ERROR @ WHtree::convert2grid(): coordinate grid not recognized" << std::endl; return false; } } // end convert2grid() ------------------------------------------------------------------------------------- bool WHtree::readTree( const std::string &filename ) { m_nodes.clear(); m_leaves.clear(); m_coordinates.clear(); m_trackids.clear(); m_discarded.clear(); WFileParser parser( filename ); if( !parser.readFile() ) { std::cerr << "ERROR @ WHtree::readTree(): Parser error" << std::endl; return false; } std::vector lines = parser.getRawLines(); if( lines.size() == 0 ) { std::cerr << "ERROR @ WHtree::readTree(): File is empty" << std::endl; return false; } { std::vector< std::vector< std::string> >datasetStrings = parser.getLinesForTagSeparated( "imagesize" ); if( datasetStrings.size() == 0 ) { std::cerr << "ERROR @ WHtree::readTree(): Dataset size was not found in tree file" << std::endl; return false; } if( datasetStrings.size() > 1 ) { std::cerr << "ERROR @ WHtree::readTree(): Dataset attribute had multiple lines" << std::endl; return false; } WHcoord datasetSize( string_utils::fromString( datasetStrings[0][0] ), string_utils::fromString( datasetStrings[0][1] ), string_utils::fromString( datasetStrings[0][2] ) ); std::string gridString( datasetStrings[0][3] ); if( gridString == getGridString( HC_VISTA ) ) { m_datasetGrid = HC_VISTA; } else if( gridString == getGridString( HC_NIFTI ) ) { m_datasetGrid = HC_NIFTI; } else { std::cerr << "ERROR @ WHtree::readTree(): Dataset grid type string \"" << gridString << "\" could not be identified" << std::endl; return false; } m_datasetSize = datasetSize; } { std::vector< std::vector< std::string > > streamNumberStrings = parser.getLinesForTagSeparated( "streams" ); if( streamNumberStrings.size() == 0 ) { std::cerr << "WARNING @ WHtree::readTree(): tracking streams number was not found in tree file,"; std::cerr << " assuming streams=0 for compatibility" << std::endl; m_numStreamlines = 0; } if( streamNumberStrings.size() > 1 ) { std::cerr << "ERROR @ WHtree::readTree(): tracking streams number attribute has multiple lines" << std::endl; return false; } if( streamNumberStrings[0].size() > 1 ) { std::cerr << "ERROR @ WHtree::readTree(): tracking streams number attribute has multiple elements" << std::endl; return false; } m_numStreamlines = string_utils::fromString< size_t >( streamNumberStrings[0][0] ); } { std::vector< std::vector< std::string > >logFactorStrings = parser.getLinesForTagSeparated( "logfactor" ); if( logFactorStrings.size() == 0 ) { std::cerr << "WARNING @ WHtree::readTree(): logarithmic normalization factor was not found in tree file,"; std::cerr << " assuming logFactor=0 for compatibility" << std::endl; m_logFactor = 0; } if( logFactorStrings.size() > 1 ) { std::cerr << "ERROR @ WHtree::readTree():"; std::cerr << "logarithmic normalization factor attribute has multiple lines" << std::endl; return false; } if( logFactorStrings[0].size() > 1 ) { std::cerr << "ERROR @ WHtree::readTree(): logarithmic normalization factor attribute has multiple elements" << std::endl; return false; } m_logFactor = string_utils::fromString< float >( logFactorStrings[0][0] ); if( m_logFactor != 0 && m_numStreamlines != 0 && m_logFactor != log10( m_numStreamlines ) ) { std::cerr << "ERROR @ WHtree::readTree(): tracking streams number ("; std::cerr << m_numStreamlines << ") and logarithmic normalization factor ("; std::cerr << m_logFactor << ") are a missmatch " << std::endl; return false; } } { std::vector< std::vector< std::string> >coordStrings = parser.getLinesForTagSeparated( "coordinates" ); m_coordinates.reserve( coordStrings.size() ); m_leaves.reserve( coordStrings.size() ); size_t leafCount( 0 ); for( size_t i = 0; i < coordStrings.size(); ++i ) { WHcoord tempCoord( string_utils::fromString( coordStrings[i][0] ), string_utils::fromString( coordStrings[i][1] ), string_utils::fromString( coordStrings[i][2] ) ); WHnode tempNode( std::make_pair( 0, leafCount ) ); m_leaves.push_back( tempNode ); m_coordinates.push_back( tempCoord ); ++leafCount; } } { std::vector< std::vector< std::string > > indexStrings = parser.getLinesForTagSeparated( "trackindex" ); if( indexStrings.empty() ) { if( m_datasetGrid == HC_NIFTI ) { std::cerr << "ERROR @ WHtree::readTree(): no tract ids in roi file, necessary to work on nifti mode" << std::endl; return false; } else { m_trackids.reserve( m_coordinates.size() ); for( size_t i = 0; i < m_coordinates.size(); ++i ) { m_trackids.push_back( i ); } } } else { m_trackids.reserve( indexStrings.size() ); for( size_t i = 0; i < indexStrings.size(); ++i ) { size_t tempIndex( string_utils::fromString< size_t >( indexStrings[i][0] ) ); m_trackids.push_back( tempIndex ); } } } { std::vector< std::vector< std::string> >clusterStrings = parser.getLinesForTagSeparated( "clusters" ); m_nodes.reserve( clusterStrings.size() ); size_t nodeCount( 0 ); for( size_t i = 0; i < clusterStrings.size(); ++i ) { dist_t distance( string_utils::fromString< dist_t > ( clusterStrings[i][0] ) ); std::vectorjoiningNodes; for( size_t j = 1; j < clusterStrings[i].size(); j += 2 ) { joiningNodes.push_back( std::make_pair( string_utils::fromString( clusterStrings[i][j] ), string_utils::fromString( clusterStrings[i][j+1] ) ) ); } size_t tempSize( 0 ), tempHLevel( 0 ); nodeID_t tempID( std::make_pair( 1, nodeCount ) ); for( std::vector::const_iterator iter( joiningNodes.begin() ); iter != joiningNodes.end(); ++iter) { WHnode* kid( fetchNode( *iter ) ); if( kid == 0 ) { std::cerr << "ERROR @ WHtree::readTree(): kid id (" << iter->first << "-" << iter->second << ") was out of boundaries. Nodes: " << m_nodes.size() << std::endl; return false; } tempSize += kid->getSize(); tempHLevel = std::max( tempHLevel, kid->getHLevel() ); kid->setParent( tempID ); } ++tempHLevel; WHnode tempNode( tempID, joiningNodes, tempSize, distance, tempHLevel ); //std::cout << tempNode.printAllData() << std::endl; m_nodes.push_back( tempNode ); ++nodeCount; } } { std::vector< std::vector< std::string> >discardedStrings = parser.getLinesForTagSeparated( "discarded" ); for( size_t i = 0; i < discardedStrings.size(); ++i ) { WHcoord tempCoord( string_utils::fromString( discardedStrings[i][0] ), string_utils::fromString( discardedStrings[i][1] ), string_utils::fromString( discardedStrings[i][2] ) ); m_discarded.push_back( tempCoord ); } m_discarded.sort(); } { std::vector< std::vector< std::string> >cpccStrings = parser.getLinesForTagSeparated( "cpcc" ); if( !cpccStrings.empty() ) { if( cpccStrings.size() > 1 || cpccStrings[0].size() > 1 ) { std::cerr << "ERROR @ WHtree::readTree(): multiple objects on cpcc attribute" << std::endl; return false; } m_cpcc = string_utils::fromString( cpccStrings[0][0] ); } } { m_selectedValues.clear(); m_selectedPartitions.clear(); std::vector< std::vector< std::string> >partValueStrings = parser.getLinesForTagSeparated( "partvalues" ); if( !partValueStrings.empty() ) { m_selectedValues.reserve( partValueStrings.size() ); for( size_t i = 0; i < partValueStrings.size(); ++i ) { float value( string_utils::fromString< float > ( partValueStrings[i][0] ) ); m_selectedValues.push_back( value ); } } std::vector< std::vector< std::string> >partitionStrings = parser.getLinesForTagSeparated( "partitions" ); if( !partitionStrings.empty() ) { m_selectedPartitions.reserve( partitionStrings.size() ); for( size_t i = 0; i < partitionStrings.size(); ++i ) { std::vector< size_t > thisPartition; thisPartition.reserve( partitionStrings[i].size() ); for( size_t j = 0; j < partitionStrings[i].size(); ++j ) { size_t partCluster( string_utils::fromString< size_t > ( partitionStrings[i][j] ) ); thisPartition.push_back( partCluster ); } m_selectedPartitions.push_back( thisPartition ); } } std::vector< std::vector< std::string > >partcolorStrings = parser.getLinesForTagSeparated( "partcolors" ); if( !partcolorStrings.empty() ) { m_selectedColors.reserve( partcolorStrings.size() ); for( size_t i = 0; i < partcolorStrings.size(); ++i ) { std::vector< WHcoord > thisPartColors; thisPartColors.reserve( partcolorStrings[i].size() ); for( size_t j = 0; j < partcolorStrings[i].size(); ++j ) { std::string thisCoordstring( partcolorStrings[i][j] ); if( thisCoordstring.size() != 11 ) { std::cerr << "ERROR @ WHtree::readTree(): partition colors have wrong size (" << thisCoordstring.size(); std::cerr << ") while it should be 11. string: " << thisCoordstring << std::endl; m_selectedColors.clear(); break; } std::string colorR( thisCoordstring.substr( 0, 3 ) ); std::string colorG( thisCoordstring.substr( 4, 3 ) ); std::string colorB( thisCoordstring.substr( 8, 3 ) ); WHcoord thisColor( string_utils::fromString< coord_t > ( colorR ), string_utils::fromString< coord_t > ( colorG ), string_utils::fromString< coord_t > ( colorB ) ); thisPartColors.push_back( thisColor ); } m_selectedColors.push_back( thisPartColors ); } } if( m_selectedColors.size() != 0 ) { if( m_selectedColors.size() != m_selectedPartitions.size() ) { std::cerr << "ERROR @ WHtree::readTree(): partition and colors dimensions dont match. Color field will be left empty" << std::endl; m_selectedColors.clear(); } else { for( size_t i = 0; i < m_selectedColors.size(); ++i ) { if( m_selectedColors[i].size() != m_selectedPartitions[i].size() ) { std::cerr << "ERROR @ WHtree::readTree(): partition and colors dimensions dont match."; std::cerr << " Color field will be left empty" << std::endl; m_selectedColors.clear(); break; } } } } if( m_selectedPartitions.size() != m_selectedValues.size() ) { std::cerr << "ERROR @ WHtree::readTree(): partition and value dimensions dont match. Fields will be left empty" << std::endl; clearPartitions(); } } if( !check() ) { std::cerr << "ERROR @ WHtree::readTree(): loaded tree is not consistent" << std::endl; return false; } #if NEWBOOST m_treeName = boost::filesystem::path( filename ).stem().string(); #else m_treeName = boost::filesystem::path( filename ).stem(); #endif m_loadStatus = true; return true; } // end readTree() ------------------------------------------------------------------------------------- bool WHtree::writeTree( const std::string &filename, const bool niftiMode ) const { std::ofstream outFile( filename.c_str() ); if( !outFile ) { std::cerr << "ERROR: unable to open out file: \"" << filename << "\"" << std::endl; exit( -1 ); } std::string gridString; if( niftiMode ) { gridString = getGridString( HC_NIFTI ); } else { gridString = getGridString( HC_VISTA ); } outFile << "#imagesize" << std::endl << m_datasetSize << " " << gridString << std::endl << "#endimagesize" << std::endl; outFile << std::endl; if( m_cpcc != 0 ) { outFile << "#cpcc" << std::endl << string_utils::toString( m_cpcc ) << std::endl << "#endcpcc" << std::endl << std::endl; } outFile << "#streams" << std::endl << m_numStreamlines << std::endl << "#endstreams" << std::endl; outFile << "#logfactor" << std::endl << m_logFactor << std::endl << "#endlogfactor" << std::endl; outFile << "#coordinates" << std::endl; for( std::vector::const_iterator coordIter( m_coordinates.begin() ) ; coordIter != m_coordinates.end() ; ++coordIter ) { WHcoord currentCoord( *coordIter ); if( niftiMode ) { if( m_datasetGrid == HC_VISTA ) { currentCoord = currentCoord.vista2nifti( m_datasetSize ); } } else { if( m_datasetGrid == HC_NIFTI ) { currentCoord = currentCoord.nifti2vista( m_datasetSize ); } } outFile << currentCoord << std::endl; } outFile << "#endcoordinates" << std::endl << std::endl; outFile << "#trackindex" << std::endl; for( std::vector::const_iterator indexIter( m_trackids.begin() ) ; indexIter != m_trackids.end() ; ++indexIter ) { outFile << *indexIter << std::endl; } outFile << "#endtrackindex" << std::endl << std::endl; outFile << "#clusters" << std::endl; for( std::vector::const_iterator nodeIter( m_nodes.begin() ) ; nodeIter != m_nodes.end() ; ++nodeIter ) { outFile << *nodeIter << std::endl; } outFile << "#endclusters" << std::endl << std::endl; outFile << "#discarded" << std::endl; for( std::list::const_iterator coordIter( m_discarded.begin() ) ; coordIter != m_discarded.end() ; ++coordIter ) { WHcoord currentCoord( *coordIter ); if( niftiMode ) { if( m_datasetGrid == HC_VISTA ) { currentCoord = currentCoord.vista2nifti( m_datasetSize ); } } else { if( m_datasetGrid == HC_NIFTI ) { currentCoord = currentCoord.nifti2vista( m_datasetSize ); } } outFile << currentCoord << std::endl; } outFile << "#enddiscarded" << std::endl; if( m_selectedValues.size() !=0 ) { outFile << std::endl << "#partvalues" << std::endl; for( size_t i = 0; i < m_selectedValues.size(); ++i ) { outFile << m_selectedValues[i] << std::endl; } outFile << "#endpartvalues" << std::endl; outFile << std::endl << "#partitions" << std::endl; for( size_t i = 0; i < m_selectedPartitions.size(); ++i ) { for( size_t j = 0; j < m_selectedPartitions[i].size(); ++j ) { outFile <::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter ) { WHcoord currentCoord( getCoordinate4leaf( leafIter->getID() ) ); outFile << "Coord: " << currentCoord << " " << leafIter->printAllData() << std::endl; } outFile << std::endl << std::endl << "============NODES============" << std::endl << std::endl; for( std::vector::const_iterator nodeIter( m_nodes.begin() ) ; nodeIter != m_nodes.end() ; ++nodeIter ) { outFile << nodeIter->printAllData() << std::endl; } return true; } // end writeTreeDebug() ------------------------------------------------------------------------------------- bool WHtree::writeTreeOldWalnut( const std::string &filename ) const { std::ofstream outFile( filename.c_str() ); if( !outFile ) { std::cerr << "ERROR: unable to open out file: \"" << filename << "\"" << std::endl; exit( -1 ); } outFile << "#coordinates" << std::endl; for( std::vector::const_iterator coordIter( m_coordinates.begin() ) ; coordIter != m_coordinates.end() ; ++coordIter ) { WHcoord currentCoord( *coordIter ); if( m_datasetGrid == HC_VISTA ) { currentCoord = currentCoord.vista2nifti( m_datasetSize ); } outFile << boost::format( "%03d,%03d,%03d\n" ) % currentCoord.m_x % currentCoord.m_y % currentCoord.m_z; } outFile << "#endcoordinates" << std::endl << std::endl; outFile << "#clusters" << std::endl; for( std::vector::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter) { std::vector currentKids( nodeIter->getChildren() ); for( size_t i = 0; i < currentKids.size(); ++i ) { size_t currentID( currentKids[i].second ); if( currentKids[i].first ) { currentID += getNumLeaves(); } outFile << boost::format( "%06d" ) % currentID << "," << std::flush; } outFile << string_utils::toString( nodeIter->getDistLevel() ) << std::endl; } outFile << "#endclusters" << std::endl << std::endl; return true; } // end writeTreeOldWalnut() ------------------------------------------------------------------------------------- bool WHtree::writeTreeSimple( const std::string &filename ) const { std::ofstream outFile( filename.c_str() ); if( !outFile ) { std::cerr << "ERROR: unable to open out file: \"" << filename << "\"" << std::endl; exit( -1 ); } outFile << getNumLeaves() << std::endl; for( std::vector::const_iterator nodeIter( m_nodes.begin() ) ; nodeIter != m_nodes.end() ; ++nodeIter ) { outFile << *nodeIter << std::endl; } return true; } // end writeTreeSimple() ------------------------------------------------------------------------------------- void WHtree::insertPartitions( const std::vector > &selectedPartitions, const std::vector< float > &selectedValues, const std::vector > &selectedColors ) { clearPartitions(); if( selectedPartitions.size() != selectedValues.size() ) { std::cerr << "ERROR @ WHtree::insertPartitions(): inserted partition set and partition value vector have different dimensions" << std::endl; } else { m_selectedPartitions = selectedPartitions; m_selectedValues = selectedValues; } if( !selectedColors.empty() ) { if( selectedColors.size() != selectedPartitions.size() ) { std::cerr << "ERROR @ WHtree::insertPartitions(): inserted partition color set and partition set have different dimensions" << std::endl; } else { for( size_t i = 0; i < selectedColors.size(); ++i ) { if( selectedColors[i].size() != selectedPartitions[i].size() ) { std::cerr << "ERROR @ WHtree::insertPartitions(): partition and colors dimensions dont match"; std::cerr << " (" << selectedPartitions[i].size() << "-" << selectedColors[i].size(); std::cerr << ") Color field will be left empty" << std::endl; return; } } m_selectedColors = selectedColors; } } return; } // end insertPartitions() ------------------------------------------------------------------------------------- void WHtree::insertPartColors( const std::vector > &selectedColors ) { if( selectedColors.size() != m_selectedPartitions.size() ) { std::cerr << "ERROR @ WHtree::insertPartColors(): inserted partition color set and partition set have different dimensions" << std::endl; } else { for( size_t i = 0; i < selectedColors.size(); ++i ) { if( selectedColors[i].size() != m_selectedPartitions[i].size() ) { std::cerr << "ERROR @ WHtree::insertPartColors(): partition and colors dimensions dont match."; std::cerr << " Color field will be left empty" << std::endl; clearPartColors(); return; } } m_selectedColors = selectedColors; } return; } // end insertPartColors() ------------------------------------------------------------------------------------- void WHtree::clearPartitions() { std::vector > empty1; std::vector< float > empty2; std::vector > empty3; m_selectedPartitions.swap( empty1 ); m_selectedValues.swap( empty2 ); m_selectedColors.swap( empty3 ); return; } // end clearPartitions() ------------------------------------------------------------------------------------- void WHtree::clearPartColors() { std::vector > empty; m_selectedColors.swap( empty ); return; } // end clearPartColors() ------------------------------------------------------------------------------------- std::vector< std::vector< unsigned int > > WHtree::getBranching( const std::vector < nodeID_t > &thisPartition, size_t depthLevel, std::vector< std::vector < nodeID_t > > *partitionSet, const bool excludeLeaves ) { if( depthLevel == 0 ) { return std::vector< std::vector< unsigned int > >(); } std::vector< std::vector < nodeID_t > > addedPartitionSet; std::vector< std::vector< unsigned int > > addedIndexTable; addedIndexTable.reserve( thisPartition.size() ); addedPartitionSet.reserve( thisPartition.size() ); for( size_t i = 0; i < thisPartition.size(); ++i) { // if its a base node and flag is set not to divide them, skip if( getNode( thisPartition[i] ).getHLevel() == 1 && excludeLeaves) { continue; } // get branched sub/partition for every cluster std::vector branch; { std::vector kids( getNode( thisPartition[i] ).getChildren() ); branch.reserve( kids.size() ); for( size_t j = 0; j < kids.size(); ++j) { branch.push_back( kids[j] ); } } // insert branched partition { std::vector < nodeID_t > newPartition( thisPartition ); newPartition.erase( newPartition.begin()+i ); newPartition.insert( newPartition.begin()+i, branch.begin(), branch.end() ); addedPartitionSet.push_back( newPartition ); addedIndexTable.push_back( std::vector( 1, i ) ); } // obtain further sub-partitions if depth level continues if( depthLevel > 1 ) { std::vector< std::vector < nodeID_t > > subPartitionSet; std::vector< std::vector< unsigned int > > subIndexTable( getBranching( branch, depthLevel-1, &subPartitionSet, excludeLeaves ) ); addedPartitionSet.reserve( addedPartitionSet.size() + subPartitionSet.size() ); addedIndexTable.reserve( addedPartitionSet.size() + subPartitionSet.size() ); if( subPartitionSet.size() != subIndexTable.size() ) { throw std::runtime_error( "ERROR @ WHtree::getBranching(): dimension error on obtained vectors" ); } for( size_t j = 0; j < subIndexTable.size(); ++j) { std::vector < nodeID_t > newPartition( thisPartition ); newPartition.erase( newPartition.begin()+i ); newPartition.insert( newPartition.begin()+i, subPartitionSet[j].begin(), subPartitionSet[j].end() ); addedPartitionSet.push_back( newPartition ); std::vector< unsigned int > newIndexEntry( 1, i ); newIndexEntry.insert( newIndexEntry.end(), subIndexTable[j].begin(), subIndexTable[j].end() ); addedIndexTable.push_back( newIndexEntry ); } } } //end for loop // add the obtained partitions to the vector partitionSet->insert( partitionSet->end(), addedPartitionSet.begin(), addedPartitionSet.end() ); return addedIndexTable; } // end getBranching() ------------------------------------------------------------------------------------- std::vector< std::vector< unsigned int > > WHtree::getBranching( const std::vector < size_t > &thisPartition, size_t depthLevel, std::vector< std::vector < size_t > > *partitionSet ) { if( !partitionSet->empty() ) { throw std::runtime_error( "ERROR @ WHtree::getBranching(): partition set wasnt empty" ); } std::vector partFullId; std::vector< std::vector < nodeID_t > > partitionFullIdSet; partFullId.reserve( thisPartition.size() ); for( size_t i = 0; i < thisPartition.size(); ++i ) { partFullId.push_back( std::make_pair( true, thisPartition[i] ) ); } std::vector< std::vector< unsigned int > > indexTable( getBranching( partFullId, depthLevel, &partitionFullIdSet, true ) ); partitionSet->reserve( partitionFullIdSet.size() ); for( size_t i = 0; i < partitionFullIdSet.size(); ++i ) { std::vector thisSet; thisSet.reserve( partitionFullIdSet[i].size() ); for( size_t j = 0; j < partitionFullIdSet[i].size(); ++j ) { if( partitionFullIdSet[i][j].first) { thisSet.push_back( partitionFullIdSet[i][j].second ); } else { std::cerr << "WARNING @ WHtree::getBranching(), leaves were returned" << std::endl; } } partitionSet->push_back( thisSet ); } return indexTable; } // === PRIVATE MEMBER FUNCTIONS === WHnode* WHtree::fetchNode( const size_t thisNode ) { if( thisNode >= m_nodes.size() ) { return 0; } else { return &( m_nodes[thisNode] ); } } // end fetchNode() ------------------------------------------------------------------------------------- WHnode* WHtree::fetchNode( const nodeID_t &thisNode ) { if( thisNode.first ) { return fetchNode( thisNode.second ); } else { return fetchLeaf( thisNode.second ); } } // end fetchNode() ------------------------------------------------------------------------------------- WHnode* WHtree::fetchLeaf( const size_t thisLeaf ) { if( thisLeaf >= m_leaves.size() ) { return 0; } else { return &( m_leaves[thisLeaf] ); } } // end fetchLeaf() ------------------------------------------------------------------------------------- WHnode* WHtree::fetchRoot() { return fetchNode( getNumNodes()-1 ); } // end fetchRoot() ------------------------------------------------------------------------------------- std::pair WHtree::cleanup( std::vector *outLookup ) { //finish setting pruning flags on unnecessary nodes //reset nodes size and for( std::vector::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter ) { nodesIter->setSize( 0 ); nodesIter->setHLevel( 0 ); } //initialize base nodes size for( std::vector::const_iterator leavesIter( m_leaves.begin() ); leavesIter != m_leaves.end(); ++leavesIter ) { WHnode *parentNode( fetchNode( leavesIter->getParent() ) ); size_t currentSize( parentNode->getSize() ); if( !( leavesIter->isFlagged() ) ) { // leaf will not be pruned parentNode->setSize( currentSize+1 ); parentNode->setHLevel( 1 ); } } //initialize remaining nodes for( std::vector::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end()-1; ++nodesIter ) { WHnode *parentNode( fetchNode( nodesIter->getParent() ) ); size_t currentNodeSize( nodesIter->getSize() ); size_t currentPapaSize( parentNode->getSize() ); parentNode->setSize( currentPapaSize + currentNodeSize ); if( currentNodeSize < 2 ) { // if a node has less than 2 leaves it is unnecesary in a hierarchical tree, so in that case the prune bit must be set too nodesIter->setFlag( true ); if( currentNodeSize > 0 ) { parentNode->setHLevel( nodesIter->getHLevel() ); } } else { parentNode->setHLevel( std::max( parentNode->getHLevel(), nodesIter->getHLevel()+1 ) ); } } // loop through nodes and check that there are no hanging nodes ( nodes with one or no children) without structural function for( std::vector::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter ) { size_t numNewKids( 0 ); std::vector kids( nodesIter->getChildren() ); for( std::vector::iterator kidsIter( kids.begin() ); kidsIter != kids.end(); ++kidsIter ) { if( fetchNode( *kidsIter )->isLeaf() ) { if( !( getNode( *kidsIter ).isFlagged() ) ) { ++numNewKids; } } else { if( ( getNode( *kidsIter ).getHLevel() ) != 0 ) { ++numNewKids; } } } if( numNewKids <= 1 ) { nodesIter->setFlag( true ); } } // create new IDs lookup tables const size_t INVALID( getNumLeaves()+1 ); std::vector lookupLeafID( getNumLeaves(), INVALID ), lookupNodeID( getNumNodes(), INVALID ), lookupParentID( getNumNodes(), INVALID ); size_t leafCounter( 0 ), nodeCounter( 0 ); // new ID counters // loop through leaves and create lookup table for new leaves IDs for( size_t i = 0; i < m_leaves.size(); ++i ) { if( !m_leaves[i].isFlagged() ) { lookupLeafID[i] = leafCounter++; } } // loop through nodes and create lookup table for new nodes IDs for( size_t i = 0; i < m_nodes.size(); ++i ) { if( !m_nodes[i].isFlagged() ) { lookupNodeID[i] = nodeCounter++; } } // loop through nodes and create lookup table for new nodes parent_IDs for( size_t i = 0; i < m_nodes.size(); ++i ) { if( m_nodes[i].isFlagged() ) { const WHnode* searchNode( &getNode( i ) ); while( searchNode->isFlagged() ) // while parents are set to prune, keep going up the tree until a valid node is reached { if( searchNode->isRoot() ) { break; // this was the top node of the tree } searchNode = &getNode( searchNode->getParent() ); } if( searchNode->isRoot() && searchNode->isFlagged() ) { lookupParentID[i] = 0; } else { lookupParentID[i] = lookupNodeID[searchNode->getID()]; } if( lookupParentID[i] == INVALID ) { throw std::runtime_error( "ERROR @ WHtree::cleanup(): error filling new parent ID lookup table" ); } } else { lookupParentID[i] = lookupNodeID[m_nodes[i].getID()]; } } // delete discarded elements from containers // eliminate discarded leaves from the leaves vector and the coordinates vector size_t discardedLeaves( 0 ), discardedNodes( 0 ); std::vector::iterator leavesDelIter( m_leaves.begin() ); std::vector::iterator coordDelIter( m_coordinates.begin() ); while( leavesDelIter != m_leaves.end() ) { if( leavesDelIter->isFlagged() ) { ++discardedLeaves; m_discarded.push_back( *coordDelIter ); leavesDelIter = m_leaves.erase( leavesDelIter ); coordDelIter = m_coordinates.erase( coordDelIter ); } else { ++leavesDelIter; ++coordDelIter; } } // eliminate discarded nodes from the vector std::vector::iterator nodesDelIter( m_nodes.begin() ); while( nodesDelIter != m_nodes.end() ) { if( nodesDelIter->isFlagged() ) { ++discardedNodes; nodesDelIter = m_nodes.erase( nodesDelIter ); } else { ++nodesDelIter; } } // update names of non-discarded elements // loop through leaves and change leaves IDs and Parents IDs for( std::vector::iterator leavesIter( m_leaves.begin() ); leavesIter != m_leaves.end(); ++leavesIter ) { size_t newID( lookupLeafID[leavesIter->getID()] ); size_t newParentID( lookupParentID[leavesIter->getParent().second] ); if( ( newID == INVALID ) || ( newParentID == INVALID ) ) { std::cerr << "Discarded " << discardedLeaves<< " and " << discardedNodes<< " nodes" << std::endl; std::cerr << "Old ID: " << leavesIter->getID() << ". New ID: " << newID<< ". Old parent ID: " << leavesIter->getParent().second << ". New parent ID: " << newParentID << std::endl; throw std::runtime_error( "ERROR @ WHtree::cleanup(): error updating leaf IDs, invalid lookup table value" ); } leavesIter->setID( std::make_pair( false, newID ) ); leavesIter->setParent( std::make_pair( true, newParentID ) ); } // loop through nodes and change names of nodes IDs and parents for( std::vector::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter ) { size_t newID( lookupNodeID[nodesIter->getID()] ); size_t newParentID( 0 ); if( ( nodesIter+1 ) != m_nodes.end() ) { newParentID = ( lookupParentID[nodesIter->getParent().second] ); } std::vector emptyKids; if( ( newID == INVALID) || ( newParentID == INVALID ) ) { throw std::runtime_error( "ERROR @ WHtree::cleanup(): error updating node IDs, invalid lookup table value" ); } if( newParentID == 0 ) // if node is top of the tree parent must be set to 0-0 { if( ( nodesIter+1 ) != m_nodes.end() ) // this should only happen at the last node { std::cerr << std::endl << "Node says its root: " << nodesIter->printAllData() << std::endl; std::cerr << "New ID: " << newID << ". New parent ID: " << newParentID << std::endl; std::cerr << "But last node is: " << ( m_nodes.end()-1 )->printAllData() << std::endl; std::cerr << "New ID: " << lookupNodeID[( m_nodes.end()-1 )->getID()] << std::endl; throw std::runtime_error( "ERROR @ WHtree::cleanup(): pruning failed, top of tree is not last node in vector" ); } nodesIter->setParent( std::make_pair( false, 0 ) ); } else { nodesIter->setParent( std::make_pair( true, newParentID ) ); } nodesIter->setID( std::make_pair( true, newID ) ); nodesIter->setChildren( emptyKids ); nodesIter->setHLevel( 0 ); } // fill up children and hierarchical level data for( std::vector::iterator leavesIter( m_leaves.begin() ); leavesIter != m_leaves.end(); ++leavesIter ) { WHnode *parentNode( fetchNode( leavesIter->getParent() ) ); std::vector currentKids( parentNode->getChildren() ); currentKids.push_back( leavesIter->getFullID() ); parentNode->setChildren( currentKids ); parentNode->setHLevel( 1 ); } for( std::vector::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter ) { if( nodesIter->isRoot() ) { continue; } WHnode *parentNode( fetchNode( nodesIter->getParent() ) ); std::vector currentKids( parentNode->getChildren() ); currentKids.push_back( nodesIter->getFullID() ); parentNode->setChildren( currentKids ); parentNode->setHLevel( std::max( parentNode->getHLevel(), ( nodesIter->getHLevel() )+1 ) ); } // check if final tree is consistent if( !check() ) { throw std::runtime_error( "ERROR @ WHtree::cleanup(): resulting tree is not consistent" ); } if( discardedLeaves != 0 || discardedNodes != 0 ) { m_cpcc = 0; clearPartitions(); } if( outLookup != 0 ) // if a pointer was passed as argument { *outLookup = lookupNodeID; } clearPartitions(); clearPartColors(); return std::make_pair( discardedLeaves, discardedNodes ); } // end cleanup() ------------------------------------------------------------------------------------- size_t WHtree::debinarize( bool keepBaseNodes ) { if( keepBaseNodes && !testRootBaseNodes() ) { std::cerr << "WARNING@ Debinarize: base nodes have mixed nodes and leaves, debinarize will be standard " << std::endl; keepBaseNodes = false; } const size_t origNumNodes( getNumNodes() ); std::vector validNode( getNumNodes(), true ); std::vector > realChildren; realChildren.resize( getNumNodes() ); std::vector realParentsforLeaves( getNumLeaves(), 0 ); std::vector realParentsforNodes( getNumNodes(), 0 ); if( !keepBaseNodes ) { // first loop through leaves for( unsigned int id = 0; id < getNumLeaves(); ++id ) { size_t currentNode( fetchLeaf( id )->getParent().second ); dist_t currentDist( fetchNode( currentNode )->getDistLevel() ); if( fetchNode( currentNode )->isRoot() ) // its parent is the last node { realParentsforLeaves[id] = currentNode; realChildren[currentNode].push_back( std::make_pair( false, id ) ); continue; } size_t nextParent( fetchNode( currentNode )->getParent().second ); dist_t nextDist( fetchNode( nextParent )->getDistLevel() ); while( currentDist == nextDist ) { validNode[currentNode] = false; currentNode = nextParent; currentDist = nextDist; if( fetchNode( nextParent )->isRoot() ) // if we reach the last node we stop { break; } nextParent = fetchNode( currentNode )->getParent().second; nextDist = fetchNode( nextParent )->getDistLevel(); } realParentsforLeaves[id] = currentNode; realChildren[currentNode].push_back( std::make_pair( false, id ) ); } } else { for( unsigned int id = 0; id < getNumLeaves(); ++id ) { size_t currentNode( fetchLeaf( id )->getParent().second ); if( fetchNode( currentNode )->isRoot() ) // its parent is the last node { realParentsforLeaves[id] = currentNode; realChildren[currentNode].push_back( std::make_pair( false, id ) ); continue; } realParentsforLeaves[id] = currentNode; realChildren[currentNode].push_back( std::make_pair( false, id ) ); } } // then loop through nodes for( unsigned int id = 0; id < getNumNodes()-1; ++id ) //we never process the last node (has no parent) { size_t currentNode( fetchNode( id )->getParent().second ); dist_t currentDist( fetchNode( currentNode )->getDistLevel() ); if( fetchNode( currentNode )->isRoot() ) // its parent is the last node { realParentsforNodes[id] = currentNode; if( validNode[id] ) { realChildren[currentNode].push_back( std::make_pair( true, id ) ); } continue; } size_t nextParent( fetchNode( currentNode )->getParent().second ); dist_t nextDist( fetchNode( nextParent )->getDistLevel() ); while( currentDist == nextDist ) { validNode[currentNode] = false; currentNode = nextParent; currentDist = nextDist; if( fetchNode( nextParent )->isRoot() ) // its parent is the last node { break; } nextParent = fetchNode( currentNode )->getParent().second; nextDist = fetchNode( nextParent )->getDistLevel(); } realParentsforNodes[id] = currentNode; if( validNode[id] ) realChildren[currentNode].push_back( std::make_pair( true, id ) ); } realParentsforNodes[getNumNodes()-1 ]= 0; // parent of root node // check validity for( unsigned int i = 0; i < getNumNodes(); ++i ) //we never process the last node (has no parent) { if( validNode[i] && ( realChildren[i].empty() ) ) { std::cerr << "node (1-" << i << ") has no real children" << std::endl; throw std::runtime_error( "ERROR @ WHtree::debinarize(): node has no real children" ); } } // lookuptable to account for id change due to invalid nodes size_t nbCount( 0 ); const size_t invalid( validNode.size()+1 ); std::vector changeLookup( validNode.size(), invalid ); for( size_t i = 0; i < validNode.size(); ++i ) { if( validNode[i] ) { changeLookup[i] = nbCount; ++nbCount; } } //rename real children for( size_t i = 0; i < realChildren.size(); ++i ) { for( size_t j = 0; j < realChildren[i].size(); ++j ) { if( realChildren[i][j].first ) { size_t newName( changeLookup[realChildren[i][j].second] ); if( newName == invalid ) { throw std::runtime_error( "ERROR @ WHtree::debinarize(): error renaming node children" ); } realChildren[i][j].second = newName; } } } // change leaves info for( unsigned int id = 0; id < getNumLeaves(); ++id ) { size_t realDad( changeLookup[realParentsforLeaves[id]] ); if( realDad == invalid ) { throw std::runtime_error( "ERROR @ WHtree::debinarize(): error renaming nb leaf parents" ); } fetchLeaf( id )->setParent( std::make_pair( true, realDad ) ); } { // create new nodes vector std::vector nbNodes; nbNodes.reserve( getNumNodes() ); for( unsigned int id = 0; id < getNumNodes()-1; ++id ) { if( validNode[id] ) { size_t realDad( changeLookup[realParentsforNodes[id]] ); if( realDad == invalid ) { std::cerr << "node (1-" << id << ") is valid but has invalid dad, ( preDad was 1-" << realParentsforNodes[id] << ")" << std::endl; throw std::runtime_error( "ERROR @ WHtree::debinarize(): error renaming nb node parents" ); } WHnode thisnode( std::make_pair( true, changeLookup[id] ), realChildren[id], fetchNode( id )->getSize(), fetchNode( id )->getDistLevel(), 0 ); thisnode.setParent( std::make_pair( true, realDad ) ); nbNodes.push_back( thisnode ); } } WHnode rootnode( std::make_pair( true, changeLookup[getNumNodes()-1] ), realChildren[getNumNodes()-1], fetchNode( getNumNodes()-1 )->getSize(), fetchNode( getNumNodes()-1 )->getDistLevel(), 0 ); nbNodes.push_back( rootnode ); // replace old node vector with new one m_nodes = nbNodes; } clearContainedLeaves(); clearPartitions(); // refill hLevel data for( unsigned int id = 0; id < getNumNodes(); ++id ) { WHnode* currentNode( fetchNode( id ) ); std::vector currentKids( currentNode->getChildren() ); size_t currentHLevel( 0 ); for( size_t j = 0; j < currentKids.size(); ++j ) { currentHLevel = std::max( currentHLevel, fetchNode( currentKids[j] )->getHLevel()+1 ); } currentNode->setHLevel( currentHLevel ); } if( !check() ) { throw std::runtime_error( "ERROR @ WHtree::debinarize(): resutling tree is not consistent" ); } size_t discardedNodes( origNumNodes - getNumNodes() ); if( discardedNodes != 0 ) { m_cpcc = 0; clearPartitions(); } return discardedNodes; } // end debinarize() ------------------------------------------------------------------------------------- void WHtree::forceMonotonicityUp() { // loop through nodes and force monotonicity for( std::vector::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter ) { WHnode* currentNode( fetchNode( nodesIter->getID() ) ); std::vector currentKids( currentNode->getChildren() ); for( size_t j = 0; j < currentKids.size(); ++j ) { WHnode* kid( fetchNode( currentKids[j] ) ); // if its kid has a higher level than the node, there was a non-monotonic step, and the highest level is kept if( kid->getDistLevel() > currentNode->getDistLevel() ) { currentNode->setDistLevel( kid->getDistLevel() ); } } } return; } // end forceMonotonicityUp() ------------------------------------------------------------------------------------- void WHtree::forceMonotonicityDown() { // loop through nodes and force monotonicity for( std::vector::reverse_iterator nodesIter( m_nodes.rbegin() ); nodesIter != m_nodes.rend(); ++nodesIter ) { WHnode* currentNode( fetchNode( nodesIter->getID() ) ); std::vector currentKids( currentNode->getChildren() ); for( size_t j = 0; j < currentKids.size(); ++j ) { WHnode* kid( fetchNode( currentKids[j] ) ); // if its kid has a higher level than the node, there was a non-monotonic step, and the lowest level is kept if( kid->getDistLevel() > currentNode->getDistLevel() ) { kid->setDistLevel( currentNode->getDistLevel() ); } } } return; } // end forceMonotonicityDown() ------------------------------------------------------------------------------------- void WHtree::forceMonotonicity( double errorMult ) { if( errorMult > 100 || errorMult <= 0 ) { errorMult = 1; } double errorMargin( errorMult * 1E-5 ); for( int64_t i = m_nodes.size()-1; i >= 0; ) { WHnode* currentNode( fetchNode( m_nodes[i].getID() ) ); size_t currentSize( currentNode->getSize() ); dist_t currentLevel( currentNode->getDistLevel() ); std::vector currentKids( currentNode->getChildren() ); double newLevelSum( 0 ); size_t remainingSize( currentSize ); bool doCorrect( false ); for( size_t j = 0; j < currentKids.size(); ++j ) { WHnode* kid( fetchNode( currentKids[j] ) ); // if its kid has a higher level than the node, there was a non-monotonic step if( kid->getDistLevel() > currentLevel + errorMargin ) { newLevelSum += kid->getDistLevel() * kid->getSize(); remainingSize -= kid->getSize(); doCorrect = true; } } if( doCorrect ) { // std::cout << i << " -> " << std::flush; double correctedLevel( ( newLevelSum + ( remainingSize * currentLevel ) ) / currentSize ); // correct level of current node currentNode->setDistLevel( correctedLevel ); // correct level of non-monotonic children nodes for( size_t j = 0; j < currentKids.size(); ++j ) { WHnode* kid( fetchNode( currentKids[j] ) ); // if its kid has a higher level than the node, there was a non-monotonic step, and the highest level must be kept to avoid info loss if( kid->getDistLevel() > correctedLevel ) { kid->setDistLevel( correctedLevel ); } } // if node is not root check if corrected level is higher than parent node if( currentNode->isRoot() ) { --i; } else { WHnode* parentNode( fetchNode( currentNode->getParent() ) ); double parentLevel( parentNode->getDistLevel() ); // if new level is higher than parent level, go back to parent node id and continue from there if( correctedLevel > parentLevel + errorMargin ) { i = parentNode->getID(); } else { --i; } } //DEBUG std::cout << i << " : " < " << correctedLevel << std::endl; } else { --i; } } forceMonotonicityDown(); return; } // end forceMonotonicity() -------------------------------------------------------------------------------------