1 /*
2  * scrm is an implementation of the Sequential-Coalescent-with-Recombination Model.
3  *
4  * Copyright (C) 2013, 2014 Paul R. Staab, Sha (Joe) Zhu, Dirk Metzler and Gerton Lunter
5  *
6  * This file is part of scrm.
7  *
8  * scrm is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #include "time_interval.h"
24 
25 /* --------------------------------------------------------------------
26  * TimeInterval
27  * -------------------------------------------------------------------*/
28 
TimeInterval()29 TimeInterval::TimeInterval() {
30   this->tii_ = NULL;
31   this->start_height_ = 0;
32   this->end_height_ = 0;
33 }
34 
35 
TimeInterval(TimeIntervalIterator * tii,double start_height,double end_height)36 TimeInterval::TimeInterval(TimeIntervalIterator* tii, double start_height, double end_height){
37   assert( tii != NULL );
38   this->tii_ = tii;
39   this->start_height_ = start_height;
40   this->end_height_ = end_height;
41 }
42 
43 
44 /* --------------------------------------------------------------------
45  * TimeIntervalIterator
46  * -------------------------------------------------------------------*/
47 
TimeIntervalIterator(Forest * forest)48 TimeIntervalIterator::TimeIntervalIterator(Forest *forest) {
49   // Used only for unit testing, and hence private.
50   this->forest_ = forest;
51   this->contemporaries_ = &(forest->contemporaries_);
52   this->contemporaries_->clear(false);
53   this->node_iterator_ = forest->nodes()->iterator();
54   this->good_ = false;
55   this->inside_node_ = NULL;
56   this->current_time_ = 0;
57   forest->writable_model()->resetTime();
58 }
59 
TimeIntervalIterator(Forest * forest,Node * start_node)60 TimeIntervalIterator::TimeIntervalIterator(Forest* forest,
61                                            Node* start_node) {
62 
63   this->forest_ = forest;
64   this->contemporaries_ = &forest->contemporaries_;
65   this->model_ = forest->model_;
66 
67   this->good_ = true;
68   this->inside_node_ = NULL;
69   this->node_iterator_ = forest->nodes()->iterator(start_node);
70   this->current_time_ = start_node->height();
71 
72   model_->resetTime();
73   this->searchContemporaries(start_node);
74 
75   // Skip through model changes
76   while ( model_->getNextTime() <= current_time_ ) {
77     model_->increaseTime();
78   }
79 
80   next();
81 }
82 
83 
84 // Sets current_interval_ to the next time interval.
next()85 void TimeIntervalIterator::next() {
86   if (this->inside_node_ != NULL) {
87     this->current_interval_.start_height_ = inside_node_->height();
88     this->inside_node_ = NULL;
89     return;
90   }
91 
92   if (current_time_ == DBL_MAX) {
93     good_ = false;
94     return;
95   }
96 
97   double start_height = this->current_time_;
98 
99   // Ensure that both iterators point into the future to determine the end of the
100   // interval
101   if ( start_height >= forest_->model().getNextTime() ) {
102     model_->increaseTime();
103   }
104 
105   if ( start_height >= node_iterator_.height() ) {
106     // Update contemporaries
107     contemporaries()->replaceChildren(*node_iterator_);
108 
109     // Pruning
110     while ( !(*node_iterator_)->is_last() ) {
111       // Prunes the next node BEFORE node_iterator_ gets there,
112       // and does there not invalidate it.
113       if (!forest_->pruneNodeIfNeeded((*node_iterator_)->next())) break;
114     }
115 
116     // Move node iterator forwards
117     ++node_iterator_;
118   }
119 
120   double next_model_change_ = forest_->model().getNextTime();
121 
122   assert( current_time_ <= next_model_change_ );
123   //std::cout << "current_time: " << current_time_ << " ni_height: " << node_iterator_.height() << std::endl;
124   assert( current_time_ <= node_iterator_.height() );
125 
126   // Now determine the end of the interval
127   if ( node_iterator_.height() <= next_model_change_ ) {
128     current_time_ = node_iterator_.height();
129   } else  {
130     current_time_ = next_model_change_;
131   }
132   //std::cout << " Next Node: " << node_iterator_.height()
133   //          << " Next MC: " << next_model_change_
134   //          << " CT " << current_time_ << std::endl;
135 
136   //Don't return TimeIntervals of length zero, as nothing can happen there...
137   if (start_height == current_time_) return next();
138 
139   this->current_interval_ = TimeInterval(this,
140                                          start_height,
141                                          current_time_);
142 }
143 
searchContemporariesBottomUp(Node * node,const bool use_buffer)144 void TimeIntervalIterator::searchContemporariesBottomUp(Node* node, const bool use_buffer) {
145   contemporaries()->clear(false);
146   Node* start_node = NULL;
147 
148   if ( use_buffer ) {
149     assert( node->height() >= contemporaries()->buffer_time() );
150     // check if the buffered contemporaries are contemporaries of node
151     double highest_time = -1;
152     for (size_t pop = 0; pop < model()->population_number(); ++pop) {
153       auto end = contemporaries()->buffer_end(pop);
154       for (auto it = contemporaries()->buffer_begin(pop); it != end; ++it) {
155         assert(!(*it)->is_root());
156         //std::cout << "Checking " << *it << std::endl;
157         // Prune the node if needed
158         tmp_child_1_ = (*it);
159         tmp_child_2_ = (*it)->first_child();
160         while (tmp_child_1_->countChildren() == 1 && forest_->pruneNodeIfNeeded(tmp_child_1_)) {
161           tmp_child_1_ = tmp_child_2_;
162           if (tmp_child_1_ == NULL ) break;
163           tmp_child_2_ = tmp_child_2_->first_child();
164         }
165         if (tmp_child_1_ == NULL || forest_->pruneNodeIfNeeded(tmp_child_1_)) continue;
166 
167         // And add it if it is a contemporary
168         if (tmp_child_1_->height() <= node->height() && node->height() < tmp_child_1_->parent_height()) {
169           contemporaries()->add(tmp_child_1_);
170         }
171 
172         // Find the oldest buffered node
173         if (tmp_child_1_->height() > highest_time) {
174           highest_time = tmp_child_1_->height();
175           start_node = tmp_child_1_;
176         }
177       }
178     }
179     // The node after the oldest node in the buffer should be the first node
180     // above the buffers_height.
181     assert( start_node != NULL );
182     start_node = start_node->next();
183     assert( start_node->height() >= contemporaries()->buffer_time() );
184   } else {
185     start_node = forest()->nodes()->first();
186   }
187 
188   for (NodeIterator ni = forest_->nodes()->iterator(start_node); *ni != node; ++ni) {
189     assert(ni.good());
190 
191     // Check if *ni is a contemporary of node
192     if ( (*ni)->parent_height() > node->height() ) {
193       // Is is; it may however be a node we need to prune
194       if ((*ni)->is_first()) tmp_prev_node_ = NULL;
195       else tmp_prev_node_ = (*ni)->previous();
196       tmp_child_1_ = (*ni)->first_child();
197 
198       if (forest_->pruneNodeIfNeeded(*ni)) {
199         // Removing the node invalidates the ni
200         if (tmp_prev_node_ == NULL) ni = forest_->nodes()->iterator();
201         else ni = forest_->nodes()->iterator(tmp_prev_node_);
202 
203         // Maybe a child of the node became a contemporary by removing the node
204         // This can only happen if the node has only one child.
205         if ( tmp_child_1_ != NULL && tmp_child_1_->parent_height() > node->height() ) {
206           this->contemporaries()->add(tmp_child_1_);
207         }
208       } else {
209         // No pruning => Just add to contemporaries
210         this->contemporaries()->add(*ni);
211       }
212     }
213   }
214 }
215 
216 
217 
218 // Recalculates the borders of the current interval.
219 // Used after one or more nodes where created inside the interval due to events
220 // occurring within.
recalculateInterval()221 void TimeIntervalIterator::recalculateInterval() {
222   if (!node_iterator_.good()) {
223     node_iterator_ = NodeIterator(forest_->nodes()->last());
224   }
225   else {
226     // Set node iterator back to the node at the current start_height
227     while ( (*node_iterator_)->height() > current_interval_.start_height() ) --node_iterator_;
228     ++node_iterator_;
229   }
230 
231   // Then go to the next node
232   current_interval_.end_height_ = (*node_iterator_)->height();
233   current_time_ = (*node_iterator_)->height();
234 }
235