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