/* Insert a new value, ai, into one of the heaps. Use this function when * the heaps contain less than window-1 nodes. Returns the median value. * Once there are window-1 nodes in the heap, switch to using mm_update. */ inline ai_t mm_update_init(mm_handle *mm, ai_t ai) { mm_node *node; idx_t n_s = mm->n_s; idx_t n_l = mm->n_l; node = &mm->node_data[n_s + n_l]; node->ai = ai; if (n_s == 0) { // the first node to appear in a heap mm->s_heap[0] = node; node->region = SH; node->idx = 0; mm->oldest = node; // only need to set the oldest node once mm->n_s = 1; mm->s_first_leaf = 0; } else { // at least one node already exists in the heaps mm->newest->next = node; if (n_s > n_l) { // add new node to large heap mm->l_heap[n_l] = node; node->region = LH; node->idx = n_l; ++mm->n_l; mm->l_first_leaf = FIRST_LEAF(mm->n_l); heapify_large_node(mm, n_l); } else { // add new node to small heap mm->s_heap[n_s] = node; node->region = SH; node->idx = n_s; ++mm->n_s; mm->s_first_leaf = FIRST_LEAF(mm->n_s); heapify_small_node(mm, n_s); } } mm->newest = node; return mm_get_median(mm); }
/* Insert a new value, ai, into one of the heaps or the nan array. Use this * function when there are at least window-1 nodes. Returns the median value. * If there are less than window-1 nodes, use mm_update_init_nan. */ inline ai_t mm_update_nan(mm_handle *mm, ai_t ai) { // node is oldest node with ai of newest node mm_node *node = mm->oldest; idx_t idx = node->idx; node->ai = ai; // update oldest, newest mm->oldest = mm->oldest->next; mm->newest->next = node; mm->newest = node; mm_node **l_heap = mm->l_heap; mm_node **s_heap = mm->s_heap; mm_node **n_array = mm->n_array; idx_t n_s = mm->n_s; idx_t n_l = mm->n_l; idx_t n_n = mm->n_n; mm_node *node2; if (ai != ai) { if (node->region == SH) { /* Oldest node is in the small heap and needs to be moved * to the nan array. Resulting hole in the small heap will be * filled with the rightmost leaf of the last row of the small * heap. */ // insert node into nan array node->region = NA; node->idx = n_n; n_array[n_n] = node; ++mm->n_n; // plug small heap hole --mm->n_s; if (mm->n_s == 0) { mm->s_first_leaf = 0; if (n_l > 0) { // move head node from the large heap to the small heap node2 = mm->l_heap[0]; node2->region = SH; s_heap[0] = node2; mm->n_s = 1; mm->s_first_leaf = 0; // plug hole in large heap node2= mm->l_heap[mm->n_l - 1]; node2->idx = 0; l_heap[0] = node2; --mm->n_l; if (mm->n_l == 0) mm->l_first_leaf = 0; else mm->l_first_leaf = FIRST_LEAF(mm->n_l); heapify_large_node(mm, 0); } } else { if (idx != n_s - 1) { s_heap[idx] = s_heap[n_s - 1]; s_heap[idx]->idx = idx; heapify_small_node(mm, idx); } if (mm->n_s < mm->n_l) { // move head node from the large heap to the small heap node2 = mm->l_heap[0]; node2->idx = mm->n_s; node2->region = SH; s_heap[mm->n_s] = node2; ++mm->n_s; mm->l_first_leaf = FIRST_LEAF(mm->n_s); heapify_small_node(mm, node2->idx); // plug hole in large heap node2= mm->l_heap[mm->n_l - 1]; node2->idx = 0; l_heap[0] = node2; --mm->n_l; if (mm->n_l == 0) mm->l_first_leaf = 0; else mm->l_first_leaf = FIRST_LEAF(mm->n_l); heapify_large_node(mm, 0); } else { mm->s_first_leaf = FIRST_LEAF(mm->n_s); heapify_small_node(mm, idx); } } } else if (node->region == LH) { /* Oldest node is in the large heap and needs to be moved * to the nan array. Resulting hole in the large heap will be * filled with the rightmost leaf of the last row of the large * heap. */ // insert node into nan array node->region = NA; node->idx = n_n; n_array[n_n] = node; ++mm->n_n; // plug large heap hole if (idx != n_l - 1) { l_heap[idx] = l_heap[n_l - 1]; l_heap[idx]->idx = idx; heapify_large_node(mm, idx); } --mm->n_l; if (mm->n_l == 0) mm->l_first_leaf = 0; else mm->l_first_leaf = FIRST_LEAF(mm->n_l); if (mm->n_l < mm->n_s - 1) { // move head node from the small heap to the large heap node2 = mm->s_heap[0]; node2->idx = mm->n_l; node2->region = LH; l_heap[mm->n_l] = node2; ++mm->n_l; mm->l_first_leaf = FIRST_LEAF(mm->n_l); heapify_large_node(mm, node2->idx); // plug hole in small heap if (n_s != 1) { node2 = mm->s_heap[mm->n_s - 1]; node2->idx = 0; s_heap[0] = node2; } --mm->n_s; if (mm->n_s == 0) mm->s_first_leaf = 0; else mm->s_first_leaf = FIRST_LEAF(mm->n_s); heapify_small_node(mm, 0); } // reorder large heap if needed heapify_large_node(mm, idx); } else if (node->region == NA) { // insert node into nan heap n_array[idx] = node; } } else { if (node->region == SH) heapify_small_node(mm, idx); else if (node->region == LH) heapify_large_node(mm, idx); else { // ai is not NaN but oldest node is in nan array if (n_s > n_l) { // insert into large heap node->region = LH; node->idx = n_l; l_heap[n_l] = node; ++mm->n_l; mm->l_first_leaf = FIRST_LEAF(mm->n_l); heapify_large_node(mm, n_l); } else { // insert into small heap node->region = SH; node->idx = n_s; s_heap[n_s] = node; ++mm->n_s; mm->s_first_leaf = FIRST_LEAF(mm->n_s); heapify_small_node(mm, n_s); } // plug nan array hole if (idx != n_n - 1) { n_array[idx] = n_array[n_n - 1]; n_array[idx]->idx = idx; } --mm->n_n; } } return mm_get_median(mm); }
/* Insert a new value, ai, into one of the heaps or the nan array. Use this * function when there are less than window-1 nodes. Returns the median * value. Once there are window-1 nodes in the heap, switch to using * mm_update_nan. */ ai_t mm_update_init_nan(mm_handle *mm, ai_t ai) { mm_node *node; idx_t n_s = mm->n_s; idx_t n_l = mm->n_l; idx_t n_n = mm->n_n; node = &mm->node_data[n_s + n_l + n_n]; node->ai = ai; if (ai != ai) { mm->n_array[n_n] = node; node->region = NA; node->idx = n_n; if (n_s + n_l + n_n == 0) { /* only need to set the oldest node once */ mm->oldest = node; } else { mm->newest->next = node; } ++mm->n_n; } else { if (n_s == 0) { /* the first node to appear in a heap */ mm->s_heap[0] = node; node->region = SH; node->idx = 0; if (n_s + n_l + n_n == 0) { /* only need to set the oldest node once */ mm->oldest = node; } else { mm->newest->next = node; } mm->n_s = 1; mm->s_first_leaf = 0; } else { /* at least one node already exists in the heaps */ mm->newest->next = node; if (n_s > n_l) { /* add new node to large heap */ mm->l_heap[n_l] = node; node->region = LH; node->idx = n_l; ++mm->n_l; mm->l_first_leaf = FIRST_LEAF(mm->n_l); heapify_large_node(mm, n_l); } else { /* add new node to small heap */ mm->s_heap[n_s] = node; node->region = SH; node->idx = n_s; ++mm->n_s; mm->s_first_leaf = FIRST_LEAF(mm->n_s); heapify_small_node(mm, n_s); } } } mm->newest = node; return mm_get_median(mm); }