static std::pair<uint32_t,uint32_t> lcs(std::string const & a, std::string const & b) { /* concatenate a and b into string c */ std::string c(a.size()+b.size()+2,' '); for ( uint64_t i = 0; i < a.size(); ++i ) c[i] = a[i]+2; c[a.size()] = 0; for ( uint64_t i = 0; i < b.size(); ++i ) c[a.size()+1+i] = b[i]+2; c[c.size()-1] = 1; // allocate suffix sorting ::libmaus::autoarray::AutoArray<int32_t> SA(c.size(),false); // perform suffix sorting typedef ::libmaus::suffixsort::DivSufSort<32,uint8_t *,uint8_t const *,int32_t *,int32_t const *,8> sort_type; typedef sort_type::saidx_t saidx_t; sort_type::divsufsort(reinterpret_cast<uint8_t const *>(c.c_str()), SA.get(), c.size()); // compute LCP array ::libmaus::autoarray::AutoArray<int32_t> LCP = ::libmaus::suffixsort::SkewSuffixSort<uint8_t,int32_t>::lcpByPlcp( reinterpret_cast<uint8_t const *>(c.c_str()), c.size(), SA.get()); // compute psv and nsv arrays for simulating parent operation on suffix tree ::libmaus::autoarray::AutoArray<int32_t> const prev = ::libmaus::sv::PSV::psv(LCP.get(),LCP.size()); ::libmaus::autoarray::AutoArray<int32_t> const next = ::libmaus::sv::NSV::nsv(LCP.get(),LCP.size()); #if defined(LCS_DEBUG) for ( uint64_t i = 0; i < c.size(); ++i ) { std::cerr << i << "\t" << LCP[i] << "\t" << prev[i] << "\t" << next[i] << "\t"; for ( std::string::const_iterator ita = c.begin()+SA[i]; ita != c.end(); ++ita ) if ( isalnum(*ita) ) std::cerr << *ita; else std::cerr << "<" << static_cast<int>(*ita) << ">" ; std::cerr << std::endl; } std::cerr << "---" << std::endl; #endif int32_t const n = c.size(); // queue all suffix tree leafs std::deque < QNode > Q; for ( int32_t i = 0; i < n; ++i ) Q.push_back ( QNode(i,i,0, (SA[i]< static_cast<int32_t>(a.size()+1)) ? 1:2, 1 ) ); // construct hash for tree nodes we have seen so far typedef ::libmaus::util::unordered_set < QNode , HashQNode >::type hash_type; typedef hash_type::iterator hash_iterator_type; typedef hash_type::const_iterator hash_const_iterator_type; hash_type H(n); // we simulate a bottom up traversal of the generalised suffix tree for a and b while ( Q.size() ) { // get node and compute parent QNode const I = Q.front(); Q.pop_front(); QNode P = parent(I,LCP.get(),prev.get(),next.get(),n); // have we seen this node before? hash_iterator_type it = H.find(P); // no, insert it if ( it == H.end() ) { it = H.insert(P).first; } // yes, update symbol mask and extend visited interval else { it->symmask |= I.symmask; it->fill += (I.right-I.left+1); } // if this is not the root and the node is full (we have seen all its children), // then put it in the queue if ( P.right-P.left + 1 < n && it->isFull() ) Q.push_back(P); } // maximum lcp value int32_t maxlcp = 0; uint32_t maxpos = 0; // consider all finished nodes for ( hash_const_iterator_type it = H.begin(); it != H.end(); ++it ) { #if defined(LCS_DEBUG) std::cerr << *it << std::endl; #endif // we need to have nodes from both strings a and b under this // node (sym mask has bits for 1 and 2 set) and the lcp value must be // larger than what we already have if ( it->symmask == 3 && it->depth > maxlcp ) { maxlcp = it->depth; maxpos = SA[it->left]; } } return std::pair<uint32_t,uint32_t>(maxlcp,maxpos); }
void QTransferFunction::AddNode(const float& Intensity, const float& Opacity, const QColor& Diffuse, const QColor& Specular, const QColor& Emission, const float& Roughness) { AddNode(QNode(this, Intensity, Opacity, Diffuse, Specular, Emission, Roughness)); }
// compute parent node using prev and next arrays static inline QNode parent(QNode const & I, int32_t const * LCP, int32_t const * prev, int32_t const * next, int32_t const n) { int32_t const k = ( (I.right+1 >= n) || (LCP[I.left] > LCP[I.right+1]) ) ? I.left : (I.right+1); return QNode(prev[k],next[k]-1,LCP[k],I.symmask,I.right-I.left+1); }