CMMTree v1.0
cmmtree.cpp
Go to the documentation of this file.
1#include "node.cpp"
2#include "hpp/cmmtree.hpp"
3#include "hpp/predicates.hpp"
4
5template <class X1, template<typename> class predicate>
6void CMMTree<X1, predicate>::join_data( std::vector < X1 >const* const& adr) {
7 if( p_dataset ) throw std::runtime_error("CMMTree<X1, predicate>::join_data(): This tree is already assigned with data.\nConsider using the tree_clear() function.");
8 p_dataset = adr;
9}
10
11template <class X1, template<typename> class predicate>
12void CMMTree<X1, predicate>::join_data(std::vector < X1 >const* const& adr, typename std::vector<X1>::const_iterator const& pos){
13 if( p_dataset ) throw std::runtime_error("CMMTree<X1, predicate>::join_data(): This tree is already assigned with data.\nConsider using the tree_clear() function.");
14 p_dataset = adr;
15 root->data_address()=pos;
16}
17
18template <class X1, template<typename> class predicate>
19inline
20void CMMTree<X1, predicate>::add_next_firstborn(size_t generation, node<X1>* const& node_adr){
21 if( generation == MTree.size() ){
22 MTree.emplace_back( firstborns( 1, node_adr ) );
23 }
24 else{
25 MTree[generation].push_back(node_adr);
26 }
27}
28
29template <class X1, template<typename> class predicate>
30void CMMTree<X1, predicate>::find_new_generation( size_t generation ) {
31 size_t k, sn;
32 node<X1>* p_current_node;
33 typename std::vector<X1>::const_iterator pos ;
34
35 for(size_t i = 0; i < MTree[generation].size(); ++i ){
36 k=0;
37 sn = MTree[generation][i]->siblings_number() ;
38 p_current_node = MTree[generation][i];
39 p_current_node->change_children_capacity();
40 do{
41 if(generation){
42 p_current_node=(*p_current_node->parent->children)[k];
43 }
44 pos = p_dataset->begin();
45 while( pos != p_dataset->end() ){
46 if( condition( p_current_node, pos ) ) {
47 p_current_node->add_new_node( pos );
48 if( p_current_node->children_number() == 1 ){
49 add_next_firstborn(generation+1, (*p_current_node->children)[0] );
50 }
51 }
52 pos++;
53 }
54 }while(sn > k++ );
55 }
56}
57
58template <class X1, template<typename> class predicate>
59void CMMTree<X1, predicate>::create_subtrees_roots( std::vector < X1 > const& roots_data ) {
60 if( !root->isNULLit(root->d_iterator) || root->children )
61 throw std::runtime_error("CMMTree<X1, predicate>::create_subtrees_roots():\nThis function can only be called if the root node is not associated with any element of the input dataset and has no children yet.");
62
63 typename std::vector<X1>::const_iterator pos = roots_data.begin();
64 while( pos != roots_data.end() ){
65 root->add_new_node( pos );
66 if( root->children_number() == 1 ){
67 add_next_firstborn(1, (*root->children)[0] );
68 }
69 ++pos;
70 }
71}
72
73template <class X1, template<typename> class predicate>
75 if(!p_dataset) throw std::runtime_error("CMMTree<X1, predicate>::tree_create(): The tree is not assigned to the data.\nConsider using the join_data() function.\n");
76 size_t cht; //The current height of a tree;
77 auto t1 = std::chrono::high_resolution_clock::now();
78 do{
79 cht=MTree.size();
80 find_new_generation( cht-1 );
81 }while(cht < MTree.size());
82 auto t2 = std::chrono::high_resolution_clock::now();
83 return std::chrono::duration_cast<std::chrono::microseconds> (t2 - t1).count();
84}//tree_create
85
86template <class X1, template<typename> class predicate>
88 if(i>=MTree.size() )
89 throw std::runtime_error("CMMTree<X1, predicate>::firstborns_number(): The argument out of range.");
90 return MTree[i].size();
91}
92
93template <class X1, template<typename> class predicate>
95 if(i>=MTree.size() )
96 throw std::runtime_error("CMMTree<X1, predicate>::leaves_number(): The argument out of range.");
97 size_t tmp(0);
98 if(i==0){
99 if( !MTree[0][0]->children ) return 1;
100 else return tmp;
101 }
102 for(size_t j = 0; j < MTree[i].size(); ++j )
103 for(size_t k = 0; k < MTree[i][j]->parent->children_number(); ++k )
104 if( !(*MTree[i][j]->parent->children)[k]->children )
105 tmp++;
106 return tmp;
107}
108
109template <class X1, template<typename> class predicate>
111 if(i>=MTree.size() )
112 throw std::runtime_error("CMMTree<X1, predicate>::generation_size(size_t i): The argument out of range.");
113 if(i==0) return 1;
114 size_t tmp(0);
115 for(size_t j = 0; j < MTree[i].size(); ++j )
116 tmp+=MTree[i][j]->parent->children_number();
117 return tmp;
118}
119
120template <class X1, template<typename> class predicate>
121inline
122void CMMTree<X1, predicate>::generation_addresses(size_t i, std::vector< node<X1>const* > & vec)const{
123 if(i>=MTree.size() )
124 throw std::runtime_error("CMMTree<X1, predicate>::generation_addresses(): The first argument out of range.");
125 vec.clear();
126 if( i==0 ) {
127 vec.push_back( MTree[0][0] );
128 }
129 else{
130 for(size_t j = 0; j < MTree[i].size(); ++j ){
131 for(size_t k = 0; k < MTree[i][j]->parent->children_number(); ++k ){
132 vec.push_back( (*MTree[i][j]->parent->children)[k] );
133 }
134 }
135 }
136}
137
138template <class X1, template<typename> class predicate>
139inline
140void CMMTree<X1, predicate>::generation_addresses(size_t i, std::vector< node<X1>* > & vec)const{
141 if(i>=MTree.size() )
142 throw std::runtime_error("CMMTree<X1, predicate>::generation_addresses(): The first argument out of range.");
143 vec.clear();
144 if( i==0 ) {
145 vec.push_back( MTree[0][0] );
146 }
147 else{
148 for(size_t j = 0; j < MTree[i].size(); ++j ){
149 for(size_t k = 0; k < MTree[i][j]->parent->children_number(); ++k ){
150 vec.push_back( (*MTree[i][j]->parent->children)[k] );
151 }
152 }
153 }
154}
155
156template <class X1, template<typename> class predicate>
157inline
158void CMMTree<X1, predicate>::leaves_addresses(size_t i, std::vector< node<X1>const* > & vec)const {
159 vec.clear();
160 if(i>=MTree.size() )
161 throw std::runtime_error("CMMTree<X1, predicate>::leaves_addresses(): The first argument out of range.");
162 if( i==0 ) {
163 if(!MTree[0][0]->children ){
164 vec.push_back( MTree[0][0] );
165 }
166 }
167 else{
168 for(size_t j = 0; j < MTree[i].size(); ++j ){
169 for(size_t k = 0; k < MTree[i][j]->parent->children_number(); ++k ){
170 if( !(*MTree[i][j]->parent->children)[k]->children ){
171 vec.push_back( (*MTree[i][j]->parent->children)[k] );
172 }
173 }
174 }
175 }
176}
177
178template <class X1, template<typename> class predicate>
179inline
181 if(ptr->prev)
182 if( i < ptr->prev->children->size() )
183 return ptr->prev->children->operator[](i);
184 return nullptr;
185}
186
187template <class X1, template<typename> class predicate>
188inline node<X1>const* const& CMMTree<X1, predicate>::firstborn_address(size_t i, size_t j)const {
189 if(i >= MTree.size() ) throw std::runtime_error("CMMTree<X1, predicate>::firstborn_address(): The first argument out of range.");
190 if(j >= MTree[i].size() ) throw std::runtime_error("CMMTree<X1, predicate>::firstborn_address(): The second argument out of range.");
191 return MTree[i][j];
192}
193
194template <class X1, template<typename> class predicate>
195inline
197 for(size_t i=lev; i<MTree.size();++i){
198 MTree[i].clear();
199 if(i == 1){
200 if( root->children_number() ){
201 MTree[i].push_back(root->children->operator[](0));
202 }
203 else{
204 MTree.resize(i);
205 }
206 }
207 else{
208 for(auto& r: MTree[i-1]){ // for each firsborn
209 for(auto& rc: *r->parent->children ){ // for each of brothers
210 if( rc->children_number() ){
211 MTree[i].push_back(rc->children->operator[](0));
212 }
213 }
214 }
215 if( !MTree[i].size() ){
216 MTree.resize(i);
217 }
218 }
219 }
220}
221
222template <class X1, template<typename> class predicate>
224 // NOTE ! Deleting any node also deletes all its descendants
225 if(!to_del->parent) throw std::runtime_error("CMMTree<X1, predicate>::delete_node(): The root node can not be deleted!\n");
226 node<X1>* prev=to_del->parent;
227 size_t i=0, cs=prev->children->size();
228 for(; i<cs; ++i){
229 if(prev->children->operator[](i) == to_del){
230 delete prev->children->operator[](i);
231 cs-=1;
232 for(; i<cs; ++i){
233 prev->children->operator[](i)=prev->children->operator[](i+1);
234 }
235 }
236 }
237 prev->children->pop_back();
238 if(!prev->children->size()){
239 delete prev->children;
240 prev->children = nullptr;
241 }
242 jagged_table_reconstruction( to_del->node_level() );
243}
244
245template <class X1, template<typename> class predicate>
246void CMMTree<X1, predicate>::delete_nodes( std::vector< node<X1>* > & to_del, size_t lev ) {
247 if(!lev) throw std::runtime_error("CMMTree<X1, predicate>::delete_node(): The root node can not be deleted!\n");
248 for(auto& r: to_del){
249 node<X1>* prev=r->parent;
250 size_t i=0, cs=prev->children->size();
251 for(; i<cs; ++i){
252 if(prev->children->operator[](i) == r){
253 delete prev->children->operator[](i);
254 cs-=1;
255 for(; i<cs; ++i){
256 prev->children->operator[](i)=prev->children->operator[](i+1);
257 }
258 }
259 }
260 prev->children->pop_back();
261 if(!prev->children->size()){
262 delete prev->children;
263 prev->children = nullptr;
264 }
265 }
266 jagged_table_reconstruction( lev );
267}
268
269template <class X1, template<typename> class predicate>
271 if(root->children_number()){
272 for (auto& r : *root->children)
273 delete r;
274 delete root->children;
275 root->children=0;
276 MTree.resize(1);
277 }
278 p_dataset = nullptr;
279 root->data_address()=Null_iterator( X1() );
280}
281
282template <class X1, template<typename> class predicate>
283void CMMTree<X1, predicate>::tree_shape(std::ostream& out)const{
284 out<< "\nThe shape of the CMMTree ( N - number of nodes, F - number of firstborns, L - number of leaves ).\n";
285
286 size_t T_s= MTree.size();
287 long N_i= 0, N_ip= 0;
288 long F_i= 0, F_ip= 0;
289 long L_i= 0, L_ip= 0;
290 long SN1= 0, SN2 = 0;
291 long SF1= 0, SF2 = 0;
292
293 size_t j;
294 std::vector< const node<X1>* > N_ip_vec;
295 std::vector< const node<X1>* > F_ip_vec;
296
297// NOTE !!!
298// dF/Ni and dL/Ni are not normalized to 1 and therefore may go outside the range of the normalized graph.
299 out<< "Lev ; N ; F ; L ; F/N ; L/N ; dF/Ni ; dL/Ni ; dF/(Fi+Fip); dF/(Ni+Nip); dL/(Ni+Nip);(SN2-SN1)/Ni;(SF2-SF1)/Ni;\n";
300 out<< "----;------------;------------;------------;------------;------------;------------;------------;------------;------------;------------;------------;------------;\n";
301
302 for(size_t i=0; i<T_s ; ++i){
303 N_i= (long)generation_size(i);
304 F_i= (long)firstborns_number(i);
305 L_i= (long)leaves_number(i);
306
307 // Sums based on the firstborn of the previous generation.
308 if(i>0){
309 if(F_ip % 2){
310 SF1=SF2=0; j=0;
311
312 for( ; j < MTree[i-1].size()/2; ++j ){
313 MTree[i-1][j]->all_siblings_addresses( F_ip_vec );
314 for(auto&& r:F_ip_vec){
315 SF1+= (long)r->children_number();
316 }
317 }
318 j++;
319 for( ; j < MTree[i-1].size(); ++j ){
320 MTree[i-1][j]->all_siblings_addresses( F_ip_vec );
321 for(auto&& r:F_ip_vec){
322 SF2+= (long)r->children_number();
323 }
324 }
325 }
326 else{
327 SF1=SF2=0; j=0;
328 for( ; j < MTree[i-1].size()/2; ++j ){
329 MTree[i-1][j]->all_siblings_addresses( F_ip_vec );
330 for(auto&& r:F_ip_vec){
331 SF1+= (long)r->children_number();
332 }
333 }
334 for( ; j < MTree[i-1].size(); ++j ){
335 MTree[i-1][j]->all_siblings_addresses( F_ip_vec );
336 for(auto&& r:F_ip_vec) {
337 SF2+= (long)r->children_number();
338 }
339 }
340 }
341 }
342
343 if(i>0){ // Sums based on previous generation nodes
344 generation_addresses(i-1, N_ip_vec) ;
345 if(N_ip_vec.size() % 2){
346 SN1=SN2=0; j=0;
347 for( ; j < N_ip_vec.size()/2; ++j ){
348 SN1+= (long)N_ip_vec[j]->children_number();
349 }
350 j++;
351 for( ; j < N_ip_vec.size(); ++j ){
352 SN2+= (long)N_ip_vec[j]->children_number();
353 }
354 }
355 else{
356 SN1=SN2=0; j=0;
357 for( ; j < N_ip_vec.size()/2; ++j ){
358 SN1+= (long)N_ip_vec[j]->children_number();
359 }
360 for( ; j < N_ip_vec.size(); ++j ){
361 SN2+= (long)N_ip_vec[j]->children_number();
362 }
363 }
364 }
365
366 out.width(4);
367 out << i << ";" ;
368
369 out.width(12);
370 out << N_i << ';'; // N
371 out.width(12);
372 out << F_i << ';'; // F
373 out.width(12);
374 out << L_i << ';'; // L
375 out.width(12);
376 out << (double)F_i/(double)N_i << ';'; // F/N
377 out.width(12);
378 out << (double)L_i/(double)N_i << ';'; // L/N
379 out.width(12);
380 out << (double)(F_i - F_ip)/(double)N_i << ';'; // dF/Ni
381 out.width(12);
382 out << (double)(L_i - L_ip)/(double)N_i << ';'; // dL/Ni
383 out.width(12);
384 out << (double)(F_i - F_ip)/(double)(F_i + F_ip) << ';'; // dF/(Fi + Fip)
385 out.width(12);
386 out << (double)(F_i - F_ip)/(double)(N_i + N_ip) << ';'; // dF/(Ni + Nip)
387 out.width(12);
388 out << (double)(L_i - L_ip)/(double)(N_i + N_ip) << ';'; // dL/(Ni + Nip)
389 out.width(12);
390 out << (double)(SN2 - SN1)/(double)N_i << ';'; // (SN2-SN1)/Ni
391 out.width(12);
392 out << (double)(SF2 - SF1)/(double)N_i << ';'; // (SF2-SF1)/Ni
393 out.width(12);
394 out << std::endl;
395
396 N_ip= (long)generation_size(i);
397 F_ip= (long)firstborns_number(i);
398 L_ip= (long)leaves_number(i);
399 }
400 out<< "----;------------;------------;------------;------------;------------;------------;------------;------------;------------;------------;------------;------------;\n";
401}//tree_shape
402
403template <class X1, template<typename> class predicate>
404std::ostream& operator<<(std::ostream& out, CMMTree<X1, predicate> const& r) {
405 int c(0);
406 std::string msg("\n");
407
408 #ifdef NODE_COUNTER
409 #ifdef MAX_NODES_TO_PRINT
410 if( r.all_nodes_number() <= MAX_NODES_TO_PRINT )
411 c = 1;
412 else
413 msg = ("\nCMMTree has more nodes than was defined using the \'MAX_NODES_TO_PRINT\' directive.\n");
414 #else
415 msg = "\n\'MAX_NODES_TO_PRINT\' is not defined.\n";
416 #endif // MAX_NODES_TO_PRINT
417 #else
418 msg = "\nPlease define the \'NODE_COUNTER\' and \'MAX_NODES_TO_PRINT\' directives.\n";
419 #endif // NODE_COUNTER
420
421 if(c){
422 std::vector< node<X1>const* > vec;
423 #ifdef PRINT_ALL_PATHS
424 std::vector< typename std::vector<X1>::const_iterator > path;
425 size_t k;
426 for(size_t i=0; i<r.MTree.size() ; ++i){
427 r.generation_addresses(i, vec);
428 out << "--Level : " << i << " --" << std::endl;
429 path.clear();
430 for(size_t j=0; j<vec.size() ; ++j){
431 out << "---Path : " << j << " ---" << std::endl;
432 vec[j]->data_on_path(path);
433 k = path.size();
434 while(k>0){
435 out<<*path[--k] << "\n"; //";";
436 }
437 }
438 out << std::endl;
439 }
440 #else
441 for(size_t i=0; i<r.MTree.size() ; ++i){
442 r.generation_addresses(i, vec);
443 for(size_t j=0; j<vec.size() ; ++j){
444 //out << *vec[j] << ':';
445 out << '(' ;
446 if( vec[j]->data_address() != Null_iterator( X1() ) )
447 out<< *vec[j]->data_address();
448 out<< ") ";
449 }
450 out <<'\n';
451 }
452 #endif // PRINT_ALL_PATHS
453 }
454 else
455 out << "CMMTree hight : " << r.tree_height() << msg;
456 return out;
457}
458
The Conditional Multiway Mapped Tree (CMMTree) class definition.
Definition cmmtree.hpp:21
size_t firstborns_number(size_t i) const
This function returns the number of firstborn nodes of one generation of the CMMTree - at the level p...
Definition cmmtree.cpp:87
size_t generation_size(size_t i) const
This function returns the total number of nodes one generation of the CMMTree - at the level passed b...
Definition cmmtree.cpp:110
void generation_addresses(size_t i, std::vector< const node< X1 > * > &vec) const
This function allows you to get all the addresses of the i-th generation firstborn nodes....
Definition cmmtree.cpp:122
void tree_shape(std::ostream &out) const
This function allows you to represent a tree in a parametric form.
Definition cmmtree.cpp:283
void join_data(std::vector< X1 >const *const &adr)
This function is used to connect the CMMTree object to the input data vector.
Definition cmmtree.cpp:6
void tree_clear()
This function clears the entire CMMTree object.
Definition cmmtree.cpp:270
long long tree_create()
A function that starts the process of the CMMTree construction.
Definition cmmtree.cpp:74
void delete_one_node(node< X1 > *&to_del)
This function deletes the node whose address is passed as an argument.
Definition cmmtree.cpp:223
const node< X1 > * brother_address(const node< X1 > *ptr, size_t i) const
This function allows you to obtain the address of the i-th brother of the firstborn node.
Definition cmmtree.cpp:180
void create_subtrees_roots(std::vector< X1 > const &roots_data)
This function allows you to initialize the creation of a forest using a separate data set - different...
Definition cmmtree.cpp:59
node< X1 > const *const & firstborn_address(size_t i, size_t j) const
The function returns the address of the j-th firstborn of the i-th generation.
Definition cmmtree.cpp:188
size_t all_nodes_number() const
This function returns the number of all nodes in the CMMTree.
Definition cmmtree.hpp:198
size_t tree_height() const
This function returns the CMMTree height.
Definition cmmtree.hpp:231
void delete_nodes(std::vector< node< X1 > * > &to_del, size_t lev)
Using this function you can delete more than one node from a specified node generation at once.
Definition cmmtree.cpp:246
void leaves_addresses(size_t i, std::vector< const node< X1 > * > &vec) const
This function allows you to get all the addresses of the i-th generation leaves.
Definition cmmtree.cpp:158
size_t leaves_number(size_t i) const
This function returns the number of leaves one generation of the CMMTree - at the level passed by the...
Definition cmmtree.cpp:94
The node class definition. This is a template of a class whose objects are used to build a tree of re...
Definition node.hpp:45
size_t node_level() const
This function returns the level of the CMMTree where a given node is located.
Definition node.cpp:51
void change_children_capacity() const
A function that reduces the size of the vector of parent's children's addresses - from capacity() to ...
Definition node.hpp:199
size_t children_number() const
The function returns the number of children of a given node.
Definition node.hpp:188
void add_new_node(data_addr const &pos)
This function is used to create another CMMTree node.
Definition node.cpp:19
std::ostream & operator<<(std::ostream &out, CMMTree< X1, predicate > const &r)
Definition cmmtree.cpp:404
std::vector< T >::const_iterator const & Null_iterator(T)
An iterator that is supposed to point to "nothing" of specified type ;).
Definition node.hpp:20