/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2003, 2004, 2005  Gabor Csardi <csardi@rmki.kfki.hu>
   MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
   02110-1301 USA

*/

#include "types.h"
#include "memory.h"
#include "random.h"
#include "error.h"

#include <assert.h>
#include <string.h> 		/* memcpy & co. */
#include <stdlib.h>

#define PARENT(x)     (((x)+1)/2-1)
#define LEFTCHILD(x)  (((x)+1)*2-1)
#define RIGHTCHILD(x) (((x)+1)*2)
  
/**
 * \ingroup heap
 * \brief Initializes an empty heap object (constructor).
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_heap_init           (igraph_heap_t* h, long int alloc_size) {
  if (alloc_size <= 0 ) { alloc_size=1; }
  h->stor_begin=Calloc(alloc_size, igraph_real_t);
  if (h->stor_begin==0) {
    IGRAPH_ERROR("heap init failed", IGRAPH_ENOMEM);
  }
  h->stor_end=h->stor_begin + alloc_size;
  h->end=h->stor_begin;
  h->destroy=1;
  
  return 0;  
}

/**
 * \ingroup heap
 * \brief Initializes a heap object from an array, the heap is also
 * built of course (constructor).
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_heap_init_array     (igraph_heap_t *h, igraph_real_t* data, long int len) {
  h->stor_begin=Calloc(len, igraph_real_t);
  if (h->stor_begin==0) {
    IGRAPH_ERROR("heap init from array failed", IGRAPH_ENOMEM);
  }
  h->stor_end=h->stor_begin+len;
  h->end=h->stor_end;
  h->destroy=1;

  memcpy(h->stor_begin, data, len*sizeof(igraph_real_t));

  igraph_heap_i_build (h->stor_begin, h->end-h->stor_begin, 0);
  
  return 0;
}

/**
 * \ingroup heap
 * \brief Destroys an initialized heap object.
 */

void igraph_heap_destroy        (igraph_heap_t* h) {  
  if (h->destroy) {
    if (h->stor_begin != 0) {
      Free(h->stor_begin);
      h->stor_begin=0;
    }
  }
}

/**
 * \ingroup heap
 * \brief Decides whether a heap object is empty.
 */

igraph_bool_t igraph_heap_empty          (igraph_heap_t* h) {
  assert(h != NULL);
  assert(h->stor_begin != NULL);
  return h->stor_begin == h->end;
}

/**
 * \ingroup heap
 * \brief Adds an element to a heap object.
 */

int igraph_heap_push           (igraph_heap_t* h, igraph_real_t elem) {
  int ret;
  assert(h != NULL);
  assert(h->stor_begin != NULL);
	
  /* full, allocate more storage */
  if (h->stor_end == h->end) {
    long int new_size = igraph_heap_size(h) * 2;
    if (new_size == 0) { new_size = 1; }
    IGRAPH_CHECK(ret=igraph_heap_reserve(h, new_size));
  }
	
  *(h->end) = elem;
  h->end += 1;

  /* maintain heap */
  igraph_heap_i_shift_up(h->stor_begin, igraph_heap_size(h), igraph_heap_size(h)-1);
	
  return 0;
}

/**
 * \ingroup heap
 * \brief Returns the largest element in a heap.
 */

igraph_real_t igraph_heap_max       (igraph_heap_t* h) {
  assert(h != NULL);
  assert(h->stor_begin != NULL);
  assert(h->stor_begin != h->end);
  
  return h->stor_begin[0];
}

/**
 * \ingroup heap
 * \brief Returns and removes the largest element in a heap.
 */

igraph_real_t igraph_heap_delete_max(igraph_heap_t* h) {
  igraph_real_t tmp;

  assert(h != NULL);
  assert(h->stor_begin != NULL);

  tmp=h->stor_begin[0];
  igraph_heap_i_switch(h->stor_begin, 0, igraph_heap_size(h)-1);
  h->end -= 1;
  igraph_heap_i_sink(h->stor_begin, h->end-h->stor_begin, 0);
  
  return tmp;
}

/**
 * \ingroup heap
 * \brief Gives the number of elements in a heap.
 */

long int igraph_heap_size      (igraph_heap_t* h) {
  assert(h != NULL);
  assert(h->stor_begin != NULL);
  return h->end - h->stor_begin;
}

/**
 * \ingroup heap
 * \brief Allocates more memory for a heap if needed.
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_heap_reserve        (igraph_heap_t* h, long int size) {
  long int actual_size=igraph_heap_size(h);
  igraph_real_t *tmp;
  assert(h != NULL);
  assert(h->stor_begin != NULL);
  
  if (size <= actual_size) { return 0; }
  
  tmp=Realloc(h->stor_begin, size, igraph_real_t);
  if (tmp==0) {
    IGRAPH_ERROR("heap reserve failed", IGRAPH_ENOMEM);
  }
  h->stor_begin=tmp;
  h->stor_end=h->stor_begin + size;
  h->end=h->stor_begin+actual_size;
  
  return 0;
}

/**
 * \ingroup heap
 * \brief Build a heap, this should not be called directly.
 */

void igraph_heap_i_build(igraph_real_t* arr, long int size, long int head) {

  if (RIGHTCHILD(head) < size) { 
    /* both subtrees */
    igraph_heap_i_build(arr, size, LEFTCHILD(head) );
    igraph_heap_i_build(arr, size, RIGHTCHILD(head));
    igraph_heap_i_sink(arr, size, head);
  } else if (LEFTCHILD(head) < size) {
    /* only left */
    igraph_heap_i_build(arr, size, LEFTCHILD(head));
    igraph_heap_i_sink(arr, size, head);
  } else {
    /* none */
  }
}

/**
 * \ingroup heap
 * \brief Shift an element upwards in a heap, this should not be
 * called directly.
 */

void igraph_heap_i_shift_up(igraph_real_t* arr, long int size, long int elem) {
  
  if (elem==0 || arr[elem] < arr[PARENT(elem)]) { 
    /* at the top */
  } else {
    igraph_heap_i_switch(arr, elem, PARENT(elem));
    igraph_heap_i_shift_up(arr, size, PARENT(elem));
  }
}

/**
 * \ingroup heap
 * \brief Moves an element down in a heap, this function should not be
 * called directly.
 */

void igraph_heap_i_sink(igraph_real_t* arr, long int size, long int head) {

  if (LEFTCHILD(head) >= size) { 
    /* no subtrees */
  } else if (RIGHTCHILD(head) == size ||
	     arr[LEFTCHILD(head)] >= arr[RIGHTCHILD(head)]) {
    /* sink to the left if needed */
    if (arr[head] < arr[LEFTCHILD(head)]) {
      igraph_heap_i_switch(arr, head, LEFTCHILD(head));
      igraph_heap_i_sink(arr, size, LEFTCHILD(head));
    }
  } else {
    /* sink to the right */
    if (arr[head] < arr[RIGHTCHILD(head)]) {
      igraph_heap_i_switch(arr, head, RIGHTCHILD(head));
      igraph_heap_i_sink(arr, size, RIGHTCHILD(head));
    }
  }
}

/**
 * \ingroup heap
 * \brief Switches two elements in a heap, this function should not be
 * called directly.
 */

void igraph_heap_i_switch(igraph_real_t* arr, long int e1, long int e2) {
  if (e1!=e2) {
    igraph_real_t tmp=arr[e1];
    arr[e1]=arr[e2];
    arr[e2]=tmp;
  }
}

/**
 * \ingroup indheap
 * \brief Initializes an indexed heap (constructor).
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_indheap_init           (igraph_indheap_t* h, long int alloc_size) {
 if (alloc_size <= 0 ) { alloc_size=1; }
 h->stor_begin=Calloc(alloc_size, igraph_real_t);
 if (h->stor_begin==0) {
   h->index_begin=0;
   IGRAPH_ERROR("indheap init failed", IGRAPH_ENOMEM);
 }
 h->index_begin=Calloc(alloc_size, long int);
 if (h->index_begin==0) {
   Free(h->stor_begin);
   h->stor_begin=0;
   IGRAPH_ERROR("indheap init failed", IGRAPH_ENOMEM);
 }
 
 h->stor_end=h->stor_begin + alloc_size;
 h->end=h->stor_begin;
 h->destroy=1;
 
 return 0;  
}

/**
 * \ingroup indheap
 * \brief Initializes and build an indexed heap from a C array (constructor).
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_indheap_init_array     (igraph_indheap_t *h, igraph_real_t* data, long int len) {
  long int i;

  h->stor_begin=Calloc(len, igraph_real_t);
  if (h->stor_begin==0) {
    h->index_begin=0;
    IGRAPH_ERROR("indheap init from array failed", IGRAPH_ENOMEM);
  }
  h->index_begin=Calloc(len, long int);
  if (h->index_begin==0) {
    Free(h->stor_begin);
    h->stor_begin=0;
    IGRAPH_ERROR("indheap init from array failed", IGRAPH_ENOMEM);
  }
  h->stor_end=h->stor_begin+len;
  h->end=h->stor_end;
  h->destroy=1;

  memcpy(h->stor_begin, data, len*sizeof(igraph_real_t));
  for (i=0; i<len; i++) {
    h->index_begin[i]=i+1;
  }

  igraph_indheap_i_build (h, 0);
  
  return 0;
}

/**
 * \ingroup indheap
 * \brief Destroys an initialized indexed heap. 
 */

void igraph_indheap_destroy        (igraph_indheap_t* h) {  
  assert(h != 0);
  if (h->destroy) {
    if (h->stor_begin != 0) {
      Free(h->stor_begin);
      h->stor_begin=0;
    }
    if (h->index_begin != 0) {
      Free(h->index_begin);
      h->index_begin=0;
    }
  }
}

/**
 * \ingroup indheap
 * \brief Checks whether a heap is empty.
 */

igraph_bool_t igraph_indheap_empty          (igraph_indheap_t* h) {
  assert(h != 0);
  assert(h->stor_begin != 0);
  return h->stor_begin == h->end;
}

/**
 * \ingroup indheap
 * \brief Adds an element to an indexed heap.
 */

int igraph_indheap_push           (igraph_indheap_t* h, igraph_real_t elem) {
  assert(h != 0);
  assert(h->stor_begin != 0);
	
  /* full, allocate more storage */
  if (h->stor_end == h->end) {
    long int new_size = igraph_indheap_size(h) * 2;
    if (new_size == 0) { new_size = 1; }
    IGRAPH_CHECK(igraph_indheap_reserve(h, new_size));
  }
	
  *(h->end) = elem;
  h->end += 1;
  *(h->index_begin+igraph_indheap_size(h)-1)=igraph_indheap_size(h)-1;

  /* maintain indheap */
  igraph_indheap_i_shift_up(h, igraph_indheap_size(h)-1);
	
  return 0;
}

/**
 * \ingroup indheap
 * \brief Adds an element to an indexed heap with a given index.
 */

int igraph_indheap_push_index(igraph_indheap_t* h, long int idx, igraph_real_t elem) {
  assert(h != 0);
  assert(h->stor_begin != 0);
	
  /* full, allocate more storage */
  if (h->stor_end == h->end) {
    long int new_size = igraph_indheap_size(h) * 2;
    if (new_size == 0) { new_size = 1; }
    IGRAPH_CHECK(igraph_indheap_reserve(h, new_size));
  }
	
  *(h->end) = elem;
  h->end += 1;
  *(h->index_begin+igraph_indheap_size(h)-1)=idx;

  /* maintain indheap */
  igraph_indheap_i_shift_up(h, igraph_indheap_size(h)-1);
	
  return 0;
}

/**
 * \ingroup indheap
 * \brief Modifies an element in an indexed heap.
 */

int igraph_indheap_modify(igraph_indheap_t* h, long int idx, igraph_real_t elem) {
  long int i, n;

  assert(h != 0);
  assert(h->stor_begin != 0);

  n = igraph_indheap_size(h);
  for (i=0; i<n; i++)
    if (h->index_begin[i] == idx) {
	  h->stor_begin[i] = elem;
	  break;
	}

  if (i == n) return 0;

  /* maintain indheap */
  igraph_indheap_i_build(h, 0);

  return 0;
}

/**
 * \ingroup indheap
 * \brief Returns the largest element in an indexed heap.
 */

igraph_real_t igraph_indheap_max       (igraph_indheap_t* h) {
  assert(h != NULL);
  assert(h->stor_begin != NULL);
  assert(h->stor_begin != h->end);
  
  return h->stor_begin[0];
}

/**
 * \ingroup indheap
 * \brief Removes the largest element from an indexed heap.
 */

igraph_real_t igraph_indheap_delete_max(igraph_indheap_t* h) {
  igraph_real_t tmp;

  assert(h != NULL);
  assert(h->stor_begin != NULL);

  tmp=h->stor_begin[0];
  igraph_indheap_i_switch(h, 0, igraph_indheap_size(h)-1);
  h->end -= 1;
  igraph_indheap_i_sink(h, 0);
  
  return tmp;
}

/**
 * \ingroup indheap
 * \brief Gives the number of elements in an indexed heap.
 */

long int igraph_indheap_size      (igraph_indheap_t* h) {
  assert(h != 0);
  assert(h->stor_begin != 0);
  return h->end - h->stor_begin;
}

/**
 * \ingroup indheap
 * \brief Reserves more memory for an indexed heap.
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_indheap_reserve        (igraph_indheap_t* h, long int size) {
  long int actual_size=igraph_indheap_size(h);
  igraph_real_t *tmp1;
  long int *tmp2;
  assert(h != 0);
  assert(h->stor_begin != 0);
  
  if (size <= actual_size) { return 0; }

  tmp1=Calloc(size, igraph_real_t);  
  if (tmp1==0) {
    IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, tmp1); 	/* TODO: hack */
  tmp2=Calloc(size, long int);
  if (tmp2==0) {
    IGRAPH_ERROR("indheap reserve failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, tmp2);
  memcpy(tmp1, h->stor_begin, actual_size*sizeof(igraph_real_t));
  memcpy(tmp2, h->index_begin, actual_size*sizeof(long int));
  Free(h->stor_begin);
  Free(h->index_begin);
  
  h->stor_begin=tmp1;
  h->index_begin=tmp2;
  h->stor_end=h->stor_begin + size;
  h->end=h->stor_begin+actual_size;
  
  IGRAPH_FINALLY_CLEAN(2);
  return 0;
}

/**
 * \ingroup indheap
 * \brief Returns the index of the largest element in an indexed heap.
 */

long int igraph_indheap_max_index(igraph_indheap_t *h) {
  assert(h != 0);
  assert(h->stor_begin != 0);
  return h->index_begin[0];  
}

/**
 * \ingroup indheap
 * \brief Builds an indexed heap, this function should not be called
 * directly. 
 */

void igraph_indheap_i_build(igraph_indheap_t* h, long int head) {

  long int size=igraph_indheap_size(h);
  if (RIGHTCHILD(head) < size) { 
    /* both subtrees */
    igraph_indheap_i_build(h, LEFTCHILD(head) );
    igraph_indheap_i_build(h, RIGHTCHILD(head));
    igraph_indheap_i_sink(h, head);
  } else if (LEFTCHILD(head) < size) {
    /* only left */
    igraph_indheap_i_build(h, LEFTCHILD(head));
    igraph_indheap_i_sink(h, head);
  } else {
    /* none */
  }
}

/**
 * \ingroup indheap
 * \brief Moves an element up in the heap, don't call this function
 * directly. 
 */

void igraph_indheap_i_shift_up(igraph_indheap_t *h, long int elem) {
  
  if (elem==0 || h->stor_begin[elem] < h->stor_begin[PARENT(elem)]) { 
    /* at the top */
  } else {
    igraph_indheap_i_switch(h, elem, PARENT(elem));
    igraph_indheap_i_shift_up(h, PARENT(elem));
  }
}

/**
 * \ingroup indheap
 * \brief Moves an element down in the heap, don't call this function
 * directly. 
 */

void igraph_indheap_i_sink(igraph_indheap_t* h, long int head) {

  long int size=igraph_indheap_size(h);
  if (LEFTCHILD(head) >= size) { 
    /* no subtrees */
  } else if (RIGHTCHILD(head) == size ||
	     h->stor_begin[LEFTCHILD(head)]>=h->stor_begin[RIGHTCHILD(head)]) {
    /* sink to the left if needed */
    if (h->stor_begin[head] < h->stor_begin[LEFTCHILD(head)]) {
      igraph_indheap_i_switch(h, head, LEFTCHILD(head));
      igraph_indheap_i_sink(h, LEFTCHILD(head));
    }
  } else {
    /* sink to the right */
    if (h->stor_begin[head] < h->stor_begin[RIGHTCHILD(head)]) {
      igraph_indheap_i_switch(h, head, RIGHTCHILD(head));
      igraph_indheap_i_sink(h, RIGHTCHILD(head));
    }
  }
}

/**
 * \ingroup indheap
 * \brief Switches two elements in a heap, don't call this function
 * directly. 
 */

void igraph_indheap_i_switch(igraph_indheap_t* h, long int e1, long int e2) {
  if (e1!=e2) {
    igraph_real_t tmp=h->stor_begin[e1];
    h->stor_begin[e1]=h->stor_begin[e2];
    h->stor_begin[e2]=tmp;
    
    tmp=h->index_begin[e1];
    h->index_begin[e1]=h->index_begin[e2];
    h->index_begin[e2]=tmp;
  }
}


/**
 * \ingroup doubleindheap
 * \brief Initializes an empty doubly indexed heap object (constructor).
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_d_indheap_init           (igraph_d_indheap_t* h, long int alloc_size) {
 if (alloc_size <= 0 ) { alloc_size=1; }
  h->stor_begin=Calloc(alloc_size, igraph_real_t);
  if (h->stor_begin==0) {
    h->index_begin=0;
    h->index2_begin=0;
    IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM);
  }
  h->stor_end=h->stor_begin + alloc_size;
  h->end=h->stor_begin;
  h->destroy=1;
  h->index_begin=Calloc(alloc_size, long int);
  if (h->index_begin==0) {
    Free(h->stor_begin);
    h->stor_begin=0;
    h->index2_begin=0;
    IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM);
  }
  h->index2_begin=Calloc(alloc_size, long int);
  if (h->index2_begin==0) {
    Free(h->stor_begin);
    Free(h->index_begin);
    h->stor_begin=0;
    h->index_begin=0;
    IGRAPH_ERROR("d_indheap init failed", IGRAPH_ENOMEM);
  }
  
  return 0;  
}

/**
 * \ingroup doubleindheap
 * \brief Destroys an initialized doubly indexed heap object.
 */

void igraph_d_indheap_destroy        (igraph_d_indheap_t* h) {  
  assert(h != 0);
  if (h->destroy) {
    if (h->stor_begin != 0) {
      Free(h->stor_begin);
      h->stor_begin=0;
    }
    if (h->index_begin != 0) {
      Free(h->index_begin);
      h->index_begin=0;
    }
    if (h->index2_begin != 0) {
      Free(h->index2_begin);
      h->index2_begin=0;
    }
  }
}

/**
 * \ingroup doubleindheap
 * \brief Decides whether a heap is empty.
 */

igraph_bool_t igraph_d_indheap_empty          (igraph_d_indheap_t* h) {
  assert(h != 0);
  assert(h->stor_begin != 0);
  return h->stor_begin == h->end;
}

/**
 * \ingroup doubleindheap
 * \brief Adds an element to the heap.
 */

int igraph_d_indheap_push           (igraph_d_indheap_t* h, igraph_real_t elem, 
			      long int idx, long int idx2) {
  assert(h != 0);
  assert(h->stor_begin != 0);
	
  /* full, allocate more storage */
  if (h->stor_end == h->end) {
    long int new_size = igraph_d_indheap_size(h) * 2;
    if (new_size == 0) { new_size = 1; }
    IGRAPH_CHECK(igraph_d_indheap_reserve(h, new_size));
  }
	
  *(h->end) = elem;
  h->end += 1;
  *(h->index_begin+igraph_d_indheap_size(h)-1)=idx ;
  *(h->index2_begin+igraph_d_indheap_size(h)-1)=idx2 ;

  /* maintain d_indheap */
  igraph_d_indheap_i_shift_up(h, igraph_d_indheap_size(h)-1);
	
  return 0;
}

/**
 * \ingroup doubleindheap
 * \brief Returns the largest element in the heap.
 */

igraph_real_t igraph_d_indheap_max       (igraph_d_indheap_t* h) {
  assert(h != NULL);
  assert(h->stor_begin != NULL);
  assert(h->stor_begin != h->end);
  
  return h->stor_begin[0];
}

/**
 * \ingroup doubleindheap
 * \brief Removes the largest element from the heap.
 */

igraph_real_t igraph_d_indheap_delete_max(igraph_d_indheap_t* h) {
  igraph_real_t tmp;

  assert(h != NULL);
  assert(h->stor_begin != NULL);

  tmp=h->stor_begin[0];
  igraph_d_indheap_i_switch(h, 0, igraph_d_indheap_size(h)-1);
  h->end -= 1;
  igraph_d_indheap_i_sink(h, 0);
  
  return tmp;
}

/**
 * \ingroup doubleindheap
 * \brief Gives the number of elements in the heap.
 */

long int igraph_d_indheap_size      (igraph_d_indheap_t* h) {
  assert(h != 0);
  assert(h->stor_begin != 0);
  return h->end - h->stor_begin;
}

/**
 * \ingroup doubleindheap
 * \brief Allocates memory for a heap.
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_d_indheap_reserve        (igraph_d_indheap_t* h, long int size) {
  long int actual_size=igraph_d_indheap_size(h);
  igraph_real_t *tmp1;
  long int *tmp2, *tmp3;
  assert(h != 0);
  assert(h->stor_begin != 0);
  
  if (size <= actual_size) { return 0; }

  tmp1=Calloc(size, igraph_real_t);
  if (tmp1==0) {
    IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, tmp1);	/* TODO: hack */
  tmp2=Calloc(size, long int);
  if (tmp2==0) {
    IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, tmp2);	/* TODO: hack */
  tmp3=Calloc(size, long int);
  if (tmp3==0) {
    IGRAPH_ERROR("d_indheap reserve failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, tmp3); 	/* TODO: hack */

  memcpy(tmp1, h->stor_begin, actual_size*sizeof(igraph_real_t));
  memcpy(tmp2, h->index_begin, actual_size*sizeof(long int));
  memcpy(tmp3, h->index2_begin, actual_size*sizeof(long int));
  Free(h->stor_begin);
  Free(h->index_begin);
  Free(h->index2_begin);

  h->stor_begin=tmp1;
  h->stor_end=h->stor_begin + size;
  h->end=h->stor_begin+actual_size;
  h->index_begin=tmp2; 
  h->index2_begin=tmp3;

  IGRAPH_FINALLY_CLEAN(3);
  return 0;
}

/**
 * \ingroup doubleindheap
 * \brief Gives the indices of the maximal element in the heap.
 */

void igraph_d_indheap_max_index(igraph_d_indheap_t *h, long int *idx, long int *idx2) {
  assert(h != 0);
  assert(h->stor_begin != 0);
  (*idx)=h->index_begin[0];
  (*idx2)=h->index2_begin[0];
}

/**
 * \ingroup doubleindheap
 * \brief Builds the heap, don't call it directly.
 */

void igraph_d_indheap_i_build(igraph_d_indheap_t* h, long int head) {

  long int size=igraph_d_indheap_size(h);
  if (RIGHTCHILD(head) < size) { 
    /* both subtrees */
    igraph_d_indheap_i_build(h, LEFTCHILD(head) );
    igraph_d_indheap_i_build(h, RIGHTCHILD(head));
    igraph_d_indheap_i_sink(h, head);
  } else if (LEFTCHILD(head) < size) {
    /* only left */
    igraph_d_indheap_i_build(h, LEFTCHILD(head));
    igraph_d_indheap_i_sink(h, head);
  } else {
    /* none */
  }
}

/**
 * \ingroup doubleindheap
 * \brief Moves an element up in the heap, don't call it directly.
 */

void igraph_d_indheap_i_shift_up(igraph_d_indheap_t *h, long int elem) {
  
  if (elem==0 || h->stor_begin[elem] < h->stor_begin[PARENT(elem)]) { 
    /* at the top */
  } else {
    igraph_d_indheap_i_switch(h, elem, PARENT(elem));
    igraph_d_indheap_i_shift_up(h, PARENT(elem));
  }
}

/**
 * \ingroup doubleindheap
 * \brief Moves an element down in the heap, don't call it directly.
 */

void igraph_d_indheap_i_sink(igraph_d_indheap_t* h, long int head) {

  long int size=igraph_d_indheap_size(h);
  if (LEFTCHILD(head) >= size) { 
    /* no subtrees */
  } else if (RIGHTCHILD(head) == size ||
	     h->stor_begin[LEFTCHILD(head)]>=h->stor_begin[RIGHTCHILD(head)]) {
    /* sink to the left if needed */
    if (h->stor_begin[head] < h->stor_begin[LEFTCHILD(head)]) {
      igraph_d_indheap_i_switch(h, head, LEFTCHILD(head));
      igraph_d_indheap_i_sink(h, LEFTCHILD(head));
    }
  } else {
    /* sink to the right */
    if (h->stor_begin[head] < h->stor_begin[RIGHTCHILD(head)]) {
      igraph_d_indheap_i_switch(h, head, RIGHTCHILD(head));
      igraph_d_indheap_i_sink(h, RIGHTCHILD(head));
    }
  }
}

/**
 * \ingroup doubleindheap
 * \brief Switches two elements in the heap, don't call it directly.
 */

void igraph_d_indheap_i_switch(igraph_d_indheap_t* h, long int e1, long int e2) {
  if (e1!=e2) {
    long int tmpi;
    igraph_real_t tmp=h->stor_begin[e1];
    h->stor_begin[e1]=h->stor_begin[e2];
    h->stor_begin[e2]=tmp;
    
    tmpi=h->index_begin[e1];
    h->index_begin[e1]=h->index_begin[e2];
    h->index_begin[e2]=tmpi;

    tmpi=h->index2_begin[e1];
    h->index2_begin[e1]=h->index2_begin[e2];
    h->index2_begin[e2]=tmpi;
  }
}

/*************************************************/

#undef PARENT
#undef LEFTCHILD
#undef RIGHTCHILD
#define PARENT(x)     ((x)/2)
#define LEFTCHILD(x)  ((x)*2+1)
#define RIGHTCHILD(x) ((x)*2)
#define INACTIVE      IGRAPH_INFINITY
#define UNDEFINED     0.0
#define INDEXINC      1

void igraph_i_cutheap_switch(igraph_i_cutheap_t *ch, 
			    long int hidx1, long int hidx2) {
  if (hidx1 != hidx2) {
    long int idx1=VECTOR(ch->index)[hidx1];
    long int idx2=VECTOR(ch->index)[hidx2];

    igraph_real_t tmp=VECTOR(ch->heap)[hidx1];
    VECTOR(ch->heap)[hidx1]=VECTOR(ch->heap)[hidx2];
    VECTOR(ch->heap)[hidx2]=tmp;
    
    VECTOR(ch->index)[hidx1]=idx2;
    VECTOR(ch->index)[hidx2]=idx1;
    
    VECTOR(ch->hptr)[idx1] = hidx2+INDEXINC;
    VECTOR(ch->hptr)[idx2] = hidx1+INDEXINC;
  }
}

void igraph_i_cutheap_sink(igraph_i_cutheap_t *ch, long int hidx) {
  long int size=igraph_vector_size(&ch->heap);
  if (LEFTCHILD(hidx) >= size) {
    /* leaf node */
  } else if (RIGHTCHILD(hidx) == size ||
	     VECTOR(ch->heap)[LEFTCHILD(hidx)] >= 
	     VECTOR(ch->heap)[RIGHTCHILD(hidx)]) {
    /* sink to the left if needed */
    if (VECTOR(ch->heap)[hidx] < VECTOR(ch->heap)[LEFTCHILD(hidx)]) {
      igraph_i_cutheap_switch(ch, hidx, LEFTCHILD(hidx));
      igraph_i_cutheap_sink(ch, LEFTCHILD(hidx));
    }
  } else {
    /* sink to the right */
    if (VECTOR(ch->heap)[hidx] < VECTOR(ch->heap)[RIGHTCHILD(hidx)]) {
      igraph_i_cutheap_switch(ch, hidx, RIGHTCHILD(hidx));
      igraph_i_cutheap_sink(ch, RIGHTCHILD(hidx));
    }
  }
}

void igraph_i_cutheap_shift_up(igraph_i_cutheap_t *ch, long int hidx) {
  if (hidx==0 || VECTOR(ch->heap)[hidx] < VECTOR(ch->heap)[PARENT(hidx)]) {
    /* at the top */
  } else {
    igraph_i_cutheap_switch(ch, hidx, PARENT(hidx));
    igraph_i_cutheap_shift_up(ch, PARENT(hidx));
  }
}

int igraph_i_cutheap_init(igraph_i_cutheap_t *ch, igraph_integer_t nodes) {
  ch->dnodes=nodes;
  IGRAPH_VECTOR_INIT_FINALLY(&ch->heap, nodes);	/* all zero */
  IGRAPH_CHECK(igraph_vector_init_seq(&ch->index, 0, nodes-1));
  IGRAPH_FINALLY(igraph_vector_destroy, &ch->index);
  IGRAPH_CHECK(igraph_vector_init_seq(&ch->hptr, INDEXINC, nodes+INDEXINC-1));  
  IGRAPH_FINALLY_CLEAN(2);
  return 0;
}

void igraph_i_cutheap_destroy(igraph_i_cutheap_t *ch) {
  igraph_vector_destroy(&ch->hptr);
  igraph_vector_destroy(&ch->index);
  igraph_vector_destroy(&ch->heap);
}

igraph_bool_t igraph_i_cutheap_empty(igraph_i_cutheap_t *ch) {
  return igraph_vector_empty(&ch->heap);
}

/* Number of active vertices */

igraph_integer_t igraph_i_cutheap_active_size(igraph_i_cutheap_t *ch) {
  return igraph_vector_size(&ch->heap);
}

/* Number of all (defined) vertices */

igraph_integer_t igraph_i_cutheap_size(igraph_i_cutheap_t *ch) {
  return ch->dnodes;
}

igraph_real_t igraph_i_cutheap_maxvalue(igraph_i_cutheap_t *ch) {
  return VECTOR(ch->heap)[0];
}

igraph_integer_t igraph_i_cutheap_popmax(igraph_i_cutheap_t *ch) {
  long int size=igraph_vector_size(&ch->heap);
  igraph_integer_t maxindex=VECTOR(ch->index)[0];
  /* put the last element to the top */
  igraph_i_cutheap_switch(ch, 0, size-1);
  /* remove the last element */
  VECTOR(ch->hptr)[(long int) igraph_vector_tail(&ch->index)] = INACTIVE;
  igraph_vector_pop_back(&ch->heap);
  igraph_vector_pop_back(&ch->index);
  igraph_i_cutheap_sink(ch, 0);
  
  return maxindex;
}

/* Update the value of an active vertex, if not active it will be ignored */

int igraph_i_cutheap_update(igraph_i_cutheap_t *ch, igraph_integer_t index,
			    igraph_real_t add) {
  igraph_integer_t hidx=VECTOR(ch->hptr)[(long int)index];
  if (hidx != INACTIVE && hidx != UNDEFINED) {
    long int hidx2=hidx-INDEXINC;
/*     printf("updating vertex %li, heap index %li\n", (long int) index, hidx2); */
    VECTOR(ch->heap)[hidx2] += add;
    igraph_i_cutheap_sink(ch, hidx2);
    igraph_i_cutheap_shift_up(ch, hidx2);
  }
  return 0;
}

/* Reset the value of all vertices to zero and make them active */

int igraph_i_cutheap_reset_undefine(igraph_i_cutheap_t *ch, long int vertex) {
  long int i, j, n=igraph_vector_size(&ch->hptr);
  /* undefine */
  VECTOR(ch->hptr)[vertex] = UNDEFINED;
  ch->dnodes -= 1;

  IGRAPH_CHECK(igraph_vector_resize(&ch->heap, ch->dnodes));
  igraph_vector_null(&ch->heap);

  IGRAPH_CHECK(igraph_vector_resize(&ch->index, ch->dnodes));

  j=0;
  for (i=0; i<n; i++) {
    if (VECTOR(ch->hptr)[i] != UNDEFINED) {
      VECTOR(ch->index)[j]=i;
      VECTOR(ch->hptr)[i]=j+INDEXINC;
      j++;
    }
  }
	     
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1